mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Nyakundi Emmanuel <nyariboemmanuel8@gmail.com>
To: axboe@kernel.dk
Cc: federico.brasili@gmail.com, io-uring@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Nyakundi Emmanuel <nyariboemmanuel8@gmail.com>
Subject: [PATCH] test/recv-bundle-pbuf-len-poison: add regression test for pbuf len corruption
Date: Mon,  8 Jun 2026 01:10:47 +0300	[thread overview]
Message-ID: <20260607221114.135950-1-nyariboemmanuel8@gmail.com> (raw)
In-Reply-To: <1fd2ea63-c128-4641-9565-dbafd97de612@kernel.dk>

A failed IORING_RECVSEND_BUNDLE receive on a non-INC provided-buffer
ring can persistently corrupt the buffer descriptor length. When the
receive fails with -EAGAIN, the kernel writes the requested length into
buf->len during buffer selection but never restores it on failure.

A later unrelated IORING_OP_READ using the same buffer group then
consumes the corrupted length, returning fewer bytes than expected.

This test reproduces the issue as reported by Federico Brasili.

Reported-by: Federico Brasili <federico.brasili@gmail.com>
Link: https://lore.kernel.org/io-uring/CAAEr8jbY60noGj1fw_k91UJRBkyiRVoS6=nLhZ7Svwidjn4CAA@mail.gmail.com/
Signed-off-by: Nyakundi Emmanuel <nyariboemmanuel8@gmail.com>
---
 test/recv-bundle-pbuf-len-poison.c | 146 +++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 test/recv-bundle-pbuf-len-poison.c

