public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH] io_uring/rsrc: ensure compat iovecs are copied correctly
@ 2024-08-28 15:46 Jens Axboe
  2024-08-28 15:57 ` Gabriel Krisman Bertazi
  0 siblings, 1 reply; 2+ messages in thread
From: Jens Axboe @ 2024-08-28 15:46 UTC (permalink / raw)
  To: io-uring; +Cc: Gabriel Krisman Bertazi

For buffer registration (or updates), a userspace iovec is copied in
and updated. If the application is within a compat syscall, then the
iovec type is compat_iovec rather than iovec. However, the type used
in __io_sqe_buffers_update() and io_sqe_buffers_register() is always
struct iovec, and hence the source is incremented by the size of a
non-compat iovec in the loop. This misses every other iovec in the
source, and will run into garbage half way through the copies and
return -EFAULT to the application.

Maintain the source address separately and assign to our user vec
pointer, so that copies always happen from the right source address.

Fixes: f4eaf8eda89e ("io_uring/rsrc: Drop io_copy_iov in favor of iovec API")
Signed-off-by: Jens Axboe <[email protected]>

---

diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index a860516bf448..b38d0ef41ef1 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -394,10 +394,11 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
 				   struct io_uring_rsrc_update2 *up,
 				   unsigned int nr_args)
 {
-	struct iovec __user *uvec = u64_to_user_ptr(up->data);
 	u64 __user *tags = u64_to_user_ptr(up->tags);
 	struct iovec fast_iov, *iov;
 	struct page *last_hpage = NULL;
+	struct iovec __user *uvec;
+	u64 user_data = up->data;
 	__u32 done;
 	int i, err;
 
@@ -410,7 +411,8 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
 		struct io_mapped_ubuf *imu;
 		u64 tag = 0;
 
-		iov = iovec_from_user(&uvec[done], 1, 1, &fast_iov, ctx->compat);
+		uvec = u64_to_user_ptr(user_data);
+		iov = iovec_from_user(uvec, 1, 1, &fast_iov, ctx->compat);
 		if (IS_ERR(iov)) {
 			err = PTR_ERR(iov);
 			break;
@@ -443,6 +445,10 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
 
 		ctx->user_bufs[i] = imu;
 		*io_get_tag_slot(ctx->buf_data, i) = tag;
+		if (ctx->compat)
+			user_data += sizeof(struct compat_iovec);
+		else
+			user_data += sizeof(struct iovec);
 	}
 	return done ? done : err;
 }
@@ -949,7 +955,7 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
 	struct page *last_hpage = NULL;
 	struct io_rsrc_data *data;
 	struct iovec fast_iov, *iov = &fast_iov;
-	const struct iovec __user *uvec = (struct iovec * __user) arg;
+	const struct iovec __user *uvec;
 	int i, ret;
 
 	BUILD_BUG_ON(IORING_MAX_REG_BUFFERS >= (1u << 16));
@@ -972,7 +978,8 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
 
 	for (i = 0; i < nr_args; i++, ctx->nr_user_bufs++) {
 		if (arg) {
-			iov = iovec_from_user(&uvec[i], 1, 1, &fast_iov, ctx->compat);
+			uvec = (struct iovec * __user) arg;
+			iov = iovec_from_user(uvec, 1, 1, &fast_iov, ctx->compat);
 			if (IS_ERR(iov)) {
 				ret = PTR_ERR(iov);
 				break;
@@ -980,6 +987,10 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
 			ret = io_buffer_validate(iov);
 			if (ret)
 				break;
+			if (ctx->compat)
+				arg += sizeof(struct compat_iovec);
+			else
+				arg += sizeof(struct iovec);
 		}
 
 		if (!iov->iov_base && *io_get_tag_slot(data, i)) {

-- 
Jens Axboe


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] io_uring/rsrc: ensure compat iovecs are copied correctly
  2024-08-28 15:46 [PATCH] io_uring/rsrc: ensure compat iovecs are copied correctly Jens Axboe
@ 2024-08-28 15:57 ` Gabriel Krisman Bertazi
  0 siblings, 0 replies; 2+ messages in thread
