1947 lines · 50.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <linux/kernel.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/slab.h>#include <linux/net.h>#include <linux/un.h>#include <linux/compat.h>#include <net/compat.h>#include <linux/io_uring.h> #include <uapi/linux/io_uring.h> #include "filetable.h"#include "io_uring.h"#include "kbuf.h"#include "alloc_cache.h"#include "net.h"#include "notif.h"#include "rsrc.h"#include "zcrx.h" struct io_shutdown {	struct file			*file;	int				how;}; struct io_accept {	struct file			*file;	struct sockaddr __user		*addr;	int __user			*addr_len;	int				flags;	int				iou_flags;	u32				file_slot;	unsigned long			nofile;}; struct io_socket {	struct file			*file;	int				domain;	int				type;	int				protocol;	int				flags;	u32				file_slot;	unsigned long			nofile;}; struct io_connect {	struct file			*file;	struct sockaddr __user		*addr;	int				addr_len;	bool				in_progress;	bool				seen_econnaborted;}; struct io_bind {	struct file			*file;	int				addr_len;}; struct io_listen {	struct file			*file;	int				backlog;}; struct io_sr_msg {	struct file			*file;	union {		struct compat_msghdr __user	*umsg_compat;		struct user_msghdr __user	*umsg;		void __user			*buf;	};	int				len;	unsigned			done_io;	unsigned			msg_flags;	unsigned			nr_multishot_loops;	u16				flags;	/* initialised and used only by !msg send variants */	u16				buf_group;	/* per-invocation mshot limit */	unsigned			mshot_len;	/* overall mshot byte limit */	unsigned			mshot_total_len;	void __user			*msg_control;	/* used only for send zerocopy */	struct io_kiocb 		*notif;}; /* * The UAPI flags are the lower 8 bits, as that's all sqe->ioprio will hold * anyway. Use the upper 8 bits for internal uses. */enum sr_retry_flags {	IORING_RECV_RETRY	= (1U << 15),	IORING_RECV_PARTIAL_MAP	= (1U << 14),	IORING_RECV_MSHOT_CAP	= (1U << 13),	IORING_RECV_MSHOT_LIM	= (1U << 12),	IORING_RECV_MSHOT_DONE	= (1U << 11), 	IORING_RECV_RETRY_CLEAR	= IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP,	IORING_RECV_NO_RETRY	= IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP |				  IORING_RECV_MSHOT_CAP | IORING_RECV_MSHOT_DONE,}; /* * Number of times we'll try and do receives if there's more data. If we * exceed this limit, then add us to the back of the queue and retry from * there. This helps fairness between flooding clients. */#define MULTISHOT_MAX_RETRY	32 struct io_recvzc {	struct file			*file;	u16				flags;	u32				len;	struct io_zcrx_ifq		*ifq;}; static int io_sg_from_iter_iovec(struct sk_buff *skb,				 struct iov_iter *from, size_t length);static int io_sg_from_iter(struct sk_buff *skb,			   struct iov_iter *from, size_t length); int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe){	struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown); 	if (unlikely(sqe->off || sqe->addr || sqe->rw_flags ||		     sqe->buf_index || sqe->splice_fd_in))		return -EINVAL; 	shutdown->how = READ_ONCE(sqe->len);	req->flags |= REQ_F_FORCE_ASYNC;	return 0;} int io_shutdown(struct io_kiocb *req, unsigned int issue_flags){	struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown);	struct socket *sock;	int ret; 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); 	sock = sock_from_file(req->file);	if (unlikely(!sock))		return -ENOTSOCK; 	ret = __sys_shutdown_sock(sock, shutdown->how);	io_req_set_res(req, ret, 0);	return IOU_COMPLETE;} static bool io_net_retry(struct socket *sock, int flags){	if (!(flags & MSG_WAITALL))		return false;	return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET;} static void io_netmsg_iovec_free(struct io_async_msghdr *kmsg){	if (kmsg->vec.iovec)		io_vec_free(&kmsg->vec);} static void io_netmsg_recycle(struct io_kiocb *req, unsigned int issue_flags){	struct io_async_msghdr *hdr = req->async_data; 	/* can't recycle, ensure we free the iovec if we have one */	if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) {		io_netmsg_iovec_free(hdr);		return;	} 	/* Let normal cleanup path reap it if we fail adding to the cache */	io_alloc_cache_vec_kasan(&hdr->vec);	if (hdr->vec.nr > IO_VEC_CACHE_SOFT_CAP)		io_vec_free(&hdr->vec); 	if (io_alloc_cache_put(&req->ctx->netmsg_cache, hdr))		io_req_async_data_clear(req, REQ_F_NEED_CLEANUP);} static struct io_async_msghdr *io_msg_alloc_async(struct io_kiocb *req){	struct io_ring_ctx *ctx = req->ctx;	struct io_async_msghdr *hdr; 	hdr = io_uring_alloc_async_data(&ctx->netmsg_cache, req);	if (!hdr)		return NULL; 	/* If the async data was cached, we might have an iov cached inside. */	if (hdr->vec.iovec)		req->flags |= REQ_F_NEED_CLEANUP;	return hdr;} static inline void io_mshot_prep_retry(struct io_kiocb *req,				       struct io_async_msghdr *kmsg){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); 	req->flags &= ~REQ_F_BL_EMPTY;	sr->done_io = 0;	sr->flags &= ~IORING_RECV_RETRY_CLEAR;	sr->len = sr->mshot_len;} static int io_net_import_vec(struct io_kiocb *req, struct io_async_msghdr *iomsg,			     const struct iovec __user *uiov, unsigned uvec_seg,			     int ddir){	struct iovec *iov;	int ret, nr_segs; 	if (iomsg->vec.iovec) {		nr_segs = iomsg->vec.nr;		iov = iomsg->vec.iovec;	} else {		nr_segs = 1;		iov = &iomsg->fast_iov;	} 	ret = __import_iovec(ddir, uiov, uvec_seg, nr_segs, &iov,			     &iomsg->msg.msg_iter, io_is_compat(req->ctx));	if (unlikely(ret < 0))		return ret; 	if (iov) {		req->flags |= REQ_F_NEED_CLEANUP;		io_vec_reset_iovec(&iomsg->vec, iov, iomsg->msg.msg_iter.nr_segs);	}	return 0;} static int io_copy_msghdr_from_user(struct user_msghdr *msg,				    struct user_msghdr __user *umsg){	if (!user_access_begin(umsg, sizeof(*umsg)))		return -EFAULT;	unsafe_get_user(msg->msg_name, &umsg->msg_name, ua_end);	unsafe_get_user(msg->msg_namelen, &umsg->msg_namelen, ua_end);	unsafe_get_user(msg->msg_iov, &umsg->msg_iov, ua_end);	unsafe_get_user(msg->msg_iovlen, &umsg->msg_iovlen, ua_end);	unsafe_get_user(msg->msg_control, &umsg->msg_control, ua_end);	unsafe_get_user(msg->msg_controllen, &umsg->msg_controllen, ua_end);	user_access_end();	return 0;ua_end:	user_access_end();	return -EFAULT;} static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,			   struct user_msghdr *msg,			   struct sockaddr __user **save_addr){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);	int ret; 	iomsg->msg.msg_name = &iomsg->addr;	iomsg->msg.msg_iter.nr_segs = 0; 	if (io_is_compat(req->ctx)) {		struct compat_msghdr cmsg; 		if (copy_from_user(&cmsg, sr->umsg_compat, sizeof(cmsg)))			return -EFAULT; 		ret = __get_compat_msghdr(&iomsg->msg, &cmsg, save_addr);		if (ret)			return ret; 		memset(msg, 0, sizeof(*msg));		msg->msg_namelen = cmsg.msg_namelen;		msg->msg_controllen = cmsg.msg_controllen;		msg->msg_iov = compat_ptr(cmsg.msg_iov);		msg->msg_iovlen = cmsg.msg_iovlen;	} else {		ret = io_copy_msghdr_from_user(msg, sr->umsg);		if (unlikely(ret))			return ret; 		msg->msg_flags = 0; 		ret = __copy_msghdr(&iomsg->msg, msg, save_addr);		if (ret)			return ret;	} 	if (req->flags & REQ_F_BUFFER_SELECT) {		if (msg->msg_iovlen == 0) {			sr->len = 0;		} else if (msg->msg_iovlen > 1) {			return -EINVAL;		} else {			struct iovec fast_iov, *iov; 			iov = iovec_from_user(msg->msg_iov, 1, 1, &fast_iov,					      io_is_compat(req->ctx));			if (IS_ERR(iov))				return PTR_ERR(iov);			sr->len = iov->iov_len;		}	}	return 0;} void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req){	struct io_async_msghdr *io = req->async_data; 	io_netmsg_iovec_free(io);} static int io_send_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);	struct io_async_msghdr *kmsg = req->async_data;	void __user *addr;	u16 addr_len;	int ret; 	sr->buf = u64_to_user_ptr(READ_ONCE(sqe->addr)); 	if (READ_ONCE(sqe->__pad3[0]))		return -EINVAL; 	kmsg->msg.msg_name = NULL;	kmsg->msg.msg_namelen = 0;	kmsg->msg.msg_control = NULL;	kmsg->msg.msg_controllen = 0;	kmsg->msg.msg_ubuf = NULL; 	addr = u64_to_user_ptr(READ_ONCE(sqe->addr2));	addr_len = READ_ONCE(sqe->addr_len);	if (addr) {		ret = move_addr_to_kernel(addr, addr_len, &kmsg->addr);		if (unlikely(ret < 0))			return ret;		kmsg->msg.msg_name = &kmsg->addr;		kmsg->msg.msg_namelen = addr_len;	}	if (sr->flags & IORING_RECVSEND_FIXED_BUF) {		if (!(sr->flags & IORING_SEND_VECTORIZED)) {			req->flags |= REQ_F_IMPORT_BUFFER;			return 0;		} 		kmsg->msg.msg_iter.nr_segs = sr->len;		return io_prep_reg_iovec(req, &kmsg->vec, sr->buf, sr->len);	}	if (req->flags & REQ_F_BUFFER_SELECT)		return 0; 	if (sr->flags & IORING_SEND_VECTORIZED)		return io_net_import_vec(req, kmsg, sr->buf, sr->len, ITER_SOURCE); 	return import_ubuf(ITER_SOURCE, sr->buf, sr->len, &kmsg->msg.msg_iter);} static int io_sendmsg_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);	struct io_async_msghdr *kmsg = req->async_data;	struct user_msghdr msg;	int ret; 	sr->flags |= IORING_SEND_VECTORIZED;	sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));	ret = io_msg_copy_hdr(req, kmsg, &msg, NULL);	if (unlikely(ret))		return ret;	/* save msg_control as sys_sendmsg() overwrites it */	sr->msg_control = kmsg->msg.msg_control_user; 	if (sr->flags & IORING_RECVSEND_FIXED_BUF) {		kmsg->msg.msg_iter.nr_segs = msg.msg_iovlen;		return io_prep_reg_iovec(req, &kmsg->vec, msg.msg_iov,					 msg.msg_iovlen);	}	if (req->flags & REQ_F_BUFFER_SELECT)		return 0;	return io_net_import_vec(req, kmsg, msg.msg_iov, msg.msg_iovlen, ITER_SOURCE);} #define SENDMSG_FLAGS (IORING_RECVSEND_POLL_FIRST | IORING_RECVSEND_BUNDLE | \			IORING_SEND_VECTORIZED | IORING_RECVSEND_FIXED_BUF) int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); 	sr->done_io = 0;	sr->len = READ_ONCE(sqe->len);	if (unlikely(sr->len < 0))		return -EINVAL;	sr->flags = READ_ONCE(sqe->ioprio);	if (sr->flags & ~SENDMSG_FLAGS)		return -EINVAL;	if (sr->flags & IORING_RECVSEND_FIXED_BUF) {		/* registered buffer send only supported for plain IORING_OP_SEND */		if (req->opcode != IORING_OP_SEND ||		    (req->flags & REQ_F_BUFFER_SELECT) ||		    (sr->flags & (IORING_RECVSEND_BUNDLE|IORING_SEND_VECTORIZED)))			return -EINVAL;		req->buf_index = READ_ONCE(sqe->buf_index);	}	sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;	if (sr->msg_flags & MSG_DONTWAIT)		req->flags |= REQ_F_NOWAIT;	if (req->flags & REQ_F_BUFFER_SELECT)		sr->buf_group = req->buf_index;	sr->mshot_total_len = sr->mshot_len = 0;	if (sr->flags & IORING_RECVSEND_BUNDLE) {		if (req->opcode == IORING_OP_SENDMSG)			return -EINVAL;		sr->msg_flags |= MSG_WAITALL;		req->flags |= REQ_F_MULTISHOT;	} 	if (io_is_compat(req->ctx))		sr->msg_flags |= MSG_CMSG_COMPAT; 	if (unlikely(!io_msg_alloc_async(req)))		return -ENOMEM;	if (req->opcode != IORING_OP_SENDMSG)		return io_send_setup(req, sqe);	if (unlikely(sqe->addr2 || sqe->file_index))		return -EINVAL;	return io_sendmsg_setup(req, sqe);} static void io_req_msg_cleanup(struct io_kiocb *req,			       unsigned int issue_flags){	io_netmsg_recycle(req, issue_flags);} /* * For bundle completions, we need to figure out how many segments we consumed. * A bundle could be using a single ITER_UBUF if that's all we mapped, or it * could be using an ITER_IOVEC. If the latter, then if we consumed all of * the segments, then it's a trivial questiont o answer. If we have residual * data in the iter, then loop the segments to figure out how much we * transferred. */static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret){	struct iovec *iov;	int nbufs; 	/* no data is always zero segments, and a ubuf is always 1 segment */	if (ret <= 0)		return 0;	if (iter_is_ubuf(&kmsg->msg.msg_iter))		return 1; 	iov = kmsg->vec.iovec;	if (!iov)		iov = &kmsg->fast_iov; 	/* if all data was transferred, it's basic pointer math */	if (!iov_iter_count(&kmsg->msg.msg_iter))		return iter_iov(&kmsg->msg.msg_iter) - iov; 	/* short transfer, count segments */	nbufs = 0;	do {		int this_len = min_t(int, iov[nbufs].iov_len, ret); 		nbufs++;		ret -= this_len;	} while (ret); 	return nbufs;} static int io_net_kbuf_recyle(struct io_kiocb *req, struct io_buffer_list *bl,			      struct io_async_msghdr *kmsg, int len){	req->flags |= REQ_F_BL_NO_RECYCLE;	if (req->flags & REQ_F_BUFFERS_COMMIT)		io_kbuf_commit(req, bl, len, io_bundle_nbufs(kmsg, len));	return IOU_RETRY;} static inline bool io_send_finish(struct io_kiocb *req,				  struct io_async_msghdr *kmsg,				  struct io_br_sel *sel){	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);	bool bundle_finished = sel->val <= 0;	unsigned int cflags; 	if (!(sr->flags & IORING_RECVSEND_BUNDLE)) {		cflags = io_put_kbuf(req, sel->val, sel->buf_list);

Lines 1–500 of 1947.