diff --git a/test/recv-bundle-pbuf-len-poison.c b/test/recv-bundle-pbuf-len-poison.c
new file mode 100644
index 00000000..90fafff4
--- /dev/null
+++ b/test/recv-bundle-pbuf-len-poison.c
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Regression test for io_uring provided-buffer ring length corruption.
+ *
+ * A failed IORING_RECVSEND_BUNDLE receive on a non-INC provided-buffer
+ * ring can persistently shrink the user-visible buffer descriptor length.
+ * The modified length is not rolled back when the receive fails with
+ * -EAGAIN, and a later unrelated IORING_OP_READ from a pipe consumes
+ * the corrupted length.
+ *
+ * Reported-by: Federico Brasili <federico.brasili@gmail.com>
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BGID		8
+#define BUF_SIZE	4096
+#define NR_BUFS		2
+
+static int test(void)
+{
+	struct io_uring_buf_ring *br;
+	struct io_uring_cqe *cqe;
+	struct io_uring_sqe *sqe;
+	struct io_uring ring;
+	struct io_uring_buf *buf_entry;
+	int sockfd, pipefds[2], ret;
+	void *buf;
+	char pipe_data[BUF_SIZE];
+
+	ret = io_uring_queue_init(8, &ring, 0);
+	if (ret) {
+		fprintf(stderr, "queue init failed: %d\n", ret);
+		return T_EXIT_FAIL;
+	}
+
+	if (posix_memalign(&buf, 4096, BUF_SIZE * NR_BUFS))
+		return T_EXIT_FAIL;
+
+	/* set up non-INC provided buffer ring with 2 buffers of BUF_SIZE */
+	br = io_uring_setup_buf_ring(&ring, NR_BUFS, BGID, 0, &ret);
+	if (!br) {
+		if (ret == -EINVAL)
+			return T_EXIT_SKIP;
+		fprintf(stderr, "buf ring setup failed: %d\n", ret);
+		return T_EXIT_FAIL;
+	}
+
+	io_uring_buf_ring_add(br, buf,             BUF_SIZE, 0, NR_BUFS - 1, 0);
+	io_uring_buf_ring_add(br, buf + BUF_SIZE,  BUF_SIZE, 1, NR_BUFS - 1, 1);
+	io_uring_buf_ring_advance(br, NR_BUFS);
+
+	/* create an empty SOCK_DGRAM socket to trigger -EAGAIN */
+	sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (sockfd < 0) {
+		perror("socket");
+		return T_EXIT_FAIL;
+	}
+
+	/* submit RECV_BUNDLE on empty socket — expects -EAGAIN */
+	sqe = io_uring_get_sqe(&ring);
+	io_uring_prep_recv(sqe, sockfd, NULL, 1, MSG_DONTWAIT);
+	sqe->ioprio |= IORING_RECVSEND_BUNDLE;
+	sqe->flags  |= IOSQE_BUFFER_SELECT;
+	sqe->buf_group = BGID;
+	sqe->user_data  = 0x1111;
+	io_uring_submit(&ring);
+
+	ret = io_uring_wait_cqe(&ring, &cqe);
+	if (ret) {
+		fprintf(stderr, "wait cqe failed: %d\n", ret);
+		return T_EXIT_FAIL;
+	}
+	if (cqe->res != -EAGAIN) {
+		fprintf(stderr, "expected -EAGAIN, got %d\n", cqe->res);
+		io_uring_cqe_seen(&ring, cqe);
+		return T_EXIT_FAIL;
+	}
+	io_uring_cqe_seen(&ring, cqe);
+
+	/* check entry0.len — must still be BUF_SIZE after failed RECV */
+	buf_entry = &br->bufs[0];
+	if (buf_entry->len != BUF_SIZE) {
+		fprintf(stderr,
+			"FAIL: entry0.len corrupted after -EAGAIN RECV_BUNDLE: "
+			"got %u, expected %u\n",
+			buf_entry->len, BUF_SIZE);
+		return T_EXIT_FAIL;
+	}
+
+	/* now do a pipe READ using the same buffer group */
+	if (pipe(pipefds)) {
+		perror("pipe");
+		return T_EXIT_FAIL;
+	}
+
+	memset(pipe_data, 'A', BUF_SIZE);
+	if (write(pipefds[1], pipe_data, BUF_SIZE) != BUF_SIZE) {
+		fprintf(stderr, "pipe write failed\n");
+		return T_EXIT_FAIL;
+	}
+
+	sqe = io_uring_get_sqe(&ring);
+	io_uring_prep_read(sqe, pipefds[0], NULL, BUF_SIZE, 0);
+	sqe->flags    |= IOSQE_BUFFER_SELECT;
+	sqe->buf_group = BGID;
+	sqe->user_data  = 0x6666;
+	io_uring_submit(&ring);
+
+	ret = io_uring_wait_cqe(&ring, &cqe);
+	if (ret) {
+		fprintf(stderr, "wait read cqe failed: %d\n", ret);
+		return T_EXIT_FAIL;
+	}
+	if (cqe->res != BUF_SIZE) {
+		fprintf(stderr,
+			"FAIL: READ got %d bytes, expected %d — "
+			"pbuf len was poisoned by failed RECV_BUNDLE\n",
+			cqe->res, BUF_SIZE);
+		io_uring_cqe_seen(&ring, cqe);
+		return T_EXIT_FAIL;
+	}
+	io_uring_cqe_seen(&ring, cqe);
+
+	close(sockfd);
+	close(pipefds[0]);
+	close(pipefds[1]);
+	io_uring_queue_exit(&ring);
+	free(buf);
+	return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc > 1)
+		return T_EXIT_SKIP;
+
+	return test();
+}
-- 
2.54.0


  reply	other threads:[~2026-06-07 22:12 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-07 11:41 [BUG io_uring] Failed RECVSEND_BUNDLE can persistently shrink non-INC pbuf ring len and affect later READ operations Federico Brasili
2026-06-07 19:07 ` Jens Axboe
2026-06-07 20:08   ` Federico Brasili
2026-06-07 21:22     ` Nyakundi Emmanuel
2026-06-07 21:39       ` Jens Axboe
2026-06-07 22:10         ` Nyakundi Emmanuel [this message]
2026-06-07 22:16           ` [PATCH] test/recv-bundle-pbuf-len-poison: add regression test for pbuf len corruption Jens Axboe
2026-06-07 21:38     ` [BUG io_uring] Failed RECVSEND_BUNDLE can persistently shrink non-INC pbuf ring len and affect later READ operations Jens Axboe
2026-06-07 21:52       ` Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260607221114.135950-1-nyariboemmanuel8@gmail.com \
    --to=nyariboemmanuel8@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=federico.brasili@gmail.com \
    --cc=io-uring@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®