$RodHat_
Syscall reference · Sandboxing

seccomp(2)

Set the thread's seccomp state: strict mode or a BPF filter on every syscall.

Since
Linux 3.17check your kernel →
glibc
none (use syscall(2))
System
Linux
Man page
seccomp(2)

Synopsis

#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
#include <sys/syscall.h>
#include <unistd.h>

int syscall(SYS_seccomp, unsigned int operation, unsigned int flags,
            void *args);

Rod's take

A typical daemon uses forty-odd syscalls and leaves a few hundred more loaded and pointed at whoever pops your input parser. seccomp is how you unload them. Set no_new_privs first or the load fails with EACCES and you're running naked while thinking you're armored, so check the return. Check arch before the syscall number or the 32-bit ABI walks right past you. The filter compares integers; it can't chase pointers, so paths are Landlock's problem. pledge does the coarse version in one line. This is the two-day precise version, and for untrusted code it earns it.

Flags and arguments that matter

NameWhat it does
SECCOMP_SET_MODE_STRICTAllow only read(2), write(2), _exit(2) and sigreturn(2); anything else kills the caller.
SECCOMP_SET_MODE_FILTERInstall a classic BPF program (struct sock_fprog) run on every syscall. Needs no_new_privs or CAP_SYS_ADMIN.
SECCOMP_FILTER_FLAG_TSYNCSynchronize all threads of the process to the new filter tree.
SECCOMP_FILTER_FLAG_LOGLinux 4.14Log all filter actions except SECCOMP_RET_ALLOW.
SECCOMP_FILTER_FLAG_NEW_LISTENERLinux 5.0Return a user-space notification fd for SECCOMP_RET_USER_NOTIF.
SECCOMP_GET_ACTION_AVAILLinux 4.14Test whether the kernel supports a given filter return action.
SECCOMP_RET_KILL_PROCESSLinux 4.14Filter action: kill the whole process with a core dump; the syscall is not executed.
SECCOMP_RET_ERRNOFilter action: skip the syscall and return the low 16 data bits as errno.
SECCOMP_RET_USER_NOTIFLinux 5.0Filter action: hand the decision to a user-space supervisor via the listener fd.
SECCOMP_RET_LOGLinux 4.14Filter action: allow the syscall but log it.

Errors you will actually hit

errnoMeaning
EACCESCaller lacks CAP_SYS_ADMIN and hasn't set no_new_privs before SECCOMP_SET_MODE_FILTER.
EINVALUnknown operation, invalid flags, or an invalid/empty/too-long (>4096 insns) filter.
EFAULTargs was not a valid address.
EBUSYNEW_LISTENER requested but a filter with a listener is already installed.
ENOMEMOut of memory, or total filter length on the thread exceeds 32768 instructions.

Example

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);

scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ERRNO(EPERM));
if (!ctx)
    errx(1, "seccomp_init");
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

if (seccomp_load(ctx) < 0)      /* libseccomp calls seccomp(2) */
    errx(1, "seccomp_load");
seccomp_release(ctx);

Trimmed from the full walkthrough in Your process doesn't need 400 syscalls. seccomp-BPF lets you say so..

BSD equivalent

OpenBSD: pledge(2) (OpenBSD 5.9), coarse promise strings rather than BPF. FreeBSD: Capsicum capability mode via cap_enter(2).

The long version, from the console

Sources

  1. seccomp(2), man7.org
  2. pledge(2), OpenBSD
  3. cap_enter(2), FreeBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.