All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] seccomp: Allow using SECCOMP_MODE_STRICT with SECCOMP_MODE_FILTER
@ 2026-06-15 16:20 Jamie Hill-Daniel
  2026-06-15 16:20 ` [PATCH v2 1/3] seccomp: Store death as a separate field Jamie Hill-Daniel
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Jamie Hill-Daniel @ 2026-06-15 16:20 UTC (permalink / raw)
  To: Kees Cook, Andy Lutomirski, Will Drewry
  Cc: linux-kernel, bpf, will, Jamie Hill-Daniel

This patch adjusts the logic used by seccomp to allow applying both
SECCOMP_MODE_FILTER and SECCOMP_MODE_STRICT to the same process.

Currently, once seccomp has been initialized, a process may not
transition to a different mode (only add additional filters).
This means that in container environments such as Docker, which by
default runs with SECCOMP_MODE_FILTER, processes may not enable
SECCOMP_MODE_STRICT. This is an obstacle to using applications
requiring SECCOMP_MODE_STRICT in these environments, and requires
disabling these security measures.

This series adds a new 'strict upgrade' flag, which runs strict checks
after the filters.

Link: https://github.com/moby/moby/issues/42082

Signed-off-by: Jamie Hill-Daniel <jamie@hill-daniel.co.uk>
Reviewed-by: William Liu <will@willsroot.io>
---
Jamie Hill-Daniel (3):
      seccomp: Store death as a separate field
      seccomp: Allow upgrading to strict mode after enabling filters
      selftest: seccomp: Adjust tests for using both STRICT and FILTER

 include/linux/seccomp_types.h                 |  7 ++-
 kernel/seccomp.c                              | 74 ++++++++++++---------------
 tools/testing/selftests/seccomp/seccomp_bpf.c | 68 +++++++++++-------------
 3 files changed, 68 insertions(+), 81 deletions(-)
---
base-commit: b9f0372b25cf3c41bf8eda02e65733afa5e8ad7c
change-id: 20260302-seccomp-combined-24bc3dbe32fd

Best regards,
--  
Jamie Hill-Daniel <jamie@hill-daniel.co.uk>


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

* [PATCH v2 1/3] seccomp: Store death as a separate field
  2026-06-15 16:20 [PATCH v2 0/3] seccomp: Allow using SECCOMP_MODE_STRICT with SECCOMP_MODE_FILTER Jamie Hill-Daniel
@ 2026-06-15 16:20 ` Jamie Hill-Daniel
  2026-06-15 16:34   ` sashiko-bot
  2026-06-15 16:20 ` [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters Jamie Hill-Daniel
  2026-06-15 16:20 ` [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER Jamie Hill-Daniel
  2 siblings, 1 reply; 7+ messages in thread
From: Jamie Hill-Daniel @ 2026-06-15 16:20 UTC (permalink / raw)
  To: Kees Cook, Andy Lutomirski, Will Drewry
  Cc: linux-kernel, bpf, will, Jamie Hill-Daniel

Remove SECCOMP_MODE_DEAD and store this instead in a new field
in struct seccomp. This means that mode can be used to strictly store
the current mode which is exposed to userspace.
---
 include/linux/seccomp_types.h |  4 +++-
 kernel/seccomp.c              | 19 +++++++++----------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/include/linux/seccomp_types.h b/include/linux/seccomp_types.h
index cf0a0355024f..67ab25d7540a 100644
--- a/include/linux/seccomp_types.h
+++ b/include/linux/seccomp_types.h
@@ -12,6 +12,7 @@ struct seccomp_filter;
  *
  * @mode:  indicates one of the valid values above for controlled
  *         system calls available to a process.
+ * @dead:  indicates that the process should be killed as a result of seccomp
  * @filter_count: number of seccomp filters
  * @filter: must always point to a valid seccomp-filter or NULL as it is
  *          accessed without locking during system call entry.
@@ -20,7 +21,8 @@ struct seccomp_filter;
  *          is no read locking.
  */
 struct seccomp {
-	int mode;
+	unsigned int mode : 2;
+	unsigned int dead : 1;
 	atomic_t filter_count;
 	struct seccomp_filter *filter;
 };
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 25f62867a16d..8f5903f72d54 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -31,9 +31,6 @@
 
 #include <asm/syscall.h>
 
-/* Not exposed in headers: strictly internal use only. */
-#define SECCOMP_MODE_DEAD	(SECCOMP_MODE_FILTER + 1)
-
 #ifdef CONFIG_SECCOMP_FILTER
 #include <linux/file.h>
 #include <linux/filter.h>
@@ -1079,7 +1076,7 @@ static void __secure_computing_strict(int this_syscall)
 #ifdef SECCOMP_DEBUG
 	dump_stack();
 #endif
-	current->seccomp.mode = SECCOMP_MODE_DEAD;
+	current->seccomp.dead = 1;
 	seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
 	do_exit(SIGKILL);
 }
@@ -1355,7 +1352,7 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 	case SECCOMP_RET_KILL_THREAD:
 	case SECCOMP_RET_KILL_PROCESS:
 	default:
-		current->seccomp.mode = SECCOMP_MODE_DEAD;
+		current->seccomp.dead = 1;
 		seccomp_log(this_syscall, SIGSYS, action, true);
 		/* Dump core only if this is the last remaining thread. */
 		if (action != SECCOMP_RET_KILL_THREAD ||
@@ -1396,17 +1393,19 @@ int __secure_computing(void)
 
 	this_syscall = syscall_get_nr(current, current_pt_regs());
 
+	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
+	if (unlikely(current->seccomp.dead)) {
+		WARN_ON_ONCE(1);
+		do_exit(SIGKILL);
+		return -1;
+	}
+
 	switch (mode) {
 	case SECCOMP_MODE_STRICT:
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
 		return 0;
 	case SECCOMP_MODE_FILTER:
 		return __seccomp_filter(this_syscall, false);
-	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
-	case SECCOMP_MODE_DEAD:
-		WARN_ON_ONCE(1);
-		do_exit(SIGKILL);
-		return -1;
 	default:
 		BUG();
 	}

-- 
2.54.0


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

* [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters
  2026-06-15 16:20 [PATCH v2 0/3] seccomp: Allow using SECCOMP_MODE_STRICT with SECCOMP_MODE_FILTER Jamie Hill-Daniel
  2026-06-15 16:20 ` [PATCH v2 1/3] seccomp: Store death as a separate field Jamie Hill-Daniel
@ 2026-06-15 16:20 ` Jamie Hill-Daniel
  2026-06-15 16:35   ` sashiko-bot
  2026-06-15 16:20 ` [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER Jamie Hill-Daniel
  2 siblings, 1 reply; 7+ messages in thread
From: Jamie Hill-Daniel @ 2026-06-15 16:20 UTC (permalink / raw)
  To: Kees Cook, Andy Lutomirski, Will Drewry
  Cc: linux-kernel, bpf, will, Jamie Hill-Daniel

Add a strict_upgrade flag to seccomp, which is enabled when
SECCOMP_MODE_STRICT is set after filters have been installed. This
will run the strict mode checks after all filters have been run.

This flag blocks thread syncing, in keeping with regular
SECCOMP_MODE_STRICT.
---
 include/linux/seccomp_types.h |  3 +++
 kernel/seccomp.c              | 55 +++++++++++++++++++------------------------
 2 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/include/linux/seccomp_types.h b/include/linux/seccomp_types.h
index 67ab25d7540a..d8a908cc822d 100644
--- a/include/linux/seccomp_types.h
+++ b/include/linux/seccomp_types.h
@@ -13,6 +13,8 @@ struct seccomp_filter;
  * @mode:  indicates one of the valid values above for controlled
  *         system calls available to a process.
  * @dead:  indicates that the process should be killed as a result of seccomp
+ * @strict_upgrade: indicates that strict mode has been enabled after filter
+ *          mode has been enabled.
  * @filter_count: number of seccomp filters
  * @filter: must always point to a valid seccomp-filter or NULL as it is
  *          accessed without locking during system call entry.
@@ -23,6 +25,7 @@ struct seccomp_filter;
 struct seccomp {
 	unsigned int mode : 2;
 	unsigned int dead : 1;
+	unsigned int strict_upgrade : 1;
 	atomic_t filter_count;
 	struct seccomp_filter *filter;
 };
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 8f5903f72d54..92804d488114 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -13,6 +13,7 @@
  * Mode 2 allows user-defined system call filters in the form
  *        of Berkeley Packet Filters/Linux Socket Filters.
  */
+#include "linux/seccomp.h"
 #define pr_fmt(fmt) "seccomp: " fmt
 
 #include <linux/refcount.h>
@@ -429,16 +430,6 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
 }
 #endif /* CONFIG_SECCOMP_FILTER */
 
-static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
-{
-	assert_spin_locked(&current->sighand->siglock);
-
-	if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
-		return false;
-
-	return true;
-}
-
 void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { }
 
 static inline void seccomp_assign_mode(struct task_struct *task,
@@ -504,7 +495,8 @@ static inline pid_t seccomp_can_sync_threads(void)
 		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED ||
 		    (thread->seccomp.mode == SECCOMP_MODE_FILTER &&
 		     is_ancestor(thread->seccomp.filter,
-				 caller->seccomp.filter)))
+				 caller->seccomp.filter) &&
+		     !thread->seccomp.strict_upgrade))
 			continue;
 
 		/* Return the first thread that cannot be synchronized. */
@@ -1259,6 +1251,7 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 	struct seccomp_data sd;
 	struct seccomp_filter *match = NULL;
 	int data;
+	int recheck_result;
 
 	/*
 	 * Make sure that any changes to mode from another thread have
@@ -1326,7 +1319,10 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 * a reload of all registers. This does not goto skip since
 		 * a skip would have already been reported.
 		 */
-		if (__seccomp_filter(this_syscall, true))
+		recheck_result = __seccomp_filter(this_syscall, true);
+		if (current->seccomp.strict_upgrade)
+			__secure_computing_strict(this_syscall);
+		if (recheck_result)
 			return -1;
 
 		return 0;
@@ -1386,6 +1382,7 @@ int __secure_computing(void)
 {
 	int mode = current->seccomp.mode;
 	int this_syscall;
+	int filter_ret;
 
 	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
 	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
@@ -1405,7 +1402,10 @@ int __secure_computing(void)
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
 		return 0;
 	case SECCOMP_MODE_FILTER:
-		return __seccomp_filter(this_syscall, false);
+		filter_ret = __seccomp_filter(this_syscall, false);
+		if (current->seccomp.strict_upgrade)
+			__secure_computing_strict(this_syscall);
+		return filter_ret;
 	default:
 		BUG();
 	}
@@ -1420,30 +1420,23 @@ long prctl_get_seccomp(void)
 /**
  * seccomp_set_mode_strict: internal function for setting strict seccomp
  *
- * Once current->seccomp.mode is non-zero, it may not be changed.
- *
- * Returns 0 on success or -EINVAL on failure.
+ * If current->seccomp.mode is SECCOMP_MODE_FILTER, this will enable
+ * strict_upgrade.
  */
-static long seccomp_set_mode_strict(void)
+static void seccomp_set_mode_strict(void)
 {
 	const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
-	long ret = -EINVAL;
-
 	spin_lock_irq(&current->sighand->siglock);
 
-	if (!seccomp_may_assign_mode(seccomp_mode))
-		goto out;
-
 #ifdef TIF_NOTSC
 	disable_TSC();
 #endif
-	seccomp_assign_mode(current, seccomp_mode, 0);
-	ret = 0;
+	if (current->seccomp.mode == SECCOMP_MODE_FILTER)
+		current->seccomp.strict_upgrade = 1;
+	else
+		seccomp_assign_mode(current, seccomp_mode, 0);
 
-out:
 	spin_unlock_irq(&current->sighand->siglock);
-
-	return ret;
 }
 
 #ifdef CONFIG_SECCOMP_FILTER
@@ -1948,8 +1941,6 @@ static bool has_duplicate_listener(struct seccomp_filter *new_child)
  * Every filter successfully installed will be evaluated (in reverse order)
  * for each system call the task makes.
  *
- * Once current->seccomp.mode is non-zero, it may not be changed.
- *
  * Returns 0 on success or -EINVAL on failure.
  */
 static long seccomp_set_mode_filter(unsigned int flags,
@@ -2015,7 +2006,8 @@ static long seccomp_set_mode_filter(unsigned int flags,
 
 	spin_lock_irq(&current->sighand->siglock);
 
-	if (!seccomp_may_assign_mode(seccomp_mode))
+	/* Reachable if PTRACE_O_SUSPEND_SECCOMP has been used */
+	if (current->seccomp.mode == SECCOMP_MODE_STRICT)
 		goto out;
 
 	if (has_duplicate_listener(prepared)) {
@@ -2104,7 +2096,8 @@ static long do_seccomp(unsigned int op, unsigned int flags,
 	case SECCOMP_SET_MODE_STRICT:
 		if (flags != 0 || uargs != NULL)
 			return -EINVAL;
-		return seccomp_set_mode_strict();
+		seccomp_set_mode_strict();
+		return 0;
 	case SECCOMP_SET_MODE_FILTER:
 		return seccomp_set_mode_filter(flags, uargs);
 	case SECCOMP_GET_ACTION_AVAIL:

-- 
2.54.0


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

* [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER
  2026-06-15 16:20 [PATCH v2 0/3] seccomp: Allow using SECCOMP_MODE_STRICT with SECCOMP_MODE_FILTER Jamie Hill-Daniel
  2026-06-15 16:20 ` [PATCH v2 1/3] seccomp: Store death as a separate field Jamie Hill-Daniel
  2026-06-15 16:20 ` [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters Jamie Hill-Daniel
@ 2026-06-15 16:20 ` Jamie Hill-Daniel
  2026-06-15 16:32   ` sashiko-bot
  2 siblings, 1 reply; 7+ messages in thread
From: Jamie Hill-Daniel @ 2026-06-15 16:20 UTC (permalink / raw)
  To: Kees Cook, Andy Lutomirski, Will Drewry
  Cc: linux-kernel, bpf, will, Jamie Hill-Daniel

Update tests to reflect that applying STRICT after FILTER is now possible.

Signed-off-by: Jamie Hill-Daniel <jamie@hill-daniel.co.uk>
---
 tools/testing/selftests/seccomp/seccomp_bpf.c | 68 ++++++++++++---------------
 1 file changed, 29 insertions(+), 39 deletions(-)

diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 874f17763536..f3b5e19b53a1 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -516,7 +516,7 @@ TEST(filter_chain_limits)
 	}
 }
 
-TEST(mode_filter_cannot_move_to_strict)
+TEST(mode_strict_upgrade)
 {
 	struct sock_filter filter[] = {
 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
@@ -534,8 +534,34 @@ TEST(mode_filter_cannot_move_to_strict)
 	ASSERT_EQ(0, ret);
 
 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
-	EXPECT_EQ(-1, ret);
-	EXPECT_EQ(EINVAL, errno);
+	ASSERT_EQ(0, ret);
+	syscall(__NR_exit, 0);
+}
+
+TEST_SIGNAL(mode_strict_upgrade_violation, SIGKILL)
+{
+	struct sock_filter filter[] = {
+		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+	};
+	struct sock_fprog prog = {
+		.len = (unsigned short)ARRAY_SIZE(filter),
+		.filter = filter,
+	};
+	long ret;
+
+	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+	ASSERT_EQ(0, ret);
+
+	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
+	ASSERT_EQ(0, ret);
+
+	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
+	ASSERT_EQ(0, ret);
+
+	syscall(__NR_getpid);
+	EXPECT_FALSE(true) {
+		TH_LOG("Unreachable!");
+	}
 }
 
 
@@ -2370,42 +2396,6 @@ TEST(seccomp_syscall)
 	}
 }
 
-TEST(seccomp_syscall_mode_lock)
-{
-	struct sock_filter filter[] = {
-		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
-	};
-	struct sock_fprog prog = {
-		.len = (unsigned short)ARRAY_SIZE(filter),
-		.filter = filter,
-	};
-	long ret;
-
-	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
-	ASSERT_EQ(0, ret) {
-		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
-	}
-
-	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
-	ASSERT_NE(ENOSYS, errno) {
-		TH_LOG("Kernel does not support seccomp syscall!");
-	}
-	EXPECT_EQ(0, ret) {
-		TH_LOG("Could not install filter!");
-	}
-
-	/* Make sure neither entry point will switch to strict. */
-	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0);
-	EXPECT_EQ(EINVAL, errno) {
-		TH_LOG("Switched to mode strict!");
-	}
-
-	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL);
-	EXPECT_EQ(EINVAL, errno) {
-		TH_LOG("Switched to mode strict!");
-	}
-}
-
 /*
  * Test detection of known and unknown filter flags. Userspace needs to be able
  * to check if a filter flag is supported by the current kernel and a good way

-- 
2.54.0


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

* Re: [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER
  2026-06-15 16:20 ` [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER Jamie Hill-Daniel
@ 2026-06-15 16:32   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-15 16:32 UTC (permalink / raw)
  To: Jamie Hill-Daniel; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The `mode_strict_upgrade_violation` test has a logic flaw that causes it to incorrectly pass even if the kernel mistakenly allows the forbidden syscall.
- [Medium] The patch drops test coverage for upgrading to strict mode via the `seccomp()` syscall.
--

commit 8c0b993065641d6398baa9878008c2ec51b13bef
Author: Jamie Hill-Daniel <clubby789@gmail.com>

selftest: seccomp: Adjust tests for using both STRICT and FILTER

Update tests to reflect that applying STRICT after FILTER is now possible.

> diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
> index 358b6c65e120e..17232591be590 100644
> --- a/tools/testing/selftests/seccomp/seccomp_bpf.c
> +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c

[ ... ]

> @@ -540,8 +540,34 @@ TEST(mode_filter_cannot_move_to_strict)
>  	ASSERT_EQ(0, ret);
>  
>  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
> -	EXPECT_EQ(-1, ret);
> -	EXPECT_EQ(EINVAL, errno);
> +	ASSERT_EQ(0, ret);
> +	syscall(__NR_exit, 0);
> +}
> +
> +TEST_SIGNAL(mode_strict_upgrade_violation, SIGKILL)
> +{
> +	struct sock_filter filter[] = {
> +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
> +	};
> +	struct sock_fprog prog = {
> +		.len = (unsigned short)ARRAY_SIZE(filter),
> +		.filter = filter,
> +	};
> +	long ret;
> +
> +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
> +	ASSERT_EQ(0, ret);
> +
> +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
> +	ASSERT_EQ(0, ret);
> +
> +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
> +	ASSERT_EQ(0, ret);
> +
> +	syscall(__NR_getpid);
> +	EXPECT_FALSE(true) {
> +		TH_LOG("Unreachable!");
> +	}
>  }

[Severity: Medium]
If the kernel mistakenly allows __NR_getpid, will the implicit return from this
test function mask the failure?

Returning from a kselftest function invokes the harness wrapper which calls
the standard library's _exit(), invoking the __NR_exit_group syscall. Because
__NR_exit_group is also forbidden in strict seccomp mode (only __NR_exit is
allowed), the kernel kills the test process with SIGKILL.

Since the parent harness expects a SIGKILL (due to the TEST_SIGNAL macro), it
matches the expected signal and overrides the test state to PASSED, hiding the
EXPECT_FALSE failure.

Should we explicitly call syscall(__NR_exit, 1); after the assertion fails to
ensure the test exits normally and the harness correctly fails it?

[ ... ]

> @@ -2376,42 +2402,6 @@ TEST(seccomp_syscall)
>  	}
>  }
>  
> -TEST(seccomp_syscall_mode_lock)
> -{
> -	struct sock_filter filter[] = {
> -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
> -	};
> -	struct sock_fprog prog = {
> -		.len = (unsigned short)ARRAY_SIZE(filter),
> -		.filter = filter,
> -	};
> -	long ret;
> -
> -	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
> -	ASSERT_EQ(0, ret) {
> -		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
> -	}
> -
> -	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
> -	ASSERT_NE(ENOSYS, errno) {
> -		TH_LOG("Kernel does not support seccomp syscall!");
> -	}
> -	EXPECT_EQ(0, ret) {
> -		TH_LOG("Could not install filter!");
> -	}
> -
> -	/* Make sure neither entry point will switch to strict. */
> -	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0);
> -	EXPECT_EQ(EINVAL, errno) {
> -		TH_LOG("Switched to mode strict!");
> -	}
> -
> -	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL);
> -	EXPECT_EQ(EINVAL, errno) {
> -		TH_LOG("Switched to mode strict!");
> -	}
> -}

[Severity: Medium]
Does dropping this test also drop test coverage for upgrading to strict mode
via the seccomp() syscall?

The new replacement tests (mode_strict_upgrade and
mode_strict_upgrade_violation) only validate the prctl() interface, leaving the
seccomp() syscall path untested for the newly allowed transition from
SECCOMP_MODE_FILTER to SECCOMP_MODE_STRICT.

Could we add tests to ensure the seccomp() syscall correctly enforces this ABI?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-seccomp-combined-v2-0-41687a943ae0@hill-daniel.co.uk?part=3

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

* Re: [PATCH v2 1/3] seccomp: Store death as a separate field
  2026-06-15 16:20 ` [PATCH v2 1/3] seccomp: Store death as a separate field Jamie Hill-Daniel
@ 2026-06-15 16:34   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-15 16:34 UTC (permalink / raw)
  To: Jamie Hill-Daniel; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The newly added defense `if (unlikely(current->seccomp.dead))` was omitted from the non-BPF fallback implementation of `secure_computing_strict()`.
--

commit 17b53379696e6ea38281041129401658643c996d
Author: Jamie Hill-Daniel <clubby789@gmail.com>

seccomp: Store death as a separate field

This patch removes SECCOMP_MODE_DEAD and stores the death state in a new
bitfield within struct seccomp. This allows the mode field to strictly store
the current seccomp mode while exposing it to userspace.

> diff --git a/kernel/seccomp.c b/kernel/seccomp.c
> index 066909393c38f..2d21cb6bbd94d 100644
> --- a/kernel/seccomp.c
> +++ b/kernel/seccomp.c

[ ... ]

> @@ -1396,17 +1393,19 @@ int __secure_computing(void)
>  
>  	this_syscall = syscall_get_nr(current, current_pt_regs());
>  
> +	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
> +	if (unlikely(current->seccomp.dead)) {
> +		WARN_ON_ONCE(1);
> +		do_exit(SIGKILL);
> +		return -1;
> +	}
> +

[Severity: High]
Is it possible we need this same check in the non-BPF fallback version of
secure_computing_strict()?

When CONFIG_HAVE_ARCH_SECCOMP_FILTER is disabled, secure_computing_strict()
evaluates current->seccomp.mode. Previously, if a killed process miraculously
survived do_exit() and issued another syscall, the mode would be
SECCOMP_MODE_DEAD and trigger a BUG() instead of executing
__secure_computing_strict():

kernel/seccomp.c:secure_computing_strict() {
    ...
    if (mode == SECCOMP_MODE_DISABLED)
        return;
    else if (mode == SECCOMP_MODE_STRICT)
        __secure_computing_strict(this_syscall);
    else
        BUG();
}

With the new dead bitfield, if the process survives and issues a valid
strict-mode syscall (e.g. exit), the mode remains SECCOMP_MODE_STRICT.
It appears we'll simply execute __secure_computing_strict() again and
return successfully without killing the process, neutralizing the fail-safe.

>  	switch (mode) {
>  	case SECCOMP_MODE_STRICT:
>  		__secure_computing_strict(this_syscall);  /* may call do_exit */
>  		return 0;
>  	case SECCOMP_MODE_FILTER:
>  		return __seccomp_filter(this_syscall, false);
> -	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
> -	case SECCOMP_MODE_DEAD:
> -		WARN_ON_ONCE(1);
> -		do_exit(SIGKILL);
> -		return -1;
>  	default:
>  		BUG();
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-seccomp-combined-v2-0-41687a943ae0@hill-daniel.co.uk?part=1

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

* Re: [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters
  2026-06-15 16:20 ` [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters Jamie Hill-Daniel
@ 2026-06-15 16:35   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-15 16:35 UTC (permalink / raw)
  To: Jamie Hill-Daniel; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Stale syscall number is evaluated in the strict mode check after a ptracer modifies the syscall, potentially causing false positive kills.
- [High] Upgrading to strict mode from filter mode skips arch_seccomp_spec_mitigate, potentially leaving strict processes vulnerable to speculative execution flaws.
- [Medium] Missing `strict_upgrade` check in `seccomp_set_mode_filter` allows bypassed filter installation and TSYNC when seccomp is suspended.
--

commit 586f767ffd81c4f0c9b3df714ec047c0eabb4c30
Author: Jamie Hill-Daniel <clubby789@gmail.com>

seccomp: Allow upgrading to strict mode after enabling filters

Add a strict_upgrade flag to seccomp, which is enabled when
SECCOMP_MODE_STRICT is set after filters have been installed. This
will run the strict mode checks after all filters have been run.

This flag blocks thread syncing, in keeping with regular
SECCOMP_MODE_STRICT.

[ ... ]

> diff --git a/kernel/seccomp.c b/kernel/seccomp.c
> index 2d21cb6bbd94d..57ca0c49ec062 100644
> --- a/kernel/seccomp.c
> +++ b/kernel/seccomp.c

[ ... ]

> @@ -1405,7 +1402,10 @@ int __secure_computing(void)
>  		__secure_computing_strict(this_syscall);  /* may call do_exit */
>  		return 0;
>  	case SECCOMP_MODE_FILTER:
> -		return __seccomp_filter(this_syscall, false);
> +		filter_ret = __seccomp_filter(this_syscall, false);
> +		if (current->seccomp.strict_upgrade)
> +			__secure_computing_strict(this_syscall);
> +		return filter_ret;

[Severity: High]
If a filter returns SECCOMP_RET_TRACE, a ptracer can change the syscall number.
While __seccomp_filter() correctly handles this by fetching the new syscall and
evaluating it against strict mode internally, this outer check in
__secure_computing() uses the original, unmodified this_syscall variable.

Does this redundant check use a stale this_syscall value, potentially killing
the process for a syscall that was already legitimately sanitized by the
ptracer?

>  	default:
>  		BUG();
>  	}

[ ... ]

> @@ -1420,30 +1420,23 @@ long prctl_get_seccomp(void)
>  /**
>   * seccomp_set_mode_strict: internal function for setting strict seccomp
>   *
> - * Once current->seccomp.mode is non-zero, it may not be changed.
> - *
> - * Returns 0 on success or -EINVAL on failure.
> + * If current->seccomp.mode is SECCOMP_MODE_FILTER, this will enable
> + * strict_upgrade.
>   */
> -static long seccomp_set_mode_strict(void)
> +static void seccomp_set_mode_strict(void)
>  {
>  	const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
> -	long ret = -EINVAL;
> -
>  	spin_lock_irq(&current->sighand->siglock);
>  
> -	if (!seccomp_may_assign_mode(seccomp_mode))
> -		goto out;
> -
>  #ifdef TIF_NOTSC
>  	disable_TSC();
>  #endif
> -	seccomp_assign_mode(current, seccomp_mode, 0);
> -	ret = 0;
> +	if (current->seccomp.mode == SECCOMP_MODE_FILTER)
> +		current->seccomp.strict_upgrade = 1;
> +	else
> +		seccomp_assign_mode(current, seccomp_mode, 0);

[Severity: High]
When a process enters filter mode using the SECCOMP_FILTER_FLAG_SPEC_ALLOW
flag, it opts out of speculative execution mitigations.

By skipping seccomp_assign_mode() when upgrading from filter mode, are we
failing to retroactively enforce these mitigations (like SSBD/STIBP) which are
normally enforced by strict mode?

> -out:
>  	spin_unlock_irq(&current->sighand->siglock);
> -
> -	return ret;
>  }

[ ... ]

> @@ -2015,7 +2006,8 @@ static long seccomp_set_mode_filter(unsigned int flags,
>  
>  	spin_lock_irq(&current->sighand->siglock);
>  
> -	if (!seccomp_may_assign_mode(seccomp_mode))
> +	/* Reachable if PTRACE_O_SUSPEND_SECCOMP has been used */
> +	if (current->seccomp.mode == SECCOMP_MODE_STRICT)
>  		goto out;

[Severity: Medium]
When a process uses strict_upgrade, its mode remains SECCOMP_MODE_FILTER.

Since this check only verifies SECCOMP_MODE_STRICT, does it allow a suspended
process with strict_upgrade set to successfully append new filters or use
SECCOMP_FILTER_FLAG_TSYNC, violating the immutability of strict mode?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-seccomp-combined-v2-0-41687a943ae0@hill-daniel.co.uk?part=2

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

end of thread, other threads:[~2026-06-15 16:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15 16:20 [PATCH v2 0/3] seccomp: Allow using SECCOMP_MODE_STRICT with SECCOMP_MODE_FILTER Jamie Hill-Daniel
2026-06-15 16:20 ` [PATCH v2 1/3] seccomp: Store death as a separate field Jamie Hill-Daniel
2026-06-15 16:34   ` sashiko-bot
2026-06-15 16:20 ` [PATCH v2 2/3] seccomp: Allow upgrading to strict mode after enabling filters Jamie Hill-Daniel
2026-06-15 16:35   ` sashiko-bot
2026-06-15 16:20 ` [PATCH v2 3/3] selftest: seccomp: Adjust tests for using both STRICT and FILTER Jamie Hill-Daniel
2026-06-15 16:32   ` sashiko-bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.