How Linux Implements Seccomp to Restrict System Calls

This article provides an overview of how the Linux kernel implements Secure Computing Mode (seccomp) to restrict the system calls a process can execute. It covers the evolution from strict seccomp to flexible Berkeley Packet Filter (BPF) filtering, the internal kernel mechanics that intercept system calls, the execution of filter programs, and how process inheritance and privilege controls ensure that sandboxing policies cannot be bypassed.

The Two Modes of Seccomp

Linux provides two distinct operational modes for seccomp, configured primarily through the seccomp() system call or legacy prctl() operations:

  1. Strict Mode (SECCOMP_SET_MODE_STRICT): The original, hardcoded implementation introduced in Linux 2.6.12. In this mode, a process is restricted strictly to four system calls: read(), write(), _exit(), and sigreturn(). Attempting any other system call causes the kernel to immediately terminate the process with a SIGKILL signal.
  2. Filter Mode (SECCOMP_SET_MODE_FILTER): Introduced in Linux 3.5, this mode allows developers to define fine-grained, programmable allowlists and blocklists using classic Berkeley Packet Filter (cBPF) bytecode.

System Call Inspection with cBPF

Under filter mode, the kernel treats incoming system calls similarly to network packets. Before a system call executes, the kernel constructs a read-only metadata structure named struct seccomp_data and feeds it to the user-supplied BPF program:

struct seccomp_data {
    int nr;                    /* System call number */
    __u32 arch;                /* Architecture ABI (e.g., AUDIT_ARCH_X86_64) */
    __u64 instruction_pointer; /* CPU instruction pointer */
    __u64 args[6];             /* System call arguments */
};

The filter evaluates this data and returns a 32-bit status code that dictates the kernel's response:

Kernel Interception and Execution Flow

The enforcement of seccomp is integrated directly into the kernel's low-level system call entry path:

  1. Thread Flag Verification: When a process installs a seccomp filter, the kernel sets the _TIF_SECCOMP thread information flag in the task's thread_info structure.
  2. Entry Point Interception: Whenever the thread issues a software interrupt or executes a dedicated instruction (such as syscall on x86-64), the architecture-specific assembly entry handler checks for active thread flags.
  3. Filter Evaluation: If _TIF_SECCOMP is set, control diverts to __secure_computing(). This invokes seccomp_run_filters(), which steps through all installed BPF programs attached to the process's struct seccomp container.
  4. Action Resolution: If multiple filters exist, the kernel runs all of them in reverse chronological order and selects the return value with the highest precedence (the most restrictive action).
  5. Dispatch or Abort: If the resolved action is SECCOMP_RET_ALLOW, the kernel passes execution to the target system call handler. Otherwise, the kernel aborts execution, sets register return values, or raises signals as instructed.

Security Guarantees and Filter Inheritance

To prevent unprivileged processes from subverting restrictions, Linux enforces two critical behavioral models: