Landlock: userland documentation

Landlock rules

eBPF programs are used to create security rules. They are contained and can call only a whitelist of dedicated functions. Moreover, they cannot loop, which protects from denial of service. More information on BPF can be found in Documentation/networking/filter.txt.

Writing a rule

To enforce a security policy, a thread first needs to create a Landlock rule. The easiest way to write an eBPF program depicting a security rule is to write it in the C language. As described in samples/bpf/README.rst, LLVM can compile such programs. Files samples/bpf/landlock1_kern.c and those in tools/testing/selftests/landlock/rules/ can be used as examples. The following example is a simple rule to forbid file creation, whatever syscall may be used (e.g. open, mkdir, link...). The ctx->event contains the event ID for which the rule is actually ran. The ctx->arg2 contains the action type performed on the file (cf. File system action types).

static int deny_file_creation(struct landlock_context *ctx)
{
    if (ctx->event != LANDLOCK_SUBTYPE_EVENT_FS)
        return 1;
    if (ctx->arg2 & LANDLOCK_ACTION_FS_NEW)
        return 1;
    return 0;
}

Once the eBPF program is created, the next step is to create the metadata describing the Landlock rule. This metadata includes a subtype which contains the minimal ABI version that must be supported by the kernel, the event to which the rule is tied, and optional Landlock rule abilities.

static union bpf_prog_subtype subtype = {
    .landlock_rule = {
        .abi = 1,
        .event = LANDLOCK_SUBTYPE_EVENT_FS,
    }
};

The Landlock ABI is important to inform the kernel which features or behavior the rule can handle. The user-space thread should set the lowest possible ABI to be as compatible as possible with older kernels. For the list of features provided by ABI, see Landlock features.

A Landlock event describes the kind of kernel object for which a rule will be triggered to allow or deny an action. For example, the event LANDLOCK_SUBTYPE_EVENT_FS is triggered every time a landlocked thread performs an action related to the filesystem (e.g. open, read, write, mount...).

The Landlock rule abilities should only be used if the rule needs a specific feature such as debugging. This should be avoided if not strictly necessary.

The next step is to fill a union bpf_attr with BPF_PROG_TYPE_LANDLOCK_RULE, the previously created subtype and other BPF program metadata. This bpf_attr must then be passed to the bpf(2) syscall alongside the BPF_PROG_LOAD command. If everything is deemed correct by the kernel, the thread gets a file descriptor referring to this rule.

In the following code, the insn variable is an array of BPF instructions which can be extracted from an ELF file as is done in bpf_load_file() from samples/bpf/bpf_load.c.

union bpf_attr attr = {
    .prog_type = BPF_PROG_TYPE_LANDLOCK_RULE,
    .insn_cnt = sizeof(insn) / sizeof(struct bpf_insn),
    .insns = (__u64) (unsigned long) insn,
    .license = (__u64) (unsigned long) "GPL",
    .prog_subtype = &subtype,
    .prog_subtype_size = sizeof(subtype),
};
int rule = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
if (rule == -1)
    exit(1);

Enforcing a rule

Once the Landlock rule has been created or received (e.g. through a UNIX socket), the thread willing to sandbox itself (and its future children) should perform the following two steps to properly sandbox itself with a rule.

The thread should first request to never be allowed to get new privileges with a call to prctl(2) and the PR_SET_NO_NEW_PRIVS option. More information can be found in Documentation/prctl/no_new_privs.txt.

if (prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0))
    exit(1);

A thread can apply a rule to itself by using the seccomp(2) syscall. The operation is SECCOMP_PREPEND_LANDLOCK_RULE, the flags must be empty and the args argument must point to a valid Landlock rule file descriptor.

if (seccomp(SECCOMP_PREPEND_LANDLOCK_RULE, 0, &rule))
    exit(1);

If the syscall succeeds, the rule is now enforced on the calling thread and will be enforced on all its subsequently created children of the thread as well. Once a thread is landlocked, there is no way to remove this security policy, only stacking more restrictions is allowed. The rule evaluation is performed from the newest to the oldest.

When a syscall ask for an action on a kernel object, if this action is denied, then an EPERM errno code is returned through the syscall.

Inherited rules

Every new thread resulting from a clone(2) inherits Landlock rule restrictions from its parent. This is similar to the seccomp inheritance as described in Documentation/prctl/seccomp_filter.txt.

Ptrace restrictions

A landlocked process has less privileges than a non-landlocked process and must then be subject to additional restrictions when manipulating another process. To be allowed to use ptrace(2) and related syscalls on a target process, a landlocked process must have a subset of the target process rules.

Landlock features

In order to support new features over time without changing a rule behavior, every context field, flag or helpers has a minimal Landlock ABI in which they are available. A thread needs to specify this minimal ABI number in the subtype struct landlock_rule defined in include/uapi/linux/bpf.h.

