]> www.infradead.org Git - users/hch/misc.git/commitdiff
io_uring/rw: check for NULL io_br_sel when putting a buffer
authorJens Axboe <axboe@kernel.dk>
Wed, 15 Oct 2025 19:38:53 +0000 (13:38 -0600)
committerJens Axboe <axboe@kernel.dk>
Wed, 15 Oct 2025 19:38:53 +0000 (13:38 -0600)
Both the read and write side use kiocb_done() to finish a request, and
kiocb_done() will call io_put_kbuf() in case a provided buffer was used
for the request. Provided buffers are not supported for writes, hence
NULL is being passed in. This normally works fine, as io_put_kbuf()
won't actually use the value unless REQ_F_BUFFER_RING or
REQ_F_BUFFER_SELECTED is set in the request flags. But depending on
compiler (or whether or not CONFIG_CC_OPTIMIZE_FOR_SIZE is set), that
may be done even though the value is never used. This will then cause a
NULL pointer dereference.

Make it a bit more obvious and check for a NULL io_br_sel, and don't
even bother calling io_put_kbuf() for that case.

Fixes: 5fda51255439 ("io_uring/kbuf: switch to storing struct io_buffer_list locally")
Reported-by: David Howells <dhowells@redhat.com>
Tested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/rw.c

index a0f9d2021e3f3f72bd699bcf84536c9a32d235e7..5b2241a5813c98cbc2d98ba7aa28f74424408eb3 100644 (file)
@@ -655,13 +655,17 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
        if (ret >= 0 && req->flags & REQ_F_CUR_POS)
                req->file->f_pos = rw->kiocb.ki_pos;
        if (ret >= 0 && !(req->ctx->flags & IORING_SETUP_IOPOLL)) {
+               u32 cflags = 0;
+
                __io_complete_rw_common(req, ret);
                /*
                 * Safe to call io_end from here as we're inline
                 * from the submission path.
                 */
                io_req_io_end(req);
-               io_req_set_res(req, final_ret, io_put_kbuf(req, ret, sel->buf_list));
+               if (sel)
+                       cflags = io_put_kbuf(req, ret, sel->buf_list);
+               io_req_set_res(req, final_ret, cflags);
                io_req_rw_cleanup(req, issue_flags);
                return IOU_COMPLETE;
        } else {