Seccomp (secure computing mode) is a Linux kernel facility that restricts the system calls a process may invoke. In Linux security, it reduces the kernel attack surface available to a program: once a filter is installed, any system call the filter does not allow is blocked, logged or answered with an error before the kernel executes it.
Seccomp is a building block rather than a complete policy system. Browsers, container runtimes, systemd services and network daemons use it to ensure that even a fully compromised process cannot reach rarely needed kernel interfaces, which are a common source of privilege escalation vulnerabilities.
How seccomp filters system calls
Seccomp has two modes. Strict mode, the original design, allows only read, write, _exit and sigreturn, which suits pure computation on already open file descriptors. Filter mode, usually called seccomp-bpf, lets a process attach a small classic BPF program that inspects every system call and returns a verdict.
The filter receives a `seccomp_data` structure containing the system call number, the CPU architecture, the instruction pointer and up to six raw argument values. It can compare these values but cannot dereference pointers, so it can check that a flag argument equals a constant but cannot inspect a file path passed as a string.
A process installs a filter with the `seccomp()` system call or the older prctl(PR_SET_SECCOMP) interface. Unprivileged processes must first set `no_new_privs`, which prevents them from gaining privileges through setuid binaries afterward. Filters are inherited by children and can never be removed, only stacked with further filters that are stricter.
Filter actions and their effects
Each filter returns an action for every system call. When several filters are stacked, the kernel evaluates all of them and applies the most restrictive action. The table lists the available actions in order of precedence.
| Action | Effect on the process | Typical use |
|---|---|---|
| SECCOMP_RET_KILL_PROCESS | Whole process is killed with SIGSYS | Hard enforcement |
| SECCOMP_RET_KILL_THREAD | Only the calling thread is killed | Legacy default kill |
| SECCOMP_RET_TRAP | SIGSYS delivered to a handler | Emulating or reporting calls in-process |
| SECCOMP_RET_ERRNO | Call fails with a chosen error code | Graceful denial, often EPERM |
| SECCOMP_RET_USER_NOTIF | Supervisor process decides | Container managers emulating calls |
| SECCOMP_RET_TRACE | Attached ptrace tracer is notified | Debugging and sandbox research |
| SECCOMP_RET_LOG | Call allowed and logged | Building and auditing profiles |
| SECCOMP_RET_ALLOW | Call proceeds normally | Permitted operations |
Returning an error such as EPERM is usually friendlier than killing the process, because well-written software can fall back to an alternative. Killing is preferable when an unexpected call is a strong sign of exploitation and continued execution is riskier than a crash.
Seccomp among Linux security mechanisms
Seccomp controls which kernel entry points a process can use, whereas mandatory access control systems decide which objects it may touch. The mechanisms in the Linux security topic are complementary and are typically layered together.
| Mechanism | What it restricts | Granularity |
|---|---|---|
| Seccomp | System calls and their raw arguments | Per process, self-imposed |
| Linux capabilities | Privileged operations normally reserved for root | Per thread capability sets |
| AppArmor | Files, network and capabilities by path | Per program profile |
| SELinux | All objects by security label | System-wide policy |
| Namespaces | What resources a process can see | Per process group |
Because seccomp cannot read path strings, it cannot replace AppArmor or SELinux for file access policy. Conversely, those systems do not prevent a process from calling an obscure kernel interface with a vulnerable code path, which is precisely the gap that seccomp closes.
Writing and deploying seccomp profiles
Few teams write raw BPF by hand. Profiles are usually expressed through higher-level interfaces that compile them into filters. The choice depends on where the workload runs.
| Interface | Where it is used | Example |
|---|---|---|
| libseccomp | Application code in C, Go or Python | seccomp_rule_add() calls |
| systemd SystemCallFilter= | Services | SystemCallFilter=@system-service |
| Container runtime profile | Docker, Podman, containerd | JSON profile with an allowlist |
| Kubernetes seccompProfile | Pods and containers | type: RuntimeDefault |
The safest design is an allowlist with a default deny, built by observing the program in log mode, reviewing the recorded calls and then switching to enforcement. Container runtimes ship a default profile that blocks several dozen dangerous calls, such as those for loading kernel modules or changing the system clock, while keeping ordinary software working.
Filters must also check the architecture field. On systems that run 32-bit and 64-bit code, system call numbers differ between ABIs, and a filter that ignores the architecture can be bypassed by switching to the other calling convention.
Limitations and common mistakes
Seccomp is powerful but narrow by design, and misunderstanding its limits leads to false confidence. The most common problems are listed below.
- Denylists that miss new calls: each kernel release can add system calls, so a denylist silently allows them.
- Pointer arguments: checks on pointer values are subject to time-of-check to time-of-use races and do not protect data.
- Library changes: a libc update may switch to a different system call, such as
openat2orclone3, and break a strict allowlist. - Overly broad allowlists: permitting
ptrace,bpformountremoves most of the benefit. - Forgetting threads: a filter installed after threads are created applies only to the calling thread unless the TSYNC flag is used.
The current state of a process is visible in the `Seccomp:` field of `/proc/PID/status`, where 0 means disabled, 1 strict mode and 2 filter mode, which is a quick way to verify that a sandbox is active.
In everyday language
Every program talks to the operating system by making requests, such as open this file or send this data. Seccomp gives a program a short list of requests it is allowed to make, and the operating system refuses everything else.
It works like a building badge that opens only the doors a worker actually needs. If an intruder steals the badge, they still cannot enter the server room, because the badge never opened that door in the first place.
Seen in the real world
A platform team runs a public service that converts uploaded documents into images, a classic target because file parsers often contain memory corruption bugs. The conversion worker runs as a systemd service inside a container, and the team wants an exploited parser to gain as little as possible.
The team first runs the worker for a week with SECCOMP_RET_LOG as the default action, collecting the system calls it really uses. They then deploy a profile that allows only those calls, returns EPERM for everything else and explicitly blocks ptrace, mount, bpf and unshare. Kubernetes applies it through a seccompProfile of type Localhost.
Months later, a vulnerable parser is exploited in testing. The attacker code runs but every attempt to reach kernel interfaces fails, so the exploit cannot escalate and the incident remains confined to a single short-lived worker.