io_uring: Require zeroed sqe->len on provided-buffers send
authorGabriel Krisman Bertazi <krisman@suse.de>
Wed, 1 May 2024 20:56:36 +0000 (14:56 -0600)
committerJens Axboe <axboe@kernel.dk>
Wed, 1 May 2024 20:56:36 +0000 (14:56 -0600)
When sending from a provided buffer, we set sr->len to be the smallest
between the actual buffer size and sqe->len.  But, now that we
disconnect the buffer from the submission request, we can get in a
situation where the buffers and requests mismatch, and only part of a
buffer gets sent.  Assume:

* buf[1]->len = 128; buf[2]->len = 256
* sqe[1]->len = 128; sqe[2]->len = 256

If sqe1 runs first, it picks buff[1] and it's all good. But, if sqe[2]
runs first, sqe[1] picks buff[2], and the last half of buff[2] is
never sent.

While arguably the use-case of different-length sends is questionable,
it has already raised confusion with potential users of this
feature. Let's make the interface less tricky by forcing the length to
only come from the buffer ring entry itself.

Fixes: ac5f71a3d9d7 ("io_uring/net: add provided buffer support for IORING_OP_SEND")
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/net.c

index 503debecad32103b3ec171afc19eb6f908ac9e5e..b0bf8471ecb77f824e24fdc011326a2153f37844 100644 (file)
@@ -423,6 +423,8 @@ int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                sr->buf_group = req->buf_index;
                req->buf_list = NULL;
        }
+       if (req->flags & REQ_F_BUFFER_SELECT && sr->len)
+               return -EINVAL;
 
 #ifdef CONFIG_COMPAT
        if (req->ctx->compat)
@@ -586,7 +588,7 @@ retry_bundle:
        if (io_do_buffer_select(req)) {
                struct buf_sel_arg arg = {
                        .iovs = &kmsg->fast_iov,
-                       .max_len = min_not_zero(sr->len, INT_MAX),
+                       .max_len = INT_MAX,
                        .nr_iovs = 1,
                        .mode = KBUF_MODE_EXPAND,
                };