Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

io_uring/net: commit partial buffers on retry

Ring provided buffers are potentially only valid within the single
execution context in which they were acquired. io_uring deals with this
and invalidates them on retry. But on the networking side, if
MSG_WAITALL is set, or if the socket is of the streaming type and too
little was processed, then it will hang on to the buffer rather than
recycle or commit it. This is problematic for two reasons:

1) If someone unregisters the provided buffer ring before a later retry,
then the req->buf_list will no longer be valid.

2) If multiple sockers are using the same buffer group, then multiple
receives can consume the same memory. This can cause data corruption
in the application, as either receive could land in the same
userspace buffer.

Fix this by disallowing partial retries from pinning a provided buffer
across multiple executions, if ring provided buffers are used.

Cc: stable@vger.kernel.org
Reported-by: pt x <superman.xpt@gmail.com>
Fixes: c56e022c0a27 ("io_uring: add support for user mapped provided buffer ring")
Signed-off-by: Jens Axboe <axboe@kernel.dk>

Jens Axboe 41b70df5 8f5ae30d

+15 -12
+15 -12
io_uring/net.c
··· 494 494 return nbufs; 495 495 } 496 496 497 + static int io_net_kbuf_recyle(struct io_kiocb *req, 498 + struct io_async_msghdr *kmsg, int len) 499 + { 500 + req->flags |= REQ_F_BL_NO_RECYCLE; 501 + if (req->flags & REQ_F_BUFFERS_COMMIT) 502 + io_kbuf_commit(req, req->buf_list, len, io_bundle_nbufs(kmsg, len)); 503 + return IOU_RETRY; 504 + } 505 + 497 506 static inline bool io_send_finish(struct io_kiocb *req, int *ret, 498 507 struct io_async_msghdr *kmsg, 499 508 unsigned issue_flags) ··· 571 562 kmsg->msg.msg_controllen = 0; 572 563 kmsg->msg.msg_control = NULL; 573 564 sr->done_io += ret; 574 - req->flags |= REQ_F_BL_NO_RECYCLE; 575 - return -EAGAIN; 565 + return io_net_kbuf_recyle(req, kmsg, ret); 576 566 } 577 567 if (ret == -ERESTARTSYS) 578 568 ret = -EINTR; ··· 682 674 sr->len -= ret; 683 675 sr->buf += ret; 684 676 sr->done_io += ret; 685 - req->flags |= REQ_F_BL_NO_RECYCLE; 686 - return -EAGAIN; 677 + return io_net_kbuf_recyle(req, kmsg, ret); 687 678 } 688 679 if (ret == -ERESTARTSYS) 689 680 ret = -EINTR; ··· 1078 1071 } 1079 1072 if (ret > 0 && io_net_retry(sock, flags)) { 1080 1073 sr->done_io += ret; 1081 - req->flags |= REQ_F_BL_NO_RECYCLE; 1082 - return IOU_RETRY; 1074 + return io_net_kbuf_recyle(req, kmsg, ret); 1083 1075 } 1084 1076 if (ret == -ERESTARTSYS) 1085 1077 ret = -EINTR; ··· 1224 1218 sr->len -= ret; 1225 1219 sr->buf += ret; 1226 1220 sr->done_io += ret; 1227 - req->flags |= REQ_F_BL_NO_RECYCLE; 1228 - return -EAGAIN; 1221 + return io_net_kbuf_recyle(req, kmsg, ret); 1229 1222 } 1230 1223 if (ret == -ERESTARTSYS) 1231 1224 ret = -EINTR; ··· 1505 1500 zc->len -= ret; 1506 1501 zc->buf += ret; 1507 1502 zc->done_io += ret; 1508 - req->flags |= REQ_F_BL_NO_RECYCLE; 1509 - return -EAGAIN; 1503 + return io_net_kbuf_recyle(req, kmsg, ret); 1510 1504 } 1511 1505 if (ret == -ERESTARTSYS) 1512 1506 ret = -EINTR; ··· 1575 1571 1576 1572 if (ret > 0 && io_net_retry(sock, flags)) { 1577 1573 sr->done_io += ret; 1578 - req->flags |= REQ_F_BL_NO_RECYCLE; 1579 - return -EAGAIN; 1574 + return io_net_kbuf_recyle(req, kmsg, ret); 1580 1575 } 1581 1576 if (ret == -ERESTARTSYS) 1582 1577 ret = -EINTR;