[LTP] [PATCH v3 2/2] cve-2026-46331: fix intermittent ENOENT failure

Andrea Cervesato andrea.cervesato@suse.de
Mon Jul 20 16:31:52 CEST 2026


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

The required qdisc, classifier and action modules cannot be
autoloaded from the unprivileged user namespace, so arming the
traffic filter sometimes failed with ENOENT.

Preload the modules as root before dropping privileges and entering
the network namespace.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/cve/cve-2026-46331.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/testcases/cve/cve-2026-46331.c b/testcases/cve/cve-2026-46331.c
index c33d358396f21024d8a68e9cd5c4cae0a9339a9f..6af43afb7910dd72777c1433f75dc8efce33366e 100644
--- a/testcases/cve/cve-2026-46331.c
+++ b/testcases/cve/cve-2026-46331.c
@@ -32,12 +32,19 @@
  * - Reread the file through the same ``O_RDONLY`` descriptor and
  *   compare with the original pattern; any difference means the
  *   page cache was corrupted
+ *
+ * The test needs root to preload the qdisc, classifier and action
+ * modules, which cannot be autoloaded from the unprivileged user
+ * namespace, before dropping privileges to an unprivileged user.
  */
 
 #include <sys/sendfile.h>
+#include <sys/prctl.h>
+#include <pwd.h>
 #include <linux/rtnetlink.h>
 
 #include "tst_test.h"
+#include "tst_module.h"
 #include "tst_net.h"
 #include "tst_netdevice.h"
 #include "lapi/if_ether.h"
@@ -128,7 +135,25 @@ static int acc_fd = -1;
 static void setup(void)
 {
 	struct sockaddr_in addr;
-	int i;
+	struct passwd *pw;
+	static const char *const mods[] = {
+		"sch_ingress", "cls_matchall", "act_pedit"
+	};
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(mods); i++)
+		tst_modprobe(mods[i], NULL);
+
+	/* Drop privileges so the reproducer runs as an unprivileged user */
+	pw = SAFE_GETPWNAM("nobody");
+	SAFE_SETGID(pw->pw_gid);
+	SAFE_SETUID(pw->pw_uid);
+
+	/*
+	 * setuid() clears the dumpable flag, which makes the /proc/self
+	 * files owned by root and prevents tst_setup_netns() from writing the
+	 * uid/gid maps. Restore it so the user namespace can be set up.
+	 */
+	SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
 
 	tst_setup_netns();
 	NETDEV_SET_STATE("lo", 1);
@@ -144,7 +169,7 @@ static void setup(void)
 	SAFE_BIND(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
 	SAFE_LISTEN(listen_fd, 1);
 
-	for (i = 0; i < DATA_SIZE; i++)
+	for (unsigned int i = 0; i < DATA_SIZE; i++)
 		original[i] = (uint8_t)(i & 0xff);
 
 	memset(&pedit_sel_buf, 0, sizeof(pedit_sel_buf));
@@ -253,7 +278,12 @@ static struct tst_test test = {
 	.test_all = run,
 	.setup = setup,
 	.cleanup = cleanup,
+	.needs_root = 1,
 	.needs_tmpdir = 1,
+	.needs_cmds = (struct tst_cmd[]) {
+		{.cmd = "modprobe"},
+		{}
+	},
 	.needs_kconfigs = (const char *[]) {
 		"CONFIG_USER_NS=y",
 		"CONFIG_NET_NS=y",

-- 
2.51.0



More information about the ltp mailing list