6.15-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov asml.silence@gmail.com
[ 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.174609743... 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 --- io_uring/rsrc.c | 27 +++++++++++++++------------ io_uring/rsrc.h | 2 +- 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 794d4ae6f0bc8..6d61683223870 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 b52242852ff34..4373524f993c7 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 ecb59182d9b2c..0771a57d81a5b 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);