Skip to content

Commit ed123c9

Browse files
committed
io_uring/kbuf: use pre-committed buffer address for non-pollable file
For non-pollable files, buffer ring consumption will commit upfront. This is fine, but io_ring_buffer_select() will return the address of the buffer after having committed it. For incrementally consumed buffers, this is incorrect as it will modify the buffer address. Store the pre-committed value and return that. If that isn't done, then the initial part of the buffer is not used and the application will correctly assume the content arrived at the start of the userspace buffer, but the kernel will have put it later in the buffer. Or it can cause a spurious -EFAULT returned in the CQE, depending on the buffer size. As bounds are suitably checked for doing the actual IO, no adverse side effects are possible - it's just a data misplacement within the existing buffer. Reported-by: Gwendal Fernet <gwendalfernet@gmail.com> Cc: stable@vger.kernel.org Fixes: ae98dbf ("io_uring/kbuf: add support for incremental buffer consumption") Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent c6e60a0 commit ed123c9

File tree

1 file changed

+3
-1
lines changed

1 file changed

+3
-1
lines changed

io_uring/kbuf.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
139139
struct io_uring_buf_ring *br = bl->buf_ring;
140140
__u16 tail, head = bl->head;
141141
struct io_uring_buf *buf;
142+
void __user *ret;
142143

143144
tail = smp_load_acquire(&br->tail);
144145
if (unlikely(tail == head))
@@ -153,6 +154,7 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
153154
req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT;
154155
req->buf_list = bl;
155156
req->buf_index = buf->bid;
157+
ret = u64_to_user_ptr(buf->addr);
156158

157159
if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
158160
/*
@@ -168,7 +170,7 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
168170
io_kbuf_commit(req, bl, *len, 1);
169171
req->buf_list = NULL;
170172
}
171-
return u64_to_user_ptr(buf->addr);
173+
return ret;
172174
}
173175

174176
void __user *io_buffer_select(struct io_kiocb *req, size_t *len,

0 commit comments

Comments
 (0)