Ring-mapped provided buffers store buffer addresses in a shared memory ring that userspace populates. When io_uring reads buf->addr from this ring, it converts it to a user pointer via u64_to_user_ptr() without any access_ok() validation. This is OK as the iov_iter copy accessors validate the address when it's being used, but it's also different than any other address import where it's always validated. Validate the provided ring buffers at import time, unifying them with the other access methods. Fixes: c7fb19428d67 ("io_uring: add support for ring mapped supplied buffers") Signed-off-by: Jens Axboe --- diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index 7a1c65f631c2..a34db556a75c 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -250,6 +250,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, struct io_buffer_list *bl) { struct io_uring_buf_ring *br = bl->buf_ring; + struct iovec *org_iovs = arg->iovs; struct iovec *iov = arg->iovs; int nr_iovs = arg->nr_iovs; __u16 nr_avail, tail, head; @@ -311,6 +312,11 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, iov->iov_base = u64_to_user_ptr(READ_ONCE(buf->addr)); iov->iov_len = len; + if (unlikely(!access_ok(iov->iov_base, len))) { + if (arg->iovs != org_iovs) + kfree(arg->iovs); + return -EFAULT; + } iov++; arg->out_len += len; -- Jens Axboe