Python bindings for the Linux Landlock security module.
Landlock is a Linux kernel feature that enables unprivileged processes to restrict their own access to the filesystem, network, and IPC resources. This library provides both a high-level API for common use cases and low-level access to the underlying syscalls.
- Python 3.10 or later
- Linux kernel 5.13 or later with Landlock enabled
- Supported architectures: x86_64, aarch64
pip install py-landlockOr with uv:
uv add py-landlockfrom py_landlock import Landlock
Landlock() \
.allow_read("/usr", "/etc") \
.allow_execute("/usr/bin") \
.apply()
# Any attempt to write or access other paths now raises PermissionErrorfrom py_landlock import get_abi_version, LandlockNotAvailableError
try:
version = get_abi_version()
print(f"Landlock ABI v{version}")
except LandlockNotAvailableError as e:
print(f"Not available: {e}")from py_landlock import Landlock
Landlock() \
.allow_read("/usr", "/etc") \
.allow_read_write("/tmp/myapp") \
.allow_network(443, bind=False, connect=True) \
.apply()For more examples, see the examples/ directory.
The Landlock class provides a fluent builder interface for constructing and applying security policies.
| Method | Description |
|---|---|
allow_read(*paths) |
Allow reading files and listing directories |
allow_write(*paths) |
Allow writing, creating, and removing files |
allow_execute(*paths) |
Allow executing files |
allow_read_write(*paths) |
Combination of read and write access |
add_path_rule(*paths, access) |
Add a rule with specific AccessFs flags |
Network restrictions require kernel ABI version 4 or later.
| Method | Description |
|---|---|
allow_network(*ports, bind, connect) |
Allow TCP bind and/or connect on specified ports |
allow_all_network() |
Disable network restrictions entirely |
Scope restrictions limit IPC and signal delivery to processes within the same Landlock domain. Requires kernel ABI version 6 or later.
| Method | Description |
|---|---|
allow_scope(scope) |
Exempt specific scope restrictions |
allow_all_scope() |
Disable all scope restrictions |
By default, the library operates in strict mode and raises CompatibilityError if a requested feature is not supported by the running kernel. Use Landlock(strict=False) for best-effort mode which silently ignores unsupported features.
Landlock uses ABI versioning to maintain backward compatibility as new features are added. The kernel's ABI version determines which access rights are available:
| ABI Version | Kernel Version | Features Added |
|---|---|---|
| 1 | 5.13 | Basic filesystem access control |
| 2 | 5.19 | File referring (REFER) |
| 3 | 6.2 | File truncation (TRUNCATE) |
| 4 | 6.7 | TCP network restrictions |
| 5 | 6.10 | Device IOCTL (IOCTL_DEV) |
| 6 | 6.12 | Scope restrictions (abstract UNIX, signals) |
| 7 | 6.14 | Audit logging control |
For advanced use cases, the library exposes the underlying syscall wrappers:
from py_landlock import (
create_ruleset,
add_rule,
restrict_self,
RulesetAttr,
PathBeneathAttr,
AccessFs,
)
attr = RulesetAttr()
attr.handled_access_fs = AccessFs.READ_FILE | AccessFs.WRITE_FILE
ruleset_fd = create_ruleset(attr)
path_attr = PathBeneathAttr.from_path("/tmp", AccessFs.READ_FILE | AccessFs.WRITE_FILE)
add_rule(ruleset_fd, path_attr)
restrict_self(ruleset_fd)| Exception | Description |
|---|---|
LandlockError |
Base exception for all Landlock errors |
LandlockNotAvailableError |
Landlock not available (wrong platform, architecture, or kernel) |
LandlockDisabledError |
Landlock supported but disabled at boot |
RulesetError |
Failed to create, configure, or apply a ruleset |
PathError |
Specified path does not exist |
CompatibilityError |
Requested feature requires a higher ABI version |
NetworkDisabledError |
TCP/IP not available in kernel |
Landlock rules apply to the calling thread and are inherited by all threads and processes it creates afterward. Key behaviors:
- Rules cannot be removed once applied
- Each thread can add additional restrictions to itself
- Child threads and processes inherit all restrictions from their parent
- A thread cannot relax restrictions inherited from its parent
Landlock has several limitations documented in the kernel documentation:
-
Filesystem topology: Sandboxed threads cannot modify filesystem topology via
mount(2)orpivot_root(2). However,chroot(2)is permitted. -
Special filesystems: Files from non-user-visible filesystems (such as pipes and sockets) accessible through
/proc/<pid>/fd/*cannot be explicitly restricted. Special kernel filesystems like nsfs also cannot be directly restricted. -
Ruleset stacking limit: A maximum of 16 stacked rulesets can be applied. Once this limit is reached,
restrict_self()returnsE2BIG. This can be problematic for programs that launch other sandboxed programs. -
IOCTL restrictions: The
IOCTL_DEVaccess right only applies to device files opened after the ruleset is applied. Pre-existing file descriptors (stdin, stdout, stderr) are unaffected. -
Network restrictions: Only TCP bind and connect operations can be restricted. UDP, ICMP, and other protocols are not covered.
- Landlock website
- Linux kernel documentation
- rust-landlock - Rust bindings
- go-landlock - Go bindings