Context

The arch and syscall_nr fields may be useful to tighten an access control, but care must be taken to avoid pitfalls as explain in Documentation/prctl/seccomp_filter.txt.

struct landlock_context

context accessible to a Landlock rule

Definition

struct landlock_context {
  __u64 status;
  __u64 event;
  __u64 arg1;
  __u64 arg2;
};

Members

status
bitfield for future use (LANDLOCK_SUBTYPE_STATUS_*)
event
event type (enum landlock_subtype_event)
arg1
event’s first optional argument
arg2
event’s second optional argument

Landlock event types

enum landlock_subtype_event

event occurring when an action is performed on a particular kernel object

Constants

LANDLOCK_SUBTYPE_EVENT_UNSPEC
invalid value
LANDLOCK_SUBTYPE_EVENT_FS
generic filesystem event
LANDLOCK_SUBTYPE_EVENT_FS_IOCTL
custom IOCTL sub-event
LANDLOCK_SUBTYPE_EVENT_FS_LOCK
custom LOCK sub-event
LANDLOCK_SUBTYPE_EVENT_FS_FCNTL
custom FCNTL sub-event

Description

An event is a policy decision point which exposes the same context type (especially the same arg[0-9] field types) for each rule execution.

Event types availability and optional arguments from struct landlock_context
Event type Minimal ABI Optional arg1 Optional arg2
LANDLOCK_SUBTYPE_EVENT_FS 1 filesystem handle File system action types
LANDLOCK_SUBTYPE_EVENT_FS_IOCTL 1 filesystem handle ioctl(2) request
LANDLOCK_SUBTYPE_EVENT_FS_LOCK 1 filesystem handle flock(2) operation
LANDLOCK_SUBTYPE_EVENT_FS_FCNTL 1 filesystem handle fcntl(2) command

File system action types

Flags are used to express actions. This makes it possible to compose actions and leaves room for future improvements to add more fine-grained action types.

  • LANDLOCK_ACTION_FS_EXEC: execute a file or walk through a directory
  • LANDLOCK_ACTION_FS_WRITE: modify a file or a directory view (which include mount actions)
  • LANDLOCK_ACTION_FS_READ: read a file or a directory
  • LANDLOCK_ACTION_FS_NEW: create a file or a directory
  • LANDLOCK_ACTION_FS_GET: open or receive a file
  • LANDLOCK_ACTION_FS_REMOVE: unlink a file or remove a directory

Each of the following actions are specific to syscall multiplexers. Each of them trigger a dedicated Landlock event where their command can be read.

  • LANDLOCK_ACTION_FS_IOCTL: ioctl command
  • LANDLOCK_ACTION_FS_LOCK: flock or fcntl lock command
  • LANDLOCK_ACTION_FS_FCNTL: fcntl command
FS action types availability
Action flag Minimal ABI
LANDLOCK_ACTION_FS_EXEC 1
LANDLOCK_ACTION_FS_WRITE 1
LANDLOCK_ACTION_FS_READ 1
LANDLOCK_ACTION_FS_NEW 1
LANDLOCK_ACTION_FS_GET 1
LANDLOCK_ACTION_FS_REMOVE 1
LANDLOCK_ACTION_FS_IOCTL 1
LANDLOCK_ACTION_FS_LOCK 1
LANDLOCK_ACTION_FS_FCNTL 1

Ability types

The ability of a Landlock rule describes the available features (i.e. context fields and available helpers). This is useful to abstract user-space privileges for Landlock rules, which may not need all abilities (e.g. debug). Only the minimal set of abilities should be used (e.g. disable debug once in production).

eBPF context and functions allowed for a rule

  • LANDLOCK_SUBTYPE_ABILITY_DEBUG: allows to do debug actions (e.g. writing logs), which may be dangerous and should only be used for rule testing
Ability types availability
Ability type Minimal ABI Capability
LANDLOCK_SUBTYPE_ABILITY_DEBUG 1 CAP_SYS_ADMIN

Helper functions

See include/uapi/linux/bpf.h for functions documentation.

Generic functions availability
Helper Minimal ABI Ability
bpf_get_current_comm 1 LANDLOCK_SUBTYPE_ABILITY_DEBUG
bpf_get_current_pid_tgid 1 LANDLOCK_SUBTYPE_ABILITY_DEBUG
bpf_get_current_uid_gid 1 LANDLOCK_SUBTYPE_ABILITY_DEBUG
bpf_get_trace_printk 1 LANDLOCK_SUBTYPE_ABILITY_DEBUG
File system functions availability
Helper Minimal ABI Ability
bpf_handle_fs_get_mode 1 (none)

Landlock ABI changelog

ABI 1

Initial version.