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
165
io_uring/net.c
165
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,
|
||||
struct io_async_msghdr *iomsg,
|
||||
struct sockaddr __user **addr, int ddir)
|
||||
static int io_compat_msg_copy_hdr(struct io_kiocb *req,
|
||||
struct io_async_msghdr *iomsg,
|
||||
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 New Issue
Block a user