提交 c5eb3fd3 编写于 作者: J Jens Axboe 提交者: Joseph Qi

io_uring: fix sporadic -EFAULT from IORING_OP_RECVMSG

to #26323578

commit 0b416c3e1345fd696db4c422643468d844410877 upstream.

If we have to punt the recvmsg to async context, we copy all the
context.  But since the iovec used can be either on-stack (if small) or
dynamically allocated, if it's on-stack, then we need to ensure we reset
the iov pointer. If we don't, then we're reusing old stack data, and
that can lead to -EFAULTs if things get overwritten.

Ensure we retain the right pointers for the iov, and free it as well if
we end up having to go beyond UIO_FASTIOV number of vectors.

Fixes: 03b1230ca12a ("io_uring: ensure async punted sendmsg/recvmsg requests copy data")
Reported-by: N李通洲 <carter.li@eoitek.com>
Signed-off-by: NJens Axboe <axboe@kernel.dk>
Signed-off-by: NJoseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: NXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
上级 29e01b6a
......@@ -2037,6 +2037,7 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
struct io_kiocb **nxt, bool force_nonblock)
{
#if defined(CONFIG_NET)
struct io_async_msghdr *kmsg = NULL;
struct socket *sock;
int ret;
......@@ -2047,7 +2048,6 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
if (sock) {
struct io_async_ctx io, *copy;
struct sockaddr_storage addr;
struct msghdr *kmsg;
unsigned flags;
flags = READ_ONCE(sqe->msg_flags);
......@@ -2057,17 +2057,21 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
flags |= MSG_DONTWAIT;
if (req->io) {
kmsg = &req->io->msg.msg;
kmsg->msg_name = &addr;
kmsg = &req->io->msg;
kmsg->msg.msg_name = &addr;
/* if iov is set, it's allocated already */
if (!kmsg->iov)
kmsg->iov = kmsg->fast_iov;
kmsg->msg.msg_iter.iov = kmsg->iov;
} else {
kmsg = &io.msg.msg;
kmsg->msg_name = &addr;
kmsg = &io.msg;
kmsg->msg.msg_name = &addr;
ret = io_sendmsg_prep(req, &io);
if (ret)
goto out;
}
ret = __sys_sendmsg_sock(sock, kmsg, flags);
ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
if (force_nonblock && ret == -EAGAIN) {
copy = kmalloc(sizeof(*copy), GFP_KERNEL);
if (!copy) {
......@@ -2078,13 +2082,15 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
req->io = copy;
memcpy(&req->io->sqe, req->sqe, sizeof(*req->sqe));
req->sqe = &req->io->sqe;
return ret;
return -EAGAIN;
}
if (ret == -ERESTARTSYS)
ret = -EINTR;
}
out:
if (kmsg && kmsg->iov != kmsg->fast_iov)
kfree(kmsg->iov);
io_cqring_add_event(req, ret);
if (ret < 0)
req_set_fail_links(req);
......@@ -2116,6 +2122,7 @@ static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
struct io_kiocb **nxt, bool force_nonblock)
{
#if defined(CONFIG_NET)
struct io_async_msghdr *kmsg = NULL;
struct socket *sock;
int ret;
......@@ -2127,7 +2134,6 @@ static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
struct user_msghdr __user *msg;
struct io_async_ctx io, *copy;
struct sockaddr_storage addr;
struct msghdr *kmsg;
unsigned flags;
flags = READ_ONCE(sqe->msg_flags);
......@@ -2139,17 +2145,21 @@ static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
msg = (struct user_msghdr __user *) (unsigned long)
READ_ONCE(sqe->addr);
if (req->io) {
kmsg = &req->io->msg.msg;
kmsg->msg_name = &addr;
kmsg = &req->io->msg;
kmsg->msg.msg_name = &addr;
/* if iov is set, it's allocated already */
if (!kmsg->iov)
kmsg->iov = kmsg->fast_iov;
kmsg->msg.msg_iter.iov = kmsg->iov;
} else {
kmsg = &io.msg.msg;
kmsg->msg_name = &addr;
kmsg = &io.msg;
kmsg->msg.msg_name = &addr;
ret = io_recvmsg_prep(req, &io);
if (ret)
goto out;
}
ret = __sys_recvmsg_sock(sock, kmsg, msg, io.msg.uaddr, flags);
ret = __sys_recvmsg_sock(sock, &kmsg->msg, msg, kmsg->uaddr, flags);
if (force_nonblock && ret == -EAGAIN) {
copy = kmalloc(sizeof(*copy), GFP_KERNEL);
if (!copy) {
......@@ -2160,13 +2170,15 @@ static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
req->io = copy;
memcpy(&req->io->sqe, req->sqe, sizeof(*req->sqe));
req->sqe = &req->io->sqe;
return ret;
return -EAGAIN;
}
if (ret == -ERESTARTSYS)
ret = -EINTR;
}
out:
if (kmsg && kmsg->iov != kmsg->fast_iov)
kfree(kmsg->iov);
io_cqring_add_event(req, ret);
if (ret < 0)
req_set_fail_links(req);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册