From: Gabriel Krisman Bertazi @ 2024-08-28 15:57 UTC (permalink / raw)
  To: Jens Axboe; +Cc: io-uring

Jens Axboe <[email protected]> writes:

> For buffer registration (or updates), a userspace iovec is copied in
> and updated. If the application is within a compat syscall, then the
> iovec type is compat_iovec rather than iovec. However, the type used
> in __io_sqe_buffers_update() and io_sqe_buffers_register() is always
> struct iovec, and hence the source is incremented by the size of a
> non-compat iovec in the loop. This misses every other iovec in the
> source, and will run into garbage half way through the copies and
> return -EFAULT to the application.
>
> Maintain the source address separately and assign to our user vec
> pointer, so that copies always happen from the right source address.
>
> Fixes: f4eaf8eda89e ("io_uring/rsrc: Drop io_copy_iov in favor of iovec API")
> Signed-off-by: Jens Axboe <[email protected]>

Thanks for the fix, Jens. please take:

Reviewed-by: Gabriel Krisman Bertazi <[email protected]>

>
> ---
>
> diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
> index a860516bf448..b38d0ef41ef1 100644
> --- a/io_uring/rsrc.c
> +++ b/io_uring/rsrc.c
> @@ -394,10 +394,11 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
>  				   struct io_uring_rsrc_update2 *up,
>  				   unsigned int nr_args)
>  {
> -	struct iovec __user *uvec = u64_to_user_ptr(up->data);
>  	u64 __user *tags = u64_to_user_ptr(up->tags);
>  	struct iovec fast_iov, *iov;
>  	struct page *last_hpage = NULL;
> +	struct iovec __user *uvec;
> +	u64 user_data = up->data;
>  	__u32 done;
>  	int i, err;
>  
> @@ -410,7 +411,8 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
>  		struct io_mapped_ubuf *imu;
>  		u64 tag = 0;
>  
> -		iov = iovec_from_user(&uvec[done], 1, 1, &fast_iov, ctx->compat);
> +		uvec = u64_to_user_ptr(user_data);
> +		iov = iovec_from_user(uvec, 1, 1, &fast_iov, ctx->compat);
>  		if (IS_ERR(iov)) {
>  			err = PTR_ERR(iov);
>  			break;
> @@ -443,6 +445,10 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
>  
>  		ctx->user_bufs[i] = imu;
>  		*io_get_tag_slot(ctx->buf_data, i) = tag;
> +		if (ctx->compat)
> +			user_data += sizeof(struct compat_iovec);
> +		else
> +			user_data += sizeof(struct iovec);
>  	}
>  	return done ? done : err;
>  }
> @@ -949,7 +955,7 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
>  	struct page *last_hpage = NULL;
>  	struct io_rsrc_data *data;
>  	struct iovec fast_iov, *iov = &fast_iov;
> -	const struct iovec __user *uvec = (struct iovec * __user) arg;
> +	const struct iovec __user *uvec;
>  	int i, ret;
>  
>  	BUILD_BUG_ON(IORING_MAX_REG_BUFFERS >= (1u << 16));
> @@ -972,7 +978,8 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
>  
>  	for (i = 0; i < nr_args; i++, ctx->nr_user_bufs++) {
>  		if (arg) {
> -			iov = iovec_from_user(&uvec[i], 1, 1, &fast_iov, ctx->compat);
> +			uvec = (struct iovec * __user) arg;
> +			iov = iovec_from_user(uvec, 1, 1, &fast_iov, ctx->compat);
>  			if (IS_ERR(iov)) {
>  				ret = PTR_ERR(iov);
>  				break;
> @@ -980,6 +987,10 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
>  			ret = io_buffer_validate(iov);
>  			if (ret)
>  				break;
> +			if (ctx->compat)
> +				arg += sizeof(struct compat_iovec);
> +			else
> +				arg += sizeof(struct iovec);
>  		}
>  
>  		if (!iov->iov_base && *io_get_tag_slot(data, i)) {

-- 
Gabriel Krisman Bertazi

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-08-28 15:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-28 15:46 [PATCH] io_uring/rsrc: ensure compat iovecs are copied correctly Jens Axboe
2024-08-28 15:57 ` Gabriel Krisman Bertazi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox