diff options
author | Pavel Begunkov <asml.silence@gmail.com> | 2025-05-01 13:17:14 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-07-06 11:04:10 +0200 |
commit | d35626630a345b5fed3565bd6ccdb0a1570a624a (patch) | |
tree | 80aff3944ca43722d888e2fb6c4fe5649fd390e2 | |
parent | 0e6b730261683f352b42581f631925f3f945c041 (diff) |
io_uring/zcrx: improve area validation
[ Upstream commit d760d3f59f0d8d0df2895db30d36cf23106d6b05 ]
dmabuf backed area will be taking an offset instead of addresses, and
io_buffer_validate() is not flexible enough to facilitate it. It also
takes an iovec, which may truncate the u64 length zcrx takes. Add a new
helper function for validation.
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/0b3b735391a0a8f8971bf0121c19765131fddd3b.1746097431.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: 0ec33c81d9c7 ("io_uring/zcrx: fix area release on registration failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | io_uring/rsrc.c | 27 | ||||
-rw-r--r-- | io_uring/rsrc.h | 2 | ||||
-rw-r--r-- | io_uring/zcrx.c | 7 |
3 files changed, 19 insertions, 17 deletions
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 794d4ae6f0bc..6d6168322387 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -80,10 +80,21 @@ static int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages) return 0; } -int io_buffer_validate(struct iovec *iov) +int io_validate_user_buf_range(u64 uaddr, u64 ulen) { - unsigned long tmp, acct_len = iov->iov_len + (PAGE_SIZE - 1); + unsigned long tmp, base = (unsigned long)uaddr; + unsigned long acct_len = (unsigned long)PAGE_ALIGN(ulen); + /* arbitrary limit, but we need something */ + if (ulen > SZ_1G || !ulen) + return -EFAULT; + if (check_add_overflow(base, acct_len, &tmp)) + return -EOVERFLOW; + return 0; +} + +static int io_buffer_validate(struct iovec *iov) +{ /* * Don't impose further limits on the size and buffer * constraints here, we'll -EINVAL later when IO is @@ -91,17 +102,9 @@ int io_buffer_validate(struct iovec *iov) */ if (!iov->iov_base) return iov->iov_len ? -EFAULT : 0; - if (!iov->iov_len) - return -EFAULT; - - /* arbitrary limit, but we need something */ - if (iov->iov_len > SZ_1G) - return -EFAULT; - if (check_add_overflow((unsigned long)iov->iov_base, acct_len, &tmp)) - return -EOVERFLOW; - - return 0; + return io_validate_user_buf_range((unsigned long)iov->iov_base, + iov->iov_len); } static void io_release_ubuf(void *priv) diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h index b52242852ff3..4373524f993c 100644 --- a/io_uring/rsrc.h +++ b/io_uring/rsrc.h @@ -83,7 +83,7 @@ int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg, unsigned size, unsigned type); int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg, unsigned int size, unsigned int type); -int io_buffer_validate(struct iovec *iov); +int io_validate_user_buf_range(u64 uaddr, u64 ulen); bool io_check_coalesce_buffer(struct page **page_array, int nr_pages, struct io_imu_folio_data *data); diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c index ecb59182d9b2..0771a57d81a5 100644 --- a/io_uring/zcrx.c +++ b/io_uring/zcrx.c @@ -205,7 +205,6 @@ static int io_zcrx_create_area(struct io_zcrx_ifq *ifq, { struct io_zcrx_area *area; int i, ret, nr_pages, nr_iovs; - struct iovec iov; if (area_reg->flags || area_reg->rq_area_token) return -EINVAL; @@ -214,11 +213,11 @@ static int io_zcrx_create_area(struct io_zcrx_ifq *ifq, if (area_reg->addr & ~PAGE_MASK || area_reg->len & ~PAGE_MASK) return -EINVAL; - iov.iov_base = u64_to_user_ptr(area_reg->addr); - iov.iov_len = area_reg->len; - ret = io_buffer_validate(&iov); + ret = io_validate_user_buf_range(area_reg->addr, area_reg->len); if (ret) return ret; + if (!area_reg->addr) + return -EFAULT; ret = -ENOMEM; area = kzalloc(sizeof(*area), GFP_KERNEL); |