A seccomp policy can look complete while leaving an alternate syscall path open. The filter sees a syscall number and an architecture identifier, not a semantic function name. On a multi-architecture system, the same integer may mean different things under different ABIs. A policy that checks only nr can be bypassed by reaching the kernel through a path the filter did not model.

Architecture validation belongs at the start of the filter. The Linux seccomp(2) documentation shows filters loading seccomp_data.arch and comparing it with an expected value before evaluating syscall numbers. On x86-64, the commonly used example checks the system call number for the x32 bit and rejects it when the policy is intended only for x86-64.

The filter's view

Seccomp BPF programs receive a seccomp_data structure containing the system call number, architecture, instruction pointer, and syscall arguments. The arguments are values, not validated memory buffers. A filter cannot inspect the contents of a pathname or an object referenced by a pointer without other mechanisms.

That limitation matters when teams build an allowlist from a rule generator. The generator may faithfully list syscalls, but the profile can still be too broad if it allows a generic syscall that acquires authority and then performs a second operation. The filter also has to handle multiple ABIs, statically linked binaries, interpreters, and code that changes behavior after an upgrade.

Use a default action that matches the desired risk. SECCOMP_RET_KILL_PROCESS is a strong choice for a tightly scoped worker, while SECCOMP_RET_ERRNO can provide a controlled failure for a broader service. Logging actions can aid discovery, but an allowlist that silently logs everything and permits it is not an enforcement boundary.

Architecture before policy

A safe pattern is:

  1. 1.

    Load the architecture field.

  2. 2.

    Allow the exact architecture the service is expected to run.

  3. 3.

    Reject unknown architectures.

  4. 4.

    Check the syscall number within that architecture.

  5. 5.

    Apply the default action.

Do not assume that a successful test under one ABI proves the policy for another. A container image may contain binaries for more than one architecture, and a process can invoke code through an interpreter or compatibility mode. Where multi-architecture support is required, maintain a separate filter for each ABI and test each one.

The filter should also fail closed when it cannot classify an instruction. Empty branches and accidental fall-through return the default action, which may be permissive if the profile was assembled from a template. Review the generated BPF program and not just the human-readable policy file.

Arguments and time of check

Seccomp can compare scalar syscall arguments, but it cannot guarantee that a pointer points to the same content later in the call. A path checked in a filter and then opened by the kernel can change between the check and use unless the application also uses safe path resolution or another confinement layer.

That is why seccomp is usually paired with mount namespaces, file permissions, capabilities, and a supervisor that does not expose unnecessary descriptors. The filter narrows the syscall surface. It does not decide whether a file descriptor already held by the process is safe to use.

Testing and operations

Test the policy with both allowed and denied operations under the same runtime, cgroup, and user identity as production. Include:

  • a normal startup path;

  • each intended worker path;

  • an unknown architecture or unsupported syscall path where test infrastructure permits;

  • a denied syscall with the expected errno or process termination;

  • a restart under the deployed kernel.

Record the seccomp mode and the policy version with the service. When an application changes its runtime, native dependencies, or interpreter, rerun the tests. A profile that passed with an older Node.js, Python, or Java runtime may fail after an update, and a temporary permissive profile can become permanent if no owner removes it.

The boundary in context

Architecture-aware filters close an important gap. They do not make an untrusted program safe. A process that can write to another process's memory, abuse an already-open file descriptor, or exploit a permitted syscall still has authority. The value of seccomp is that it makes the permitted kernel-entry surface explicit and testable.

Start with the ABI, then the syscall, then the surrounding resource controls. A policy that does not know which architecture it is enforcing is not yet a security policy.

References