Skip to content

Commit 52307ac

Browse files
committed
io_uring/net: unify how recvmsg and sendmsg copy in the msghdr
For recvmsg, we roll our own since we support buffer selections. This isn't the case for sendmsg right now, but in preparation for doing so, make the recvmsg copy helpers generic so we can call them from the sendmsg side as well. Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent b4ccc4d commit 52307ac

File tree

1 file changed

+142
-129
lines changed

1 file changed

+142
-129
lines changed

io_uring/net.c

Lines changed: 142 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,150 @@ static int io_setup_async_msg(struct io_kiocb *req,
204204
return -EAGAIN;
205205
}
206206

207+
static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg)
208+
{
209+
int hdr;
210+
211+
if (iomsg->namelen < 0)
212+
return true;
213+
if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out),
214+
iomsg->namelen, &hdr))
215+
return true;
216+
if (check_add_overflow(hdr, (int)iomsg->controllen, &hdr))
217+
return true;
218+
219+
return false;
220+
}
221+
222+
#ifdef CONFIG_COMPAT
223+
static int __io_compat_msg_copy_hdr(struct io_kiocb *req,
224+
struct io_async_msghdr *iomsg,
225+
struct sockaddr __user **addr, int ddir)
226+
{
227+
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
228+
struct compat_msghdr msg;
229+
struct compat_iovec __user *uiov;
230+
int ret;
231+
232+
if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg)))
233+
return -EFAULT;
234+
235+
ret = __get_compat_msghdr(&iomsg->msg, &msg, addr);
236+
if (ret)
237+
return ret;
238+
239+
uiov = compat_ptr(msg.msg_iov);
240+
if (req->flags & REQ_F_BUFFER_SELECT) {
241+
compat_ssize_t clen;
242+
243+
iomsg->free_iov = NULL;
244+
if (msg.msg_iovlen == 0) {
245+
sr->len = 0;
246+
} else if (msg.msg_iovlen > 1) {
247+
return -EINVAL;
248+
} else {
249+
if (!access_ok(uiov, sizeof(*uiov)))
250+
return -EFAULT;
251+
if (__get_user(clen, &uiov->iov_len))
252+
return -EFAULT;
253+
if (clen < 0)
254+
return -EINVAL;
255+
sr->len = clen;
256+
}
257+
258+
if (ddir == ITER_DEST && req->flags & REQ_F_APOLL_MULTISHOT) {
259+
iomsg->namelen = msg.msg_namelen;
260+
iomsg->controllen = msg.msg_controllen;
261+
if (io_recvmsg_multishot_overflow(iomsg))
262+
return -EOVERFLOW;
263+
}
264+
265+
return 0;
266+
}
267+
268+
iomsg->free_iov = iomsg->fast_iov;
269+
ret = __import_iovec(ddir, (struct iovec __user *)uiov, msg.msg_iovlen,
270+
UIO_FASTIOV, &iomsg->free_iov,
271+
&iomsg->msg.msg_iter, true);
272+
if (unlikely(ret < 0))
273+
return ret;
274+
275+
return 0;
276+
}
277+
#endif
278+
279+
static int __io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
280+
struct sockaddr __user **addr, int ddir)
281+
{
282+
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
283+
struct user_msghdr msg;
284+
int ret;
285+
286+
if (copy_from_user(&msg, sr->umsg, sizeof(*sr->umsg)))
287+
return -EFAULT;
288+
289+
ret = __copy_msghdr(&iomsg->msg, &msg, addr);
290+
if (ret)
291+
return ret;
292+
293+
if (req->flags & REQ_F_BUFFER_SELECT) {
294+
if (msg.msg_iovlen == 0) {
295+
sr->len = iomsg->fast_iov[0].iov_len = 0;
296+
iomsg->fast_iov[0].iov_base = NULL;
297+
iomsg->free_iov = NULL;
298+
} else if (msg.msg_iovlen > 1) {
299+
return -EINVAL;
300+
} else {
301+
if (copy_from_user(iomsg->fast_iov, msg.msg_iov,
302+
sizeof(*msg.msg_iov)))
303+
return -EFAULT;
304+
sr->len = iomsg->fast_iov[0].iov_len;
305+
iomsg->free_iov = NULL;
306+
}
307+
308+
if (ddir == ITER_DEST && req->flags & REQ_F_APOLL_MULTISHOT) {
309+
iomsg->namelen = msg.msg_namelen;
310+
iomsg->controllen = msg.msg_controllen;
311+
if (io_recvmsg_multishot_overflow(iomsg))
312+
return -EOVERFLOW;
313+
}
314+
315+
return 0;
316+
}
317+
318+
iomsg->free_iov = iomsg->fast_iov;
319+
ret = __import_iovec(ddir, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
320+
&iomsg->free_iov, &iomsg->msg.msg_iter, false);
321+
if (unlikely(ret < 0))
322+
return ret;
323+
324+
return 0;
325+
}
326+
327+
static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
328+
struct sockaddr __user **addr, int ddir)
329+
{
330+
iomsg->msg.msg_name = &iomsg->addr;
331+
iomsg->msg.msg_iter.nr_segs = 0;
332+
333+
#ifdef CONFIG_COMPAT
334+
if (req->ctx->compat)
335+
return __io_compat_msg_copy_hdr(req, iomsg, addr, ddir);
336+
#endif
337+
338+
return __io_msg_copy_hdr(req, iomsg, addr, ddir);
339+
}
340+
207341
static int io_sendmsg_copy_hdr(struct io_kiocb *req,
208342
struct io_async_msghdr *iomsg)
209343
{
210344
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
211345
int ret;
212346

213-
iomsg->msg.msg_name = &iomsg->addr;
214-
iomsg->free_iov = iomsg->fast_iov;
215-
ret = sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
216-
&iomsg->free_iov);
347+
ret = io_msg_copy_hdr(req, iomsg, NULL, ITER_SOURCE);
348+
if (ret)
349+
return ret;
350+
217351
/* save msg_control as sys_sendmsg() overwrites it */
218352
sr->msg_control = iomsg->msg.msg_control_user;
219353
return ret;
@@ -435,142 +569,21 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags)
435569
return IOU_OK;
436570
}
437571

