google / google/gvisor

seccomp: SECCOMP_RET_KILL_PROCESS evaluates to SECCOMP_RET_KILL_THREAD due to action bitmask issue

Open
#13,819 1 comment 0 reactions 0 assignees View on GitHub
type: bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.