Linux Landlock Unprivileged Sandboxing Playbook
Date: 2026-04-10
Category: knowledge
Domain: software / linux security / sandboxing
Why this matters
A lot of Linux hardening tools are powerful, but awkward in different ways:
- SELinux/AppArmor can be strong, but policy authoring and rollout are not always lightweight.
- seccomp is excellent for syscall surface reduction, but it does not express path-level policy.
- eBPF / BPF LSM can be programmable and surgical, but they are still kernel-program operations.
Landlock matters because it offers a different shape of control:
- it is a stackable LSM,
- it lets a process restrict itself even when unprivileged,
- it focuses on ambient-rights reduction,
- and it is practical for app-level sandboxes that should survive contact with real deployments.
The useful mental model is not “Linux mandatory access control replacement.” It is closer to:
portable, app-driven least-privilege sandboxing for file/network access, layered on top of existing Linux security controls.
That makes it interesting for:
- CLI tools that should only touch a narrow set of files,
- plugin runners,
- document/media processors,
- CI tasks,
- developer tooling,
- user-space sandbox wrappers,
- and security-sensitive helper processes.
1) Quick mental model
Landlock is an allowlist over explicitly handled rights.
High level flow:
- Create a ruleset that says which access classes you want to handle.
- Add rules that allow specific actions on specific objects.
- Call
landlock_restrict_self(). - The current thread, and then its future children, run under that restricted domain.
Important nuance:
- rights listed in the ruleset as handled become denied by default unless later allowed by a rule;
- rights not listed as handled are not restricted by that ruleset;
- Landlock then composes with DAC, namespaces, seccomp, SELinux/AppArmor, other LSMs, etc.
So Landlock is not “deny everything automatically.” It is deny everything you explicitly chose to manage.
2) What Landlock is good at
Strong fits
A) Self-sandboxing user applications
Examples:
- PDF/image conversion tool allowed to read input dir and write only output dir
- local Markdown renderer allowed to read project files but not
$HOME/.ssh - package/plugin execution limited to a cache dir and network subset
- browser helper / preview process allowed to read assets but not mutate repo state
B) Developer-facing safety wrappers
Good when you want:
- safer local execution,
- lower blast radius for third-party tools,
- cheap containment for risky parsing logic,
- or a “least privilege by default” launcher.
C) Defense-in-depth around file and network access
Landlock is especially nice when you want to reduce the damage from:
- RCE in a helper process,
- path traversal bugs,
- malicious plugin behavior,
- accidental writes to sensitive paths,
- or over-broad network access.
D) Progressive hardening with runtime feature detection
Because Landlock is ABI-versioned and intended for best-effort adoption, it is friendly to software distributed across mixed kernel fleets.
Weak fits
A) Full system-wide MAC replacement
That is not Landlock’s job. If you need broad host policy, mature labeling, or organization-wide confinement, SELinux/AppArmor may still be the primary control.
B) Retroactive control over already-open resources
Landlock does not fully solve “what the process already opened before sandboxing.” Pre-opened file descriptors are a real caveat.
C) Policy based on rich identity semantics
Landlock understands kernel objects and rights, not business identity, tenancy metadata, or service-level intent on its own.
D) Complex exception-heavy IPC policy
Its IPC scoping model is intentionally simpler than a general-purpose policy engine.
3) The core API shape
Landlock uses three syscalls:
landlock_create_ruleset()landlock_add_rule()landlock_restrict_self()
landlock_create_ruleset()
Creates a ruleset FD and defines the handled access rights.
This is the moment where you declare:
- which filesystem rights you want the sandbox to manage,
- which network rights you want it to manage,
- and, on newer ABIs, which IPC scopes you want to enforce.
landlock_add_rule()
Adds specific allow rules to that ruleset.
Today, the main rule types are:
LANDLOCK_RULE_PATH_BENEATHfor filesystem hierarchies/filesLANDLOCK_RULE_NET_PORTfor TCP ports
landlock_restrict_self()
Enforces the ruleset.
To do this safely, the caller must either:
- have
CAP_SYS_ADMINin its user namespace, or - set
no_new_privsfirst.
In practice, the unprivileged pattern is:
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
landlock_restrict_self(ruleset_fd, 0);
Once applied, the policy is one-way:
- you cannot remove it,
- you can only layer on more restrictions.
4) Best mental model for policy design
Design Landlock policies as minimal capability envelopes.
A solid pattern is:
- allow read-only access to immutable program/runtime inputs,
- allow read-write only to narrowly scoped scratch/output dirs,
- allow connect only to explicitly needed ports,
- deny everything else among the rights you declared as handled.
Example mental sandbox for a document converter:
- read + execute:
/usr, runtime libs, app binary - read-only:
/etc/ssl/certs, input dir - read-write: temp dir, output dir
- connect TCP: maybe 443 only, or none
- no write access to home dotfiles, SSH keys, repo root, arbitrary network
That is where Landlock shines.
5) ABI versions matter more than kernel version
This is one of the biggest operational points.
You should not gate behavior by “kernel 6.x” heuristics. Use the Landlock ABI version query instead:
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
Why:
- kernels may backport features,
- distro versions do not map cleanly to upstream releases,
- and Landlock explicitly expects user space to use best-effort runtime detection.
Practical ABI progression
| ABI | Mainline orientation | New capability |
|---|---|---|
| 1 | Linux 5.13 | baseline filesystem rules |
| 2 | Linux 5.19 | LANDLOCK_ACCESS_FS_REFER |
| 3 | Linux 6.2 | LANDLOCK_ACCESS_FS_TRUNCATE |
| 4 | Linux 6.7 | TCP bind/connect control |
| 5 | Linux 6.10 | LANDLOCK_ACCESS_FS_IOCTL_DEV |
| 6 | Linux 6.12 | IPC scoping for abstract UNIX sockets and signals |
Recent kernel docs also describe newer ABI growth such as:
- ABI v7 logging controls for audit behavior,
- ABI v8 thread-synchronizing enforcement (
TSYNC) across all threads of the calling process.
Operational rule:
Probe ABI, mask unsupported rights/flags, and still enforce the strongest compatible subset.
That is the right Landlock rollout style.
6) Filesystem rights: the useful operator view
Landlock filesystem policy is path-hierarchy oriented. The main rights to remember are:
Read/execute basics
LANDLOCK_ACCESS_FS_EXECUTELANDLOCK_ACCESS_FS_READ_FILELANDLOCK_ACCESS_FS_READ_DIR
Write/mutation basics
LANDLOCK_ACCESS_FS_WRITE_FILELANDLOCK_ACCESS_FS_TRUNCATELANDLOCK_ACCESS_FS_REMOVE_FILELANDLOCK_ACCESS_FS_REMOVE_DIRLANDLOCK_ACCESS_FS_MAKE_*
Reparenting / linking
LANDLOCK_ACCESS_FS_REFER
Device ioctl control
LANDLOCK_ACCESS_FS_IOCTL_DEV
Two easy mistakes
A) WRITE_FILE and TRUNCATE are not the same
This catches people all the time.
If your app rewrites files in place, creates output with overwrite semantics, or uses O_TRUNC, then WRITE_FILE alone is often not enough.
The kernel docs explicitly recommend treating these together in most write scenarios.
A classic gotcha is creat(2):
- it sounds like “create/write,”
- but if the file already exists, truncate permission matters too.
B) REFER is special
LANDLOCK_ACCESS_FS_REFER is the oddball.
It is effectively denied by default and must be explicitly handled/allowed for relevant directories.
Also:
- ABI v1 always forbids cross-directory link/rename reparenting,
- source and destination directories need the right permissions,
- and some operations can fail with
EXDEVwhen the move would gain rights in the destination tree.
If your application depends on rename-heavy workflows, temp-file-then-atomic-move patterns, or moving files across dirs, you must test this explicitly.
7) Network rules: simple, but useful
Since ABI v4, Landlock can control TCP ports with:
LANDLOCK_ACCESS_NET_BIND_TCPLANDLOCK_ACCESS_NET_CONNECT_TCP
This is not a full network policy language. That is fine.
It is still very useful for cases like:
- allow only outbound 443,
- forbid local listener creation except one port,
- or ban unexpected active TCP connections from a helper process.
One detail worth remembering:
- binding to port
0means “pick an ephemeral port,” - and Landlock treats that as the ephemeral range when
LANDLOCK_ACCESS_NET_BIND_TCPfor port 0 is allowed.
This matters for servers or tooling that say “bind any free port.”
8) IPC scoping is powerful, but more rigid than path rules
Since ABI v6, Landlock can scope some IPC interactions to the same or nested Landlock domain:
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKETLANDLOCK_SCOPE_SIGNAL
This is important because file/network sandboxing alone does not solve all cross-process influence.
The big constraint:
- IPC scoping does not support exceptions through
landlock_add_rule().
So if you scope it, you cannot later poke holes for some external resource the way you can with path or port rules.
That makes IPC scoping best for:
- cleanly isolated helper trees,
- plugin subprocesses,
- or sandboxes where cross-domain communication should be structurally off.
It is less ideal for messy legacy apps with many exception cases.
9) The biggest practical caveat: pre-opened file descriptors
Landlock is not a time machine.
Files or directories opened before sandbox enforcement are a major caveat. Some rights are effectively checked at open time and then carried by the FD.
This matters for:
- already-open writable file handles,
- descriptors inherited across exec,
- helper-launcher designs that open things too early,
- FD passing between processes,
- and device or truncate-related behaviors tied to the opened descriptor.
Operational lesson:
Sandbox as early as possible, before opening anything you do not want to keep.
If you must pre-open resources:
- keep the list tiny,
- mark everything else
CLOEXEC, - audit inherited descriptors,
- and document which FDs intentionally survive the sandbox boundary.
This is a classic place where a “secure design” quietly loses a lot of value.
10) Threading caveat: know what restrict_self really hits
Historically, landlock_restrict_self() applies to the calling thread and its future descendants.
It does not magically retrofit sibling threads.
That makes Landlock adoption much cleaner in:
- single-threaded launchers,
- early-process sandboxing before thread pools start,
- or tightly controlled process trees.
It is trickier for already-multithreaded processes.
Recent kernel docs describe a newer ABI flag for thread-synchronized enforcement (TSYNC, ABI v8), which is exactly meant to improve this story.
But you still need runtime ABI handling and careful testing.
Operational rule:
- if you want predictable behavior across a mixed fleet, sandbox before spawning threads unless you have explicitly validated newer ABI behavior.
11) Bind mounts, OverlayFS, and path-shape gotchas
This is an easy place to get surprised.
Bind mounts
Landlock restrictions can propagate through bind-mounted hierarchy views in a way that makes sense for path-based hierarchy control.
OverlayFS
OverlayFS is different. The kernel docs explicitly note that OverlayFS layers and merged hierarchies are treated as standalone from a Landlock perspective.
Meaning:
- restricting a lower/upper layer does not automatically restrict the merged view,
- and restricting the merged view does not magically back-propagate to layers.
Operational consequence:
Policy should be written against the actual hierarchy the sandboxed process will access, not against what you hope is “the same data underneath.”
If your app runs in overlay-heavy container/runtime environments, test the exact mount topology. Do not assume storage-layer intuition is enough.
12) Landlock is layered, not singular
A process can enforce multiple rulesets over time. These compose into a Landlock domain.
Useful interpretation:
- one layer from an init system,
- one layer from a session wrapper,
- one layer from the application itself.
But there is a practical limit to the number of composed rulesets. Also, arbitrary repeated layering is usually worse than building one coherent ruleset.
Best practice:
- use one main application ruleset with multiple rules,
- reserve multi-layer composition for genuinely independent policy sources.
13) Where Landlock fits relative to seccomp, SELinux/AppArmor, and BPF LSM
Landlock vs seccomp
Use seccomp when you need:
- syscall-level reduction,
- argument-level filtering,
- very tight kernel attack-surface minimization.
Use Landlock when you need:
- path hierarchy control,
- bounded file/network access,
- easier self-sandboxing for user applications.
They are complementary. A strong pattern is:
- seccomp trims syscall surface,
- Landlock trims accessible resources.
Landlock vs SELinux/AppArmor
Use SELinux/AppArmor when you need:
- host-wide or fleet-wide policy,
- mature admin-controlled confinement,
- stronger centralized operating controls.
Use Landlock when you want:
- application-bundled sandboxing,
- unprivileged self-confinement,
- simple least-privilege envelopes without full host-policy machinery.
They also compose.
Landlock vs BPF LSM
BPF LSM is better when you need:
- programmable hook logic,
- cgroup/workload-aware custom rules,
- specialized kernel-path enforcement.
Landlock is better when you want:
- a built-in userspace API,
- no BPF verifier/program lifecycle overhead,
- portable app-shipped self-sandboxing.
Landlock is much closer to “a practical application sandbox primitive.”
14) A safe rollout pattern
Stage 0 — Capability discovery
Before you promise anything:
- query Landlock ABI,
- confirm Landlock is enabled,
- determine which rights/scopes are available.
Also remember:
EOPNOTSUPPcan mean “kernel supports it but boot config disabled it.”
Stage 1 — Read-only sandbox first
Start with the easiest high-confidence shape:
- read/execute runtime tree,
- read-only input tree,
- dedicated writable temp/output tree.
Avoid rename-heavy and device-heavy flows first.
Stage 2 — Add write paths carefully
Introduce:
WRITE_FILE,TRUNCATE,MAKE_*,REMOVE_*,- and maybe
REFER.
This is where file workflow edge cases begin to appear.
Stage 3 — Add network restriction
If the application truly only needs:
- no network, or
- outbound 443, or
- one local bind port,
encode that.
Stage 4 — Add IPC scoping only when process topology is clean
Do this after you understand the actual process graph and communication paths.
Stage 5 — Add seccomp or host policy on top
Landlock is usually strongest as one layer in a stack, not the only control.
15) Common failure modes in real deployments
A) Sandboxing too late
Symptoms:
- writable FDs remain alive,
- helper processes inherit too much,
- “sandboxed” app still writes somewhere surprising.
B) Forgetting TRUNCATE
Symptoms:
- writes work on new files,
- overwrites or
creat()fail unexpectedly, - save paths look flaky.
C) Rename/link workflows break mysteriously
Symptoms:
- temp-file commit pattern fails,
- cross-dir rename returns
EXDEVorEACCES, - app only breaks on some kernels.
Usually a REFER / source-destination rights issue.
D) Threading assumptions are wrong
Symptoms:
- one worker is sandboxed, another is not,
- behavior differs by startup timing,
- sandbox only affects descendants of one thread.
E) OverlayFS path assumptions are wrong
Symptoms:
- rule looks correct on source tree,
- merged runtime view still behaves differently.
F) Over-broad parent directory policy
Symptoms:
- policy technically works,
- but grants more ambient reach than intended.
The kernel docs recommend defining rights as close to leaf hierarchies as possible. That is good advice.
16) Practical design checklist
Before shipping a Landlock sandbox, ask:
Resource model
- What exact directories must be readable?
- What exact directories must be writable?
- Are writes append-only, overwrite, create, delete, rename, or all of the above?
- Are device files involved?
- Is network access needed at all?
- Which ports exactly?
Process model
- Is sandboxing applied before thread creation?
- Before helper exec?
- Before privileged resources are opened?
- Are inherited FDs fully audited?
Compatibility model
- What minimum Landlock ABI is required for full behavior?
- What is the degraded behavior on older ABIs?
- Does the app still work if
REFER,TRUNCATE, network, or IPC scopes are unavailable?
Validation model
- Do integration tests cover rename/move flows?
- Do they cover overwrite/truncate flows?
- Do they cover tempdir behavior?
- Do they cover container/OverlayFS mount layouts?
- Do they cover multi-thread/process startup order?
17) Best practices worth keeping
Prefer leaf-scoped rules over giant parent trees
This reduces accidental ambient reach and makes directory moves easier to reason about.
Enforce early
The value of Landlock drops fast if you open half the world before calling it.
Probe ABI at runtime
Do not ship kernel-version folklore.
Build one coherent ruleset when possible
Use multiple rules, not arbitrary numbers of rulesets.
Treat write workflows as a matrix
Test separately:
- create new file,
- overwrite existing file,
- truncate existing file,
- rename within dir,
- rename across dirs,
- delete,
- link/symlink if relevant.
Combine with other controls
Landlock is better with:
- seccomp,
- namespaces,
- SELinux/AppArmor where appropriate,
- tight FD hygiene,
- and sane exec boundaries.
18) When I would reach for Landlock first
I would reach for Landlock first when I want:
- an application to ship its own confinement,
- userspace-controlled least privilege without requiring full admin policy rollout,
- strong path-based limits on helper processes,
- lightweight network narrowing,
- or defense-in-depth for risky parsers and plugin systems.
I would not start with Landlock when the main problem is:
- whole-host mandatory policy,
- syscall attack surface only,
- or rich cross-service authorization semantics.
Bottom line
Landlock is one of the more practical Linux security primitives to adopt because it hits a rare sweet spot:
- useful without root-only orchestration,
- narrow enough to reason about,
- stackable with the rest of the Linux security model,
- and strong enough to materially reduce blast radius for real apps.
Its main traps are also predictable:
- ABI drift,
- pre-opened file descriptors,
- rename/truncate semantics,
- thread timing,
- and mount-topology assumptions.
If you treat those as first-class design concerns, Landlock becomes less like a niche kernel feature and more like a genuinely deployable sandboxing tool.
References
- Linux kernel documentation: Landlock userspace API
https://docs.kernel.org/userspace-api/landlock.html landlock(7)manual page
https://man7.org/linux/man-pages/man7/landlock.7.htmllandlock_create_ruleset(2)manual page
https://man7.org/linux/man-pages/man2/landlock_create_ruleset.2.htmllandlock_add_rule(2)manual page
https://man7.org/linux/man-pages/man2/landlock_add_rule.2.htmllandlock_restrict_self(2)manual page
https://man7.org/linux/man-pages/man2/landlock_restrict_self.2.html