438-
static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg)
439-
{
440-
int hdr;
441-
442-
if (iomsg->namelen < 0)
443-
return true;
444-
if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out),
445-
iomsg->namelen, &hdr))
446-
return true;
447-
if (check_add_overflow(hdr, (int)iomsg->controllen, &hdr))
448-
return true;
449-
450-
return false;
451-
}
452-
453-
static int __io_recvmsg_copy_hdr(struct io_kiocb *req,
454-
struct io_async_msghdr *iomsg)
455-
{
456-
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
457-
struct user_msghdr msg;
458-
int ret;
459-
460-
if (copy_from_user(&msg, sr->umsg, sizeof(*sr->umsg)))
461-
return -EFAULT;
462-
463-
ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
464-
if (ret)
465-
return ret;
466-
467-
if (req->flags & REQ_F_BUFFER_SELECT) {
468-
if (msg.msg_iovlen == 0) {
469-
sr->len = iomsg->fast_iov[0].iov_len = 0;
470-
iomsg->fast_iov[0].iov_base = NULL;
471-
iomsg->free_iov = NULL;
472-
} else if (msg.msg_iovlen > 1) {
473-
return -EINVAL;
474-
} else {
475-
if (copy_from_user(iomsg->fast_iov, msg.msg_iov, sizeof(*msg.msg_iov)))
476-
return -EFAULT;
477-
sr->len = iomsg->fast_iov[0].iov_len;
478-
iomsg->free_iov = NULL;
479-
}
480-
481-
if (req->flags & REQ_F_APOLL_MULTISHOT) {
482-
iomsg->namelen = msg.msg_namelen;
483-
iomsg->controllen = msg.msg_controllen;
484-
if (io_recvmsg_multishot_overflow(iomsg))
485-
return -EOVERFLOW;
486-
}
487-
} else {
488-
iomsg->free_iov = iomsg->fast_iov;
489-
ret = __import_iovec(ITER_DEST, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
490-
&iomsg->free_iov, &iomsg->msg.msg_iter,
491-
false);
492-
if (ret > 0)
493-
ret = 0;
494-
}
495-
496-
return ret;
497-
}
498-
499-
#ifdef CONFIG_COMPAT
500-
static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
501-
struct io_async_msghdr *iomsg)
502-
{
503-
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
504-
struct compat_msghdr msg;
505-
struct compat_iovec __user *uiov;
506-
int ret;
507-
508-
if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg)))
509-
return -EFAULT;
510-
511-
ret = __get_compat_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
512-
if (ret)
513-
return ret;
514-
515-
uiov = compat_ptr(msg.msg_iov);
516-
if (req->flags & REQ_F_BUFFER_SELECT) {
517-
compat_ssize_t clen;
518-
519-
iomsg->free_iov = NULL;
520-
if (msg.msg_iovlen == 0) {
521-
sr->len = 0;
522-
} else if (msg.msg_iovlen > 1) {
523-
return -EINVAL;
524-
} else {
525-
if (!access_ok(uiov, sizeof(*uiov)))
526-
return -EFAULT;
527-
if (__get_user(clen, &uiov->iov_len))
528-
return -EFAULT;
529-
if (clen < 0)
530-
return -EINVAL;
531-
sr->len = clen;
532-
}
533-
534-
if (req->flags & REQ_F_APOLL_MULTISHOT) {
535-
iomsg->namelen = msg.msg_namelen;
536-
iomsg->controllen = msg.msg_controllen;
537-
if (io_recvmsg_multishot_overflow(iomsg))
538-
return -EOVERFLOW;
539-
}
540-
} else {
541-
iomsg->free_iov = iomsg->fast_iov;
542-
ret = __import_iovec(ITER_DEST, (struct iovec __user *)uiov, msg.msg_iovlen,
543-
UIO_FASTIOV, &iomsg->free_iov,
544-
&iomsg->msg.msg_iter, true);
545-
if (ret < 0)
546-
return ret;
547-
}
548-
549-
return 0;
550-
}
551-
#endif
552-
553572
static int io_recvmsg_copy_hdr(struct io_kiocb *req,
554573
struct io_async_msghdr *iomsg)
555574
{
556-
iomsg->msg.msg_name = &iomsg->addr;
557-
iomsg->msg.msg_iter.nr_segs = 0;
558-
559-
#ifdef CONFIG_COMPAT
560-
if (req->ctx->compat)
561-
return __io_compat_recvmsg_copy_hdr(req, iomsg);
562-
#endif
563-
564-
return __io_recvmsg_copy_hdr(req, iomsg);
575+
return io_msg_copy_hdr(req, iomsg, &iomsg->uaddr, ITER_DEST);
565576
}
566577

567578
int io_recvmsg_prep_async(struct io_kiocb *req)
568579
{
580+
struct io_async_msghdr *iomsg;
569581
int ret;
570582

571583
if (!io_msg_alloc_async_prep(req))
572584
return -ENOMEM;
573-
ret = io_recvmsg_copy_hdr(req, req->async_data);
585+
iomsg = req->async_data;
586+
ret = io_recvmsg_copy_hdr(req, iomsg);
574587
if (!ret)
575588
req->flags |= REQ_F_NEED_CLEANUP;
576589
return ret;

0 commit comments

Comments
 (0)