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 <rbranco@suse.de> (cherry picked from commit da72537164910f9050793055fef030711c00b954)
This commit is contained in:
committed by
Luca Boccassi
parent
f190b1a631
commit
63051fa2bf
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user