Bug 218101 - When performing IORING_OP_READ_MULTISHOT, a null pointer dereference bug occurs in io_req_map_rw.
Summary: When performing IORING_OP_READ_MULTISHOT, a null pointer dereference bug occu...
Status: NEW
Alias: None
Product: Linux
Classification: Unclassified
Component: Kernel (show other bugs)
Hardware: All Linux
: P3 low
Assignee: Virtual assignee for kernel bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-11-03 14:55 UTC by j51569436
Modified: 2023-11-03 16:50 UTC (History)
1 user (show)

See Also:
Kernel Version: 6.6.0
Subsystem:
Regression: No
Bisected commit-id:


Attachments
poc.c (944 bytes, text/plain)
2023-11-03 14:55 UTC, j51569436
Details
crash log (7.61 KB, text/plain)
2023-11-03 14:56 UTC, j51569436
Details

Description j51569436 2023-11-03 14:55:10 UTC
When issuing IORING_OP_READ_MULTISHOT, the functions are called in the following flow:

io_read_mshot -> __io_read -> io_setup_async_rw -> io_alloc_async_data

```
bool io_alloc_async_data(struct io_kiocb *req)
{
    WARN_ON_ONCE(!io_cold_defs[req->opcode].async_size);
    req->async_data = kmalloc(io_cold_defs[req->opcode].async_size, GFP_KERNEL);
    if (req->async_data) {
        req->flags |= REQ_F_ASYNC_DATA;
        return false;
    }
    return true;
}
```

`io_cold_defs[IORING_OP_READ_MULTISHOT].async_size` is 0. Therefore, kmalloc returns ZERO_SIZE_PTR (0x10), and a subsequent null pointer dereference bug occurs. 


In io_setup_async_rw, before validating `io_cold_defs[IORING_OP_READ_MULTISHOT].prep_async`, the condition is ignored because the force flag is true.
Comment 1 j51569436 2023-11-03 14:55:40 UTC
Created attachment 305364 [details]
poc.c
Comment 2 j51569436 2023-11-03 14:56:09 UTC
Created attachment 305365 [details]
crash log
Comment 3 Jens Axboe 2023-11-03 15:03:33 UTC
Thanks for the report, I'll take a look.
Comment 4 Jens Axboe 2023-11-03 15:14:26 UTC
This should fix it:

diff --git a/io_uring/rw.c b/io_uring/rw.c
index 3398e1d944c2..61dd28451681 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -542,6 +542,9 @@ static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
 {
 	if (!force && !io_cold_defs[req->opcode].prep_async)
 		return 0;
+	/* opcode type doesn't need async data */
+	if (!io_cold_defs[req->opcode].async_size)
+		return 0;
 	if (!req_has_async_data(req)) {
 		struct io_async_rw *iorw;
Comment 5 Jens Axboe 2023-11-03 15:32:05 UTC
Committed: https://git.kernel.dk/cgit/linux/commit/?h=io_uring-6.7&id=0df96fb71a395b4fc9c80180306420c743f395a8

Also adds a check for provided buffers, as it has to be used with that.
Comment 6 Jens Axboe 2023-11-03 16:50:19 UTC
Patch posted, will go in before 6.7-rc1. Thanks again for the report!

Note You need to log in before you can comment on or make changes to this bug.