Skip to content

Python bindings for Linux Landlock - sandbox unprivileged processes with filesystem and network restrictions

License

Notifications You must be signed in to change notification settings

SebastienWae/py-landlock

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

py-landlock

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.

Requirements

  • Python 3.10 or later
  • Linux kernel 5.13 or later with Landlock enabled
  • Supported architectures: x86_64, aarch64

Installation

pip install py-landlock

Or with uv:

uv add py-landlock

Examples

Quick Start

from py_landlock import Landlock

Landlock() \
    .allow_read("/usr", "/etc") \
    .allow_execute("/usr/bin") \
    .apply()

# Any attempt to write or access other paths now raises PermissionError

Check Availability

from 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}")

Sandbox with Network Restrictions

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.

Usage

High-Level API

The Landlock class provides a fluent builder interface for constructing and applying security policies.

Filesystem Access Control

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 Access Control

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

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

Strict vs Best-Effort Mode

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.

ABI Compatibility

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

Low-Level API

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)

Error Handling

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

Threading

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

Limitations

Landlock has several limitations documented in the kernel documentation:

  • Filesystem topology: Sandboxed threads cannot modify filesystem topology via mount(2) or pivot_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() returns E2BIG. This can be problematic for programs that launch other sandboxed programs.

  • IOCTL restrictions: The IOCTL_DEV access 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.

Resources

License

MIT

About

Python bindings for Linux Landlock - sandbox unprivileged processes with filesystem and network restrictions

Topics

Resources

License

Stars

Watchers

Forks

Languages