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.
Created attachment 305364 [details] poc.c
Created attachment 305365 [details] crash log
Thanks for the report, I'll take a look.
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;
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.
Patch posted, will go in before 6.7-rc1. Thanks again for the report!