From 63051fa2bfa7e736a9fd33fad0a4fc3808d401cb Mon Sep 17 00:00:00 2001 From: Ricardo Branco Date: Mon, 12 Oct 2026 00:35:01 +0200 Subject: [PATCH] seccomp: mask setns() nstype to 32 bits in RestrictNamespaces= The nstype argument of setns() is an int, but it is passed to the kernel in a 64-bit register, and the kernel truncates it to the low 32 bits. The rule that blocks setns() with nstype == 0 compared the full 64-bit register with SCMP_CMP_EQ, so setting any bit above bit 31 let the call through, and the kernel then joined whichever namespace the fd referred to, even one that RestrictNamespaces= is supposed to deny. Use SCMP_CMP_MASKED_EQ with a 32-bit mask so we match on the same value the kernel does. Add a test that issues setns() via syscall() with an upper bit set. Follow-up for #44134 Signed-off-by: Ricardo Branco (cherry picked from commit da72537164910f9050793055fef030711c00b954) --- src/shared/seccomp-util.c | 5 +++-- src/test/test-seccomp.c | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index d66cc97418..a32db7a7df 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -1429,13 +1429,14 @@ int seccomp_restrict_namespaces(unsigned long retain) { 0); else /* Otherwise, block only the invocations with the appropriate flags in the loop - * below, but also the special invocation with a zero flags argument, right here. */ + * below, but also the special invocation with a zero flags argument, right here. The + * kernel takes nstype as an int and truncates it to 32 bits, hence only compare those. */ r = sym_seccomp_rule_add_exact( seccomp, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(setns), 1, - SCMP_A1(SCMP_CMP_EQ, 0)); + SCMP_A1(SCMP_CMP_MASKED_EQ, UINT32_MAX, 0)); if (r < 0) { log_debug_errno(r, "Failed to add setns() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch)); diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 1446e71853..e991442220 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -327,6 +327,12 @@ TEST(restrict_namespace) { assert_se(setns(0, 0) == -1); assert_se(errno == EPERM); + /* The kernel truncates nstype to 32 bits, make sure setting upper bits doesn't bypass the filter */ + if (sizeof(long) == 8) { + assert_se(syscall(__NR_setns, 0, (unsigned long) (UINT64_C(1) << 32)) == -1); + assert_se(errno == EPERM); + } + pid_t pid = raw_clone(CLONE_NEWNS); assert_se(pid >= 0); if (pid == 0)