forked from mirrors/linux
		
	io_uring/net: move receive multishot out of the generic msghdr path
Move the actual user_msghdr / compat_msghdr into the send and receive sides, respectively, so we can move the uaddr receive handling into its own handler, and ditto the multishot with buffer selection logic. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									52307ac4f2
								
							
						
					
					
						commit
						c55978024d
					
				
					 1 changed files with 93 additions and 72 deletions
				
			
		
							
								
								
									
										163
									
								
								io_uring/net.c
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								io_uring/net.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -204,46 +204,26 @@ static int io_setup_async_msg(struct io_kiocb *req,
 | 
			
		|||
	return -EAGAIN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg)
 | 
			
		||||
{
 | 
			
		||||
	int hdr;
 | 
			
		||||
 | 
			
		||||
	if (iomsg->namelen < 0)
 | 
			
		||||
		return true;
 | 
			
		||||
	if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out),
 | 
			
		||||
			       iomsg->namelen, &hdr))
 | 
			
		||||
		return true;
 | 
			
		||||
	if (check_add_overflow(hdr, (int)iomsg->controllen, &hdr))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
static int __io_compat_msg_copy_hdr(struct io_kiocb *req,
 | 
			
		||||
static int io_compat_msg_copy_hdr(struct io_kiocb *req,
 | 
			
		||||
				  struct io_async_msghdr *iomsg,
 | 
			
		||||
				    struct sockaddr __user **addr, int ddir)
 | 
			
		||||
				  struct compat_msghdr *msg, int ddir)
 | 
			
		||||
{
 | 
			
		||||
	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 | 
			
		||||
	struct compat_msghdr msg;
 | 
			
		||||
	struct compat_iovec __user *uiov;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg)))
 | 
			
		||||
	if (copy_from_user(msg, sr->umsg_compat, sizeof(*msg)))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	ret = __get_compat_msghdr(&iomsg->msg, &msg, addr);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	uiov = compat_ptr(msg.msg_iov);
 | 
			
		||||
	uiov = compat_ptr(msg->msg_iov);
 | 
			
		||||
	if (req->flags & REQ_F_BUFFER_SELECT) {
 | 
			
		||||
		compat_ssize_t clen;
 | 
			
		||||
 | 
			
		||||
		iomsg->free_iov = NULL;
 | 
			
		||||
		if (msg.msg_iovlen == 0) {
 | 
			
		||||
		if (msg->msg_iovlen == 0) {
 | 
			
		||||
			sr->len = 0;
 | 
			
		||||
		} else if (msg.msg_iovlen > 1) {
 | 
			
		||||
		} else if (msg->msg_iovlen > 1) {
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!access_ok(uiov, sizeof(*uiov)))
 | 
			
		||||
| 
						 | 
				
			
			@ -255,18 +235,11 @@ static int __io_compat_msg_copy_hdr(struct io_kiocb *req,
 | 
			
		|||
			sr->len = clen;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ddir == ITER_DEST && req->flags & REQ_F_APOLL_MULTISHOT) {
 | 
			
		||||
			iomsg->namelen = msg.msg_namelen;
 | 
			
		||||
			iomsg->controllen = msg.msg_controllen;
 | 
			
		||||
			if (io_recvmsg_multishot_overflow(iomsg))
 | 
			
		||||
				return -EOVERFLOW;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iomsg->free_iov = iomsg->fast_iov;
 | 
			
		||||
	ret = __import_iovec(ddir, (struct iovec __user *)uiov, msg.msg_iovlen,
 | 
			
		||||
	ret = __import_iovec(ddir, (struct iovec __user *)uiov, msg->msg_iovlen,
 | 
			
		||||
				UIO_FASTIOV, &iomsg->free_iov,
 | 
			
		||||
				&iomsg->msg.msg_iter, true);
 | 
			
		||||
	if (unlikely(ret < 0))
 | 
			
		||||
| 
						 | 
				
			
			@ -276,47 +249,35 @@ static int __io_compat_msg_copy_hdr(struct io_kiocb *req,
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int __io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
 | 
			
		||||
			     struct sockaddr __user **addr, int ddir)
 | 
			
		||||
static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
 | 
			
		||||
			   struct user_msghdr *msg, int ddir)
 | 
			
		||||
{
 | 
			
		||||
	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 | 
			
		||||
	struct user_msghdr msg;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (copy_from_user(&msg, sr->umsg, sizeof(*sr->umsg)))
 | 
			
		||||
	if (copy_from_user(msg, sr->umsg, sizeof(*sr->umsg)))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	ret = __copy_msghdr(&iomsg->msg, &msg, addr);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	if (req->flags & REQ_F_BUFFER_SELECT) {
 | 
			
		||||
		if (msg.msg_iovlen == 0) {
 | 
			
		||||
		if (msg->msg_iovlen == 0) {
 | 
			
		||||
			sr->len = iomsg->fast_iov[0].iov_len = 0;
 | 
			
		||||
			iomsg->fast_iov[0].iov_base = NULL;
 | 
			
		||||
			iomsg->free_iov = NULL;
 | 
			
		||||
		} else if (msg.msg_iovlen > 1) {
 | 
			
		||||
		} else if (msg->msg_iovlen > 1) {
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (copy_from_user(iomsg->fast_iov, msg.msg_iov,
 | 
			
		||||
					   sizeof(*msg.msg_iov)))
 | 
			
		||||
			if (copy_from_user(iomsg->fast_iov, msg->msg_iov,
 | 
			
		||||
					   sizeof(*msg->msg_iov)))
 | 
			
		||||
				return -EFAULT;
 | 
			
		||||
			sr->len = iomsg->fast_iov[0].iov_len;
 | 
			
		||||
			iomsg->free_iov = NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ddir == ITER_DEST && req->flags & REQ_F_APOLL_MULTISHOT) {
 | 
			
		||||
			iomsg->namelen = msg.msg_namelen;
 | 
			
		||||
			iomsg->controllen = msg.msg_controllen;
 | 
			
		||||
			if (io_recvmsg_multishot_overflow(iomsg))
 | 
			
		||||
				return -EOVERFLOW;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iomsg->free_iov = iomsg->fast_iov;
 | 
			
		||||
	ret = __import_iovec(ddir, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
 | 
			
		||||
	ret = __import_iovec(ddir, msg->msg_iov, msg->msg_iovlen, UIO_FASTIOV,
 | 
			
		||||
				&iomsg->free_iov, &iomsg->msg.msg_iter, false);
 | 
			
		||||
	if (unlikely(ret < 0))
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -324,30 +285,34 @@ static int __io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
 | 
			
		||||
			   struct sockaddr __user **addr, int ddir)
 | 
			
		||||
{
 | 
			
		||||
	iomsg->msg.msg_name = &iomsg->addr;
 | 
			
		||||
	iomsg->msg.msg_iter.nr_segs = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	if (req->ctx->compat)
 | 
			
		||||
		return __io_compat_msg_copy_hdr(req, iomsg, addr, ddir);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return __io_msg_copy_hdr(req, iomsg, addr, ddir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int io_sendmsg_copy_hdr(struct io_kiocb *req,
 | 
			
		||||
			       struct io_async_msghdr *iomsg)
 | 
			
		||||
{
 | 
			
		||||
	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 | 
			
		||||
	struct user_msghdr msg;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = io_msg_copy_hdr(req, iomsg, NULL, ITER_SOURCE);
 | 
			
		||||
	if (ret)
 | 
			
		||||
	iomsg->msg.msg_name = &iomsg->addr;
 | 
			
		||||
	iomsg->msg.msg_iter.nr_segs = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	if (unlikely(req->ctx->compat)) {
 | 
			
		||||
		struct compat_msghdr cmsg;
 | 
			
		||||
 | 
			
		||||
		ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_SOURCE);
 | 
			
		||||
		if (unlikely(ret))
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		return __get_compat_msghdr(&iomsg->msg, &cmsg, NULL);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_SOURCE);
 | 
			
		||||
	if (unlikely(ret))
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = __copy_msghdr(&iomsg->msg, &msg, NULL);
 | 
			
		||||
 | 
			
		||||
	/* save msg_control as sys_sendmsg() overwrites it */
 | 
			
		||||
	sr->msg_control = iomsg->msg.msg_control_user;
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -569,10 +534,66 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags)
 | 
			
		|||
	return IOU_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int io_recvmsg_mshot_prep(struct io_kiocb *req,
 | 
			
		||||
				 struct io_async_msghdr *iomsg,
 | 
			
		||||
				 size_t namelen, size_t controllen)
 | 
			
		||||
{
 | 
			
		||||
	if ((req->flags & (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) ==
 | 
			
		||||
			  (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) {
 | 
			
		||||
		int hdr;
 | 
			
		||||
 | 
			
		||||
		if (unlikely(namelen < 0))
 | 
			
		||||
			return -EOVERFLOW;
 | 
			
		||||
		if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out),
 | 
			
		||||
					namelen, &hdr))
 | 
			
		||||
			return -EOVERFLOW;
 | 
			
		||||
		if (check_add_overflow(hdr, (int)controllen, &hdr))
 | 
			
		||||
			return -EOVERFLOW;
 | 
			
		||||
 | 
			
		||||
		iomsg->namelen = namelen;
 | 
			
		||||
		iomsg->controllen = controllen;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int io_recvmsg_copy_hdr(struct io_kiocb *req,
 | 
			
		||||
			       struct io_async_msghdr *iomsg)
 | 
			
		||||
{
 | 
			
		||||
	return io_msg_copy_hdr(req, iomsg, &iomsg->uaddr, ITER_DEST);
 | 
			
		||||
	struct user_msghdr msg;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	iomsg->msg.msg_name = &iomsg->addr;
 | 
			
		||||
	iomsg->msg.msg_iter.nr_segs = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	if (unlikely(req->ctx->compat)) {
 | 
			
		||||
		struct compat_msghdr cmsg;
 | 
			
		||||
 | 
			
		||||
		ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_DEST);
 | 
			
		||||
		if (unlikely(ret))
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		ret = __get_compat_msghdr(&iomsg->msg, &cmsg, &iomsg->uaddr);
 | 
			
		||||
		if (unlikely(ret))
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		return io_recvmsg_mshot_prep(req, iomsg, cmsg.msg_namelen,
 | 
			
		||||
						cmsg.msg_controllen);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_DEST);
 | 
			
		||||
	if (unlikely(ret))
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
 | 
			
		||||
	if (unlikely(ret))
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return io_recvmsg_mshot_prep(req, iomsg, msg.msg_namelen,
 | 
			
		||||
					msg.msg_controllen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int io_recvmsg_prep_async(struct io_kiocb *req)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue