seccomp: SECCOMP_RET_KILL_PROCESS evaluates to SECCOMP_RET_KILL_THREAD due to action bitmask issue
- Dominant language
- Go
- Stars
- 19.3k
- Forks
- 2k
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 264
Description
### Description
It seems there is a bitmask misuse when extracting the seccomp action in [`checkSeccompSyscall`](https://github.com/google/gvisor/blob/3f1f8f20c8d376259749446d16766b457d9c982c/pkg/sentry/kernel/seccomp.go#L98).
Using `SECCOMP_RET_ACTION` (0x7fff0000) instead of `SECCOMP_RET_ACTION_FULL` (0xffff0000) truncates `SECCOMP_RET_KILL_PROCESS` (0x80000000) to `0x00000000` (`SECCOMP_RET_KILL_THREAD`), causing only the offending thread to be terminated rather than the entire thread group, which is not same act with Linux kernel.
### Steps to reproduce
Use the code below.
```c
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void install_seccomp_filter(void) {
struct sock_filter filter[] = {
// Intercept SYS_getpid and return SECCOMP_RET_KILL_PROCESS
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_getpid, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0 ||
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) {
perror("prctl setup failed");
exit(1);
}
}
static void *worker_thread(void *arg) {
(void)arg;
sleep(1);
// If we reach here, the thread survived after main thread was killed
printf("Worker thread survived (SECCOMP_RET_KILL_PROCESS behaved like KILL_THREAD)\n");
exit(42);
}
int main(void) {
pid_t pid = fork();
if (pid < 0) return 1;
if (pid == 0) {
pthread_t t;
install_seccomp_filter();
pthread_create(&t, NULL, worker_thread, NULL);
usleep(100000);
// Main thread triggers seccomp violation
syscall(SYS_getpid);
pthread_join(t, NULL);
_exit(0);
}
int status = 0;
waitpid(pid, &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) == 42) {
printf("Result: Process group was NOT killed.\n");
} else if (WIFSIGNALED(status)) {
printf("Result: Entire process group was terminated by signal.\n");
}
return 0;
}
```
Result(compiled using `gcc -static 1.c -o 1.out`):
```sh
sh-5.3$ share/1.out # Linux 7.1.2 Kernel
Result: Entire process group was terminated by signal.
sh-5.3$ sudo podman run -it --rm --runtime runsc -v ./share/:/share alpine
/ # share/1.out # gVisor Runtime
Worker thread survived (SECCOMP_RET_KILL_PROCESS behaved like KILL_THREAD)
Result: Process group was NOT killed.
/ # exit
sh-5.3$ sudo podman run -it --rm --runtime crun -v ./share/:/share alpine
/ # share/1.out # crun Runtime
Result: Entire process group was terminated by signal.
/ # exit
sh-5.3$ podman run -it --rm --runtime crun -v ./share/:/share alpine
/ # share/1.out # podman rootless runtime
Result: Entire process group was terminated by signal.
/ # exit
```
### runsc version
```shell
runsc version release-20260406.0
spec: 1.1.0-rc.1
```
### docker version (if using docker)
```shell
```
(podman version)
```shell
Client: Podman Engine
Version: 6.0.1
API Version: 6.0.1
Go Version: go1.26.5-X:nodwarf5
Git Commit: 4cabbe61fa3a27fafc4a3ee1226e38ae1664ae57
Built: Sat Jul 11 02:21:31 2026
OS/Arch: linux/amd64
```
### uname
```shell
Linux localhost 7.1.4-zen1-1-zen #1 ZEN SMP PREEMPT_DYNAMIC Sat, 18 Jul 2026 17:30:44 +0000 x86_64 GNU/Linux
```
### kubectl (if using Kubernetes)
```shell
```
### repo state (if built from source)
_No response_
### runsc debug logs (if available)
```shell
```
Contributor guide
Research direction
Start in pkg/sentry/kernel/seccomp.go at checkSeccompSyscall and inspect how SECCOMP_RET_ACTION and SECCOMP_RET_ACTION_FULL are used. Reproduce the issue with the provided C program, then add regression coverage showing that SECCOMP_RET_KILL_PROCESS terminates the entire thread group as it does on Linux.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, go
- Domain
- operating-systems, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 66/100