Seccomp

On this page 7

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.

ActionEffect on the processTypical use
SECCOMP_RET_KILL_PROCESSWhole process is killed with SIGSYSHard enforcement
SECCOMP_RET_KILL_THREADOnly the calling thread is killedLegacy default kill
SECCOMP_RET_TRAPSIGSYS delivered to a handlerEmulating or reporting calls in-process
SECCOMP_RET_ERRNOCall fails with a chosen error codeGraceful denial, often EPERM
SECCOMP_RET_USER_NOTIFSupervisor process decidesContainer managers emulating calls
SECCOMP_RET_TRACEAttached ptrace tracer is notifiedDebugging and sandbox research
SECCOMP_RET_LOGCall allowed and loggedBuilding and auditing profiles
SECCOMP_RET_ALLOWCall proceeds normallyPermitted operations
Seccomp return actions

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.

MechanismWhat it restrictsGranularity
SeccompSystem calls and their raw argumentsPer process, self-imposed
Linux capabilitiesPrivileged operations normally reserved for rootPer thread capability sets
AppArmorFiles, network and capabilities by pathPer program profile
SELinuxAll objects by security labelSystem-wide policy
NamespacesWhat resources a process can seePer process group
Seccomp compared with related controls

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.

InterfaceWhere it is usedExample
libseccompApplication code in C, Go or Pythonseccomp_rule_add() calls
systemd SystemCallFilter=ServicesSystemCallFilter=@system-service
Container runtime profileDocker, Podman, containerdJSON profile with an allowlist
Kubernetes seccompProfilePods and containerstype: RuntimeDefault
Ways to apply seccomp in practice

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 openat2 or clone3, and break a strict allowlist.
  • Overly broad allowlists: permitting ptrace, bpf or mount removes 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.