seccomp vs Landlock

seccomp and Landlock are both Linux sandboxing mechanisms designed to enforce unprivileged process isolation, but they operate at different abstraction layers and target distinct resource types.

  • seccomp (SECure COMPuting mode) filters system calls based on ABI syscall numbers and raw argument values before the kernel executes them.
  • Landlock is an LSM (Linux Security Module) that restricts access to kernel objects (such as filesystem paths, IPC mechanisms, and network ports) dynamically using file descriptors and object-level permissions.

Key difference

seccomp: "Can I execute this system call?"

  • What it sees: The syscall number (e.g., SYS_openat, SYS_connect) and scalar register arguments (integers, flags, pointers as raw memory addresses).
  • What it decides: Whether the CPU is allowed to transition into that kernel entry point at all.
  • The limitation: It cannot safely inspect what pointers point to (due to TOCTOU memory race conditions). It knows you called openat(), but it doesn't know which file you are opening.

Landlock: "Can I access this kernel object?"

  • What it sees: Resolved kernel structures (inodes, path hierarchies, socket endpoints) passed via file descriptors during rule setup.
  • What it decides: Whether the process has rights to perform a specific action (e.g., READ_FILE, MAKE_DIR, NET_BIND_TCP) on a target object.
  • Scope:
    • Filesystem: Uses directory/file descriptors as topological "anchors" to grant or restrict access to entire directory subtrees (LANDLOCK_RULE_PATH_BENEATH).
    • Networking (added in Linux 6.7+): Restricts TCP socket binding and connecting to specific port ranges (LANDLOCK_RULE_NET_PORT).

In Short

Process Call:  openat(AT_FDCWD, "/etc/shadow", O_RDONLY)
               │
               ▼
[ seccomp ]   ➜ "Are openat() syscalls allowed?"
               │  YES
               ▼
[ Kernel ]     ➜ Resolves path string "/etc/shadow" to kernel inode/path object
               │
               ▼
[ Landlock ]  ➜ "Is reading this path hierarchy permitted for this thread?"
               │  NO -> EACCES
               ▼
               Execute file open

In summary:

  • seccomp protects the kernel entry points (reducing kernel exploit attack surface).
  • Landlock protects the system resources/objects (enforcing file and network access rules).

Core Architectural Comparison

Feature seccomp-BPF Landlock LSM
Layer / Enforcement Point Syscall entry boundary (prctl / cBPF filter) LSM hooks inside subsystem logic
Primary Target System call numbers & scalar arguments Kernel objects (Paths, Sockets, IPC)
Path Awareness No (Cannot dereference pointers safely in cBPF) Yes (Restrict access by file descriptors / path hierarchy)
Privileges Required NO_NEW_PRIVS or CAP_SYS_ADMIN Unprivileged (requires NO_NEW_PRIVS to self-sandbox)
Network Control Course-grained (allow/block socket, connect, bind) Fine-grained TCP port binding and connection rules
Filter Evaluation Evaluated on every syscall made by the thread Evaluated at LSM hook execution points
Kernel Version Mainline since Linux 3.5 Mainline since Linux 5.13

Architectural Differences

Why seccomp struggles with Filesystem and Object Control

seccomp-BPF operates at the system call boundary before arguments are dereferenced. Because user-space memory pointers (like string paths passed to openat(2)) can suffer from Time-of-Check to Time-of-Use (TOCTOU) race conditions, seccomp filters cannot safely inspect path strings or dereference pointers.

For instance, seccomp can block the openat syscall entirely, but it cannot restrict a process to *only read from /usr/share while blocking /etc*.

How Landlock Solves Path and Object Restrictions

Landlock works at the LSM level inside the kernel where data structures (like struct path or file descriptors) are already resolved.

Instead of filtering system call numbers, Landlock creates explicit access-rights rules tied to file descriptors opened by the application prior to dropping privileges:

// Example concept: Restricting filesystem access via Landlock
int ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);

// Grant read-only access to /usr and /lib
int path_fd = open("/usr", O_PATH | O_CLOEXEC);
struct landlock_path_beneath_attr path_attr = {
    .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR,
    .parent_fd = path_fd,
};
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_attr, 0);

// Restrict current thread and future children
landlock_restrict_self(ruleset_fd, 0);

How They Complement Each Other

Rather than competing, seccomp and Landlock are typically layered together to create robust Defense-in-Depth for modern application sandboxing (e.g., systemd service isolation, container runtimes, web browsers, and CLI utilities):

  1. seccomp reduces kernel attack surface by blocking unused or dangerous system calls (e.g., disabling kexec_load, ptrace, unshare, or obsolete 32-bit entry points).
  2. Landlock enforces fine-grained access control on allowed calls (e.g., allowing openat via seccomp, but using Landlock to ensure it can only access specific directory trees or bind to designated local network ports).
Loading...