--- /dev/null
+From c16cb4e2a4b1a487ca7feae5931dfb22ac495b76 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Tue, 12 Aug 2025 08:30:11 -0600
+Subject: io_uring/net: commit partial buffers on retry
+
+From: Jens Axboe <axboe@kernel.dk>
+
+Commit 41b70df5b38bc80967d2e0ed55cc3c3896bba781 upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/net.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/io_uring/net.c
++++ b/io_uring/net.c
+@@ -351,6 +351,13 @@ static int io_setup_async_addr(struct io
+ return -EAGAIN;
+ }
+
++static void io_net_kbuf_recyle(struct io_kiocb *req)
++{
++ req->flags |= REQ_F_PARTIAL_IO;
++ if (req->flags & REQ_F_BUFFER_RING)
++ io_kbuf_recycle_ring(req);
++}
++
+ int io_sendmsg_prep_async(struct io_kiocb *req)
+ {
+ int ret;
+@@ -442,7 +449,7 @@ int io_sendmsg(struct io_kiocb *req, uns
+ kmsg->msg.msg_controllen = 0;
+ kmsg->msg.msg_control = NULL;
+ sr->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return io_setup_async_msg(req, kmsg, issue_flags);
+ }
+ if (ret == -ERESTARTSYS)
+@@ -521,7 +528,7 @@ int io_send(struct io_kiocb *req, unsign
+ sr->len -= ret;
+ sr->buf += ret;
+ sr->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return io_setup_async_addr(req, &__address, issue_flags);
+ }
+ if (ret == -ERESTARTSYS)
+@@ -891,7 +898,7 @@ retry_multishot:
+ }
+ if (ret > 0 && io_net_retry(sock, flags)) {
+ sr->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return io_setup_async_msg(req, kmsg, issue_flags);
+ }
+ if (ret == -ERESTARTSYS)
+@@ -991,7 +998,7 @@ retry_multishot:
+ sr->len -= ret;
+ sr->buf += ret;
+ sr->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return -EAGAIN;
+ }
+ if (ret == -ERESTARTSYS)
+@@ -1235,7 +1242,7 @@ int io_send_zc(struct io_kiocb *req, uns
+ zc->len -= ret;
+ zc->buf += ret;
+ zc->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return io_setup_async_addr(req, &__address, issue_flags);
+ }
+ if (ret == -ERESTARTSYS)
+@@ -1306,7 +1313,7 @@ int io_sendmsg_zc(struct io_kiocb *req,
+
+ if (ret > 0 && io_net_retry(sock, flags)) {
+ sr->done_io += ret;
+- req->flags |= REQ_F_PARTIAL_IO;
++ io_net_kbuf_recyle(req);
+ return io_setup_async_msg(req, kmsg, issue_flags);
+ }
+ if (ret == -ERESTARTSYS)