]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
io_uring/zcrx: improve area validation
authorPavel Begunkov <asml.silence@gmail.com>
Thu, 1 May 2025 12:17:14 +0000 (13:17 +0100)
committerJens Axboe <axboe@kernel.dk>
Fri, 2 May 2025 15:24:42 +0000 (09:24 -0600)
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>
io_uring/rsrc.c
io_uring/rsrc.h
io_uring/zcrx.c

index b4c5f3ee885543bb912aeb90014ee336d99adc72..1657d775c8bab270498de1617c359ded17f5caeb 100644 (file)
@@ -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)
index 6008ad2e6d9e9c763400a70625a142cd5a5fa9f7..2818aa0d04722c9b2bbbd6088ec951928fb58d5c 100644 (file)
@@ -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);
index 22f420d6fbb992ece8f238e6278373eb83f5d083..5e918587fdc503370def6fb70fb4dc9591c21921 100644 (file)
@@ -209,7 +209,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;
@@ -218,11 +217,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);