* [PATCH 0/2] Fix return with MSG_TUNC overtruncating buffers
@ 2026-09-02 23:00 Gabriel Krisman Bertazi
2026-09-02 23:00 ` [PATCH 1/2] io_uring/net: let io_recv_buf_select return the length of the buffer region Gabriel Krisman Bertazi
2026-09-02 23:00 ` [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC Gabriel Krisman Bertazi
0 siblings, 2 replies; 5+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-09-02 23:00 UTC (permalink / raw)
To: axboe; +Cc: io-uring, Gabriel Krisman Bertazi
Jens,
This is an attempt to fix the issue reported at [1]. It works by
splitting the return size (which can be the full size of the packet)
from the value actually commited in the buffer. Please, let me know
your thoughts. Patch 1 is a small preparation and patch 2 has the fix.
This was tested for regressions against liburing as well as using the
reproducer from the bug, which I can turn into a proper test case
against liburing.
I sent this before but the submission was botched. Please take this
version in consideration.
Thanks,
[1] https://github.com/axboe/liburing/issues/1619
Gabriel Krisman Bertazi (2):
io_uring/net: let io_recv_buf_select return the length of the buffer
region
io_uring/net: don't overconsume buffers when using MSG_TRUNC
io_uring/net.c | 48 +++++++++++++++++++++++++++++++++++++-----------
1 file changed, 37 insertions(+), 11 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 1/2] io_uring/net: let io_recv_buf_select return the length of the buffer region 2026-09-02 23:00 [PATCH 0/2] Fix return with MSG_TUNC overtruncating buffers Gabriel Krisman Bertazi @ 2026-09-02 23:00 ` Gabriel Krisman Bertazi 2026-09-02 23:00 ` [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC Gabriel Krisman Bertazi 1 sibling, 0 replies; 5+ messages in thread From: Gabriel Krisman Bertazi @ 2026-09-02 23:00 UTC (permalink / raw) To: axboe; +Cc: io-uring, Gabriel Krisman Bertazi, stable In preparation to using this field as an upper limit to truncation, return the size of the allocated region. Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") Cc: stable@vger.kernel.org Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de> --- io_uring/net.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/io_uring/net.c b/io_uring/net.c index fbe719d86c46..647156c9331a 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -1108,6 +1108,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg struct io_br_sel *sel, unsigned int issue_flags) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); + size_t len; int ret; /* @@ -1153,13 +1154,14 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg /* special case 1 vec, can be a fast path */ if (ret == 1) { sr->buf = arg.iovs[0].iov_base; - sr->len = arg.iovs[0].iov_len; + len = sr->len = arg.iovs[0].iov_len; goto map_ubuf; } iov_iter_init(&kmsg->msg.msg_iter, ITER_DEST, arg.iovs, ret, - arg.out_len); + arg.out_len); + len = arg.out_len; } else { - size_t len = sel->val; + len = sel->val; *sel = io_buffer_select(req, &len, sr->buf_group, issue_flags); if (!sel->addr) @@ -1173,7 +1175,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg return ret; } - return 0; + return len; } int io_recv(struct io_kiocb *req, unsigned int issue_flags) -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC 2026-09-02 23:00 [PATCH 0/2] Fix return with MSG_TUNC overtruncating buffers Gabriel Krisman Bertazi 2026-09-02 23:00 ` [PATCH 1/2] io_uring/net: let io_recv_buf_select return the length of the buffer region Gabriel Krisman Bertazi @ 2026-09-02 23:00 ` Gabriel Krisman Bertazi 2026-09-09 13:56 ` Jens Axboe 1 sibling, 1 reply; 5+ messages in thread From: Gabriel Krisman Bertazi @ 2026-09-02 23:00 UTC (permalink / raw) To: axboe; +Cc: io-uring, Gabriel Krisman Bertazi, stable When a recv/recvmsg is issued with MSG_TRUNC and the incoming packet is larger than the provided buffer, the net layer returns the full length of the packet rather than the number of bytes actually copied into the buffer. As a result, io_uring advances more of the provided buffer ring than was actually filled. Use the actual filled region size to consume the buffer, but still return the full size to preserve MSG_TRUNC semantics. Take care with multishot, because that seems to already truncate the consumption based on the available payload size. This was reported in https://github.com/axboe/liburing/issues/1619. Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260728191454.1850326-1-krisman@suse.de Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de> --- io_uring/net.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/io_uring/net.c b/io_uring/net.c index 647156c9331a..f8110dc9f860 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -853,7 +853,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) static inline bool io_recv_finish(struct io_kiocb *req, struct io_async_msghdr *kmsg, struct io_br_sel *sel, bool mshot_finished, - unsigned issue_flags) + unsigned issue_flags, size_t consumed) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); unsigned int cflags = 0; @@ -877,7 +877,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, if (sr->flags & IORING_RECVSEND_BUNDLE) { size_t this_ret = sel->val - sr->done_io; - cflags |= io_put_kbufs(req, this_ret, sel->buf_list, io_bundle_nbufs(kmsg, this_ret)); + cflags |= io_put_kbufs(req, consumed, sel->buf_list, io_bundle_nbufs(kmsg, consumed)); if (sr->flags & IORING_RECV_RETRY) cflags = req->cqe.flags | (cflags & CQE_F_MASK); if (sr->mshot_len && sel->val >= sr->mshot_len) @@ -899,7 +899,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, return false; } } else { - cflags |= io_put_kbuf(req, sel->val, sel->buf_list); + cflags |= io_put_kbuf(req, consumed, sel->buf_list); } /* @@ -1027,6 +1027,7 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) int ret, min_ret = 0; bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; bool mshot_finished = true; + size_t len, consumed = 0; sock = sock_from_file(req->file); if (unlikely(!sock)) @@ -1042,9 +1043,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) retry_multishot: sel.buf_list = NULL; + len = sr->len; if (io_do_buffer_select(req)) { - size_t len = sr->len; - sel = io_buffer_select(req, &len, sr->buf_group, issue_flags); if (!sel.addr) return -ENOBUFS; @@ -1065,6 +1065,7 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) if (req->flags & REQ_F_APOLL_MULTISHOT) { ret = io_recvmsg_multishot(sock, sr, kmsg, flags, &mshot_finished); + consumed = ret; } else { /* disable partial retry for recvmsg with cmsg attached */ if (flags & MSG_WAITALL && !kmsg->msg.msg_controllen) @@ -1072,6 +1073,15 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) ret = __sys_recvmsg_sock(sock, &kmsg->msg, sr->umsg, kmsg->uaddr, flags); + /* + * With MSG_TRUNC, the net layer will return the full size of + * the packet, even if we only filled part of it in the buffers. + * Adjust the returned size to consume only the real part of the + * buffer. + */ + consumed = ret; + if (ret > len) + consumed = len; } if (ret < min_ret) { @@ -1098,7 +1108,7 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) io_kbuf_recycle(req, sel.buf_list, issue_flags); sel.val = ret; - if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags)) + if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags, consumed)) goto retry_multishot; return sel.val; @@ -1186,6 +1196,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) struct socket *sock; unsigned flags; int ret, min_ret = 0; + size_t consumed = 0, len = 0; bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; bool mshot_finished; @@ -1215,6 +1226,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) retry_multishot: sel.buf_list = NULL; + len = sr->len; if (io_do_buffer_select(req)) { sel.val = sr->len; ret = io_recv_buf_select(req, kmsg, &sel, issue_flags); @@ -1222,6 +1234,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) kmsg->msg.msg_inq = -1; goto out_free; } + len = ret; sr->buf = NULL; } @@ -1252,6 +1265,17 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) } mshot_finished = ret <= 0; + + /* + * With MSG_TRUNC, the net layer will return the full size of + * the packet, even if we only filled part of it in the buffers. + * Adjust the returned size to consume only the real part of the + * buffer. + */ + consumed = ret; + if (ret > len) + consumed = len; + if (ret > 0) ret += sr->done_io; else if (sr->done_io) @@ -1260,7 +1284,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) io_kbuf_recycle(req, sel.buf_list, issue_flags); sel.val = ret; - if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags)) + if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags, consumed)) goto retry_multishot; return sel.val; -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC 2026-09-02 23:00 ` [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC Gabriel Krisman Bertazi @ 2026-09-09 13:56 ` Jens Axboe 2026-09-09 13:58 ` Jens Axboe 0 siblings, 1 reply; 5+ messages in thread From: Jens Axboe @ 2026-09-09 13:56 UTC (permalink / raw) To: Gabriel Krisman Bertazi; +Cc: io-uring, Gabriel Krisman Bertazi, stable > When a recv/recvmsg is issued with MSG_TRUNC and the incoming packet is > larger than the provided buffer, the net layer returns the full length > of the packet rather than the number of bytes actually copied into the > buffer. As a result, io_uring advances more of the provided buffer ring > than was actually filled. Use the actual filled region size to consume > the buffer, but still return the full size to preserve MSG_TRUNC > semantics. > > Take care with multishot, because that seems to already truncate the > consumption based on the available payload size. > > This was reported in https://github.com/axboe/liburing/issues/1619. > > Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") > Cc: stable@vger.kernel.org > Link: https://patch.msgid.link/20260728191454.1850326-1-krisman@suse.de > Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de> > --- > io_uring/net.c | 38 +++++++++++++++++++++++++++++++------- > 1 file changed, 31 insertions(+), 7 deletions(-) > > diff --git a/io_uring/net.c b/io_uring/net.c > index 647156c9331a..f8110dc9f860 100644 > --- a/io_uring/net.c > +++ b/io_uring/net.c > @@ -853,7 +853,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) > static inline bool io_recv_finish(struct io_kiocb *req, > struct io_async_msghdr *kmsg, > struct io_br_sel *sel, bool mshot_finished, > - unsigned issue_flags) > + unsigned issue_flags, size_t consumed) > { Not sure this is correct. If consumed is a size_t, then the comparison between ret > len is an unsigned comparison, and every error will then get clamped? Will need something like this folded in. diff --git a/io_uring/net.c b/io_uring/net.c index f8110dc9f860..0ca43a24f1a5 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -853,7 +853,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) static inline bool io_recv_finish(struct io_kiocb *req, struct io_async_msghdr *kmsg, struct io_br_sel *sel, bool mshot_finished, - unsigned issue_flags, size_t consumed) + unsigned issue_flags, int consumed) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); unsigned int cflags = 0; @@ -1027,7 +1027,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) int ret, min_ret = 0; bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; bool mshot_finished = true; - size_t len, consumed = 0; + int consumed = 0; + size_t len; sock = sock_from_file(req->file); if (unlikely(!sock)) @@ -1080,8 +1081,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags) * buffer. */ consumed = ret; - if (ret > len) - consumed = len; + if (ret > 0) + consumed = min_t(size_t, ret, len); } if (ret < min_ret) { @@ -1195,10 +1196,11 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) struct io_br_sel sel; struct socket *sock; unsigned flags; - int ret, min_ret = 0; - size_t consumed = 0, len = 0; + int ret, min_ret = 0, consumed = 0; + int consumed = 0; bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; bool mshot_finished; + size_t len = 0; sock = sock_from_file(req->file); if (unlikely(!sock)) @@ -1273,8 +1275,8 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags) * buffer. */ consumed = ret; - if (ret > len) - consumed = len; + if (ret > 0) + consumed = min_t(size_t, ret, len); if (ret > 0) ret += sr->done_io; -- Jens Axboe ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC 2026-09-09 13:56 ` Jens Axboe @ 2026-09-09 13:58 ` Jens Axboe 0 siblings, 0 replies; 5+ messages in thread From: Jens Axboe @ 2026-09-09 13:58 UTC (permalink / raw) To: Gabriel Krisman Bertazi; +Cc: io-uring, stable On 9/9/26 7:56 AM, Jens Axboe wrote: >> When a recv/recvmsg is issued with MSG_TRUNC and the incoming packet is >> larger than the provided buffer, the net layer returns the full length >> of the packet rather than the number of bytes actually copied into the >> buffer. As a result, io_uring advances more of the provided buffer ring >> than was actually filled. Use the actual filled region size to consume >> the buffer, but still return the full size to preserve MSG_TRUNC >> semantics. >> >> Take care with multishot, because that seems to already truncate the >> consumption based on the available payload size. >> >> This was reported in https://github.com/axboe/liburing/issues/1619. >> >> Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") >> Cc: stable@vger.kernel.org >> Link: https://patch.msgid.link/20260728191454.1850326-1-krisman@suse.de >> Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de> >> --- >> io_uring/net.c | 38 +++++++++++++++++++++++++++++++------- >> 1 file changed, 31 insertions(+), 7 deletions(-) >> >> diff --git a/io_uring/net.c b/io_uring/net.c >> index 647156c9331a..f8110dc9f860 100644 >> --- a/io_uring/net.c >> +++ b/io_uring/net.c >> @@ -853,7 +853,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) >> static inline bool io_recv_finish(struct io_kiocb *req, >> struct io_async_msghdr *kmsg, >> struct io_br_sel *sel, bool mshot_finished, >> - unsigned issue_flags) >> + unsigned issue_flags, size_t consumed) >> { > > Not sure this is correct. If consumed is a size_t, then the comparison > between ret > len is an unsigned comparison, and every error will then > get clamped? > > Will need something like this folded in. Can you check the current io_uring-7.3 or for-next tree and see if it still fixes the issue? -- Jens Axboe ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-09 13:58 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-02 23:00 [PATCH 0/2] Fix return with MSG_TUNC overtruncating buffers Gabriel Krisman Bertazi 2026-09-02 23:00 ` [PATCH 1/2] io_uring/net: let io_recv_buf_select return the length of the buffer region Gabriel Krisman Bertazi 2026-09-02 23:00 ` [PATCH 2/2] io_uring/net: don't overconsume buffers when using MSG_TRUNC Gabriel Krisman Bertazi 2026-09-09 13:56 ` Jens Axboe 2026-09-09 13:58 ` Jens Axboe
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox