Landlock LSM: kernel documentation

Author:

Mickaël Salaün

Date:

October 2026

Landlock’s goal is to create scoped access-control (i.e. sandboxing). To harden a whole system, this feature should be available to any process, including unprivileged ones. Because such a process may be compromised or backdoored (i.e. untrusted), Landlock’s features must be safe to use from the kernel and other processes point of view. Landlock’s interface must therefore expose a minimal attack surface.

Landlock is designed to be usable by unprivileged processes while following the system security policy enforced by other access control mechanisms (e.g. DAC, LSM). A Landlock rule shall not interfere with other access-controls enforced on the system, only add more restrictions.

Any user can enforce Landlock rulesets on their processes. They are merged and evaluated against inherited rulesets in a way that ensures that only more constraints can be added.

User space documentation can be found here: Landlock: unprivileged access control.

Guiding principles for safe access controls

  • A Landlock rule shall be focused on access control on kernel objects instead of syscall filtering (i.e. syscall arguments), which is the purpose of seccomp-bpf.

  • To avoid multiple kinds of side-channel attacks (e.g. leak of security policies, CPU-based attacks), Landlock rules shall not be able to programmatically communicate with user space.

  • Kernel access check shall not slow down access request from unsandboxed processes.

  • Computation related to Landlock operations (e.g. enforcing a ruleset) shall only impact the processes requesting them.

  • Resources (e.g. file descriptors) directly obtained from the kernel by a sandboxed process shall retain their scoped accesses (at the time of resource acquisition) whatever process uses them. Cf. File descriptor access rights.

  • Access denials shall be logged according to system and Landlock domain configurations. Log entries must contain information about the cause of the denial and the owner of the related security policy. Such log generation should have a negligible performance and memory impact on allowed requests.

Design choices

Inode access rights

All access rights are tied to an inode and what can be accessed through it. Reading the content of a directory does not imply to be allowed to read the content of a listed inode. Indeed, a file name is local to its parent directory, and an inode can be referenced by multiple file names thanks to (hard) links. Being able to unlink a file only has a direct impact on the directory, not the unlinked inode. This is the reason why LANDLOCK_ACCESS_FS_REMOVE_FILE or LANDLOCK_ACCESS_FS_REFER are not allowed to be tied to files but only to directories.

File descriptor access rights

Access rights are checked and tied to file descriptors at open time. The underlying principle is that equivalent sequences of operations should lead to the same results, when they are executed under the same Landlock domain.

Taking the LANDLOCK_ACCESS_FS_TRUNCATE right as an example, it may be allowed to open a file for writing without being allowed to ftruncate the resulting file descriptor if the related file hierarchy doesn’t grant that access right. The following sequences of operations have the same semantic and should then have the same result:

  • truncate(path);

  • int fd = open(path, O_WRONLY); ftruncate(fd); close(fd);

Similarly to file access modes (e.g. O_RDWR), Landlock access rights attached to file descriptors are retained even if they are passed between processes (e.g. through a Unix domain socket). Such access rights will then be enforced even if the receiving process is not sandboxed by Landlock. Indeed, this is required to keep access controls consistent over the whole system, and this avoids unattended bypasses through file descriptor passing (i.e. confused deputy attack).

Interaction between scoped flags and other access rights

The scoped flags in &struct landlock_ruleset_attr restrict the use of outgoing IPC from the created Landlock domain, while they permit reaching out to IPC endpoints within the created Landlock domain.

In the future, scoped flags may interact with other access rights, e.g. so that abstract UNIX sockets can be allow-listed by name, or so that signals can be allow-listed by signal number or target process.

When introducing LANDLOCK_ACCESS_FS_RESOLVE_UNIX, we defined it to implicitly have the same scoping semantics as a LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET flag would have: connecting to UNIX sockets within the same domain (where LANDLOCK_ACCESS_FS_RESOLVE_UNIX is used) is unconditionally allowed.

The reasoning is:

  • Like other IPC mechanisms, connecting to named UNIX sockets in the same domain should be expected and harmless. (If needed, users can further refine their Landlock policies with nested domains or by restricting LANDLOCK_ACCESS_FS_MAKE_SOCK.)

  • We reserve the option to still introduce LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET in the future. (This would be useful if we wanted to have a Landlock rule to permit IPC access to other Landlock domains.)

  • But we can postpone the point in time when users have to deal with two interacting flags visible in the userspace API. (In particular, it is possible that it won’t be needed in practice, in which case we can avoid the second flag altogether.)

  • If we do introduce LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET in the future, setting this scoped flag in a ruleset does not reduce the restrictions, because access within the same scope is already allowed based on LANDLOCK_ACCESS_FS_RESOLVE_UNIX.

Composability with user namespaces

Landlock domain-based scoping and the kernel’s user-namespace-based capability scoping enforce isolation over independent hierarchies. Landlock checks domain ancestry; the kernel’s ns_capable() checks user namespace ancestry. These hierarchies are orthogonal: Landlock enforcement is deterministic with respect to its own configuration, regardless of namespace or capability state, and vice versa. This orthogonality is a design invariant that must hold for all Landlock access controls.

Design philosophy

Landlock’s goal is to restrict a sandboxed process’s access to three kinds of resources: data (files, sockets, pipes), other processes (signals, ptrace), and kernel-internal resources whose use widens the kernel attack surface (capabilities, namespace types). Each access right or permission gates one or more operations that grant such access; restricting the operations is how Landlock restricts the underlying access.

When designing a new access control, identify the protected resource kind first (data, processes, or kernel-internal resources). The operations to restrict follow from the protected resource, by identifying which kernel code paths grant access to the resource and at which place in the code the access to the resource can be gated. Do not design a permission around “restrict the unshare(2) syscall” or similar mechanism-centric framings; design it around “restrict the process from acquiring access to namespace types” (the protected resource), letting the operation set follow.

Ruleset restriction models

Landlock provides three restriction models that differ in how rules identify the resource being restricted.

In general, the struct landlock_ruleset_attr specifies the operations to be denied by default under the enforced policy. The rules added to the ruleset define the exceptions to these restrictions, allow-listing specific conditions under which these operations are still permitted.

Per-object access rights (handled_access_*)

Per-object access rights control operations on a specific resource instance, identified in the rule key by a value drawn from an open-ended space: a file hierarchy referenced by parent_fd, or a network port identified by its 16-bit number.

Each handled_access_* field declares a set of access rights, operations which are to be denied by default once the ruleset is enforced.

The rule body declares which of the multiple distinct operations on that object instance are allowed (open, read, write, truncate; bind, connect).

Operations are grouped by object type in the respective handled_access_* field: a new operation on an existing type extends that field, and a new object type gets its own handled_access_* field.

Per-category permissions (handled_permissions)

Per-category permissions control the process’s exercise of category members, where the category is a small kernel-defined enumeration (a Linux capability number CAP_*, a namespace type CLONE_NEW*). Unlike per-object access rights, which restrict specific operations on a single resource instance, per-category permissions gate the prerequisite operation itself (exercising a capability, acquiring access to a namespace), so gating it transitively covers a broad set of downstream operations (e.g. denying CAP_SYS_ADMIN blocks all admin operations such as mounts).

These category members are the LSM-level access-control objects (the entities the process is authorized against) even though they are enum values rather than externally-instantiated kernel data structures. Per-category permissions apply where the controlled operation collapses to “may the process use this category member at all” (use a capability; acquire access to a namespace), so the rule body lists which category members the process may exercise.

Each LANDLOCK_PERMISSION_* flag maps to its own rule type and covers every kernel path that exercises a member. When a ruleset handles a permission, all uses of category members are denied unless explicitly allowed by a rule.

Logging of a denied member can be suppressed at the same granularity as the restriction itself: per rule and per member. A rule names the members whose denial should not be audited; suppression only affects the audit record, never the denial or its trace event, which reports logged=0. Suppression only applies when the layer owning the rule is the one that denied the member.

See Landlock: unprivileged access control for the concrete syscall paths covered by each permission.

The category enum is owned by the corresponding kernel subsystem (capabilities, namespaces, etc.). Userspace policy authors query category member availability via the relevant non-Landlock interfaces:

  • For capabilities: <linux/capability.h>, /proc/sys/kernel/cap_last_cap, prctl(PR_CAPBSET_READ).

  • For namespaces: <linux/sched.h>, /proc/$$/ns/*, unshare(2) runtime probe.

The Landlock ABI version does not encode this availability; ABI versioning describes which Landlock features (rule types, access rights, scopes, permissions) the kernel implements, not which category members the kernel knows about.

Forward compatibility for new category members follows a simple rule set:

  • New members in future kernels are automatically denied: rules whitelist specific values, and a member not in any rule is denied.

  • Kernel-side compatibility for split categories is handled by the owning subsystem (e.g., when CAP_BPF was split from CAP_SYS_ADMIN, either capability became sufficient for the affected operations, so a rule allowing CAP_SYS_ADMIN continues to allow operations now gated by CAP_SYS_ADMIN || CAP_BPF).

  • Unknown values in the rule body are silently accepted rather than rejected. Rejecting them would tie Landlock policy semantics to the running kernel’s category-member set: a rule built against future headers would fail to load on older kernels, forcing policy authors to know each kernel’s enumeration. Acceptance is fail-safe in both directions: a rule referring to a value the running kernel does not yet know has no effect (deny-by-default still applies to that operation), and a rule written against future headers loads identically across kernels so the same policy keeps the same restrictions. When a value becomes real on a future kernel, the policy activates as written by the author.

  • In contrast, unknown LANDLOCK_PERMISSION_* flags in handled_permissions are rejected (-EINVAL), since Landlock owns that bit space.

Cross-domain scopes (scoped)

Scopes restrict cross-domain interactions categorically, without rules. Setting a scope flag (e.g. LANDLOCK_SCOPE_SIGNAL) denies the operation to targets outside the Landlock domain or its children. Like per-category permissions, scopes provide complete coverage of the controlled operation.

Choosing a model for a new feature

  • If the new feature controls operations on resource objects supplied by the sandbox author, extend or add a per-object access right (handled_access_*).

  • If the new feature controls a per-category operation gated by an enum (a Linux capability, a namespace type, a socket family, etc.), use a per-category permission (handled_permissions). When several such enums could classify the operation, prefer the enum the originating subsystem already uses for capability/access checks (e.g. CAP_* for capable() hooks, CLONE_NEW* for namespace hooks).

  • When an operation is gated by multiple kernel-defined enums (a classic example being CAP_SYS_ADMIN plus a CLONE_NEW* flag for non-user namespace creation), define one per-category permission per enum dimension. Sandbox authors handle each dimension’s permission in handled_permissions and add rules for each; the kernel enforces each dimension at its own LSM hook. LANDLOCK_PERMISSION_NAMESPACE_USE and LANDLOCK_PERMISSION_CAPABILITY_USE follow this pattern.

  • If the new feature restricts a categorical cross-domain interaction with no per-target granularity, use a cross-domain scope (scoped).

  • For all three models, confirm a single LSM hook (or small set of related hooks) covers every kernel path that exercises the operation.

Tests

Userspace tests for backward compatibility, ptrace restrictions and filesystem support can be found here: tools/testing/selftests/landlock/.

Kernel structures

Object

struct landlock_object_underops

Operations on an underlying object

Definition:

struct landlock_object_underops {
    void (*release)(struct landlock_object *const object) __releases(object->lock);
};

Members

release

Releases the underlying object (e.g. iput() for an inode).

struct landlock_object

Security blob tied to a kernel object

Definition:

struct landlock_object {
    refcount_t usage;
    spinlock_t lock;
    void *underobj;
    union {
        struct rcu_head rcu_free;
        const struct landlock_object_underops *underops;
    };
};

Members

usage

This counter is used to tie an object to the rules matching it or to keep it alive while adding a new rule. If this counter reaches zero, this struct must not be modified, but this counter can still be read from within an RCU read-side critical section. When adding a new rule to an object with a usage counter of zero, we must wait until the pointer to this object is set to NULL (or recycled).

lock

Protects against concurrent modifications. This lock must be held from the time usage drops to zero until any weak references from underobj to this object have been cleaned up.

Lock ordering: inode->i_lock nests inside this.

underobj

Used when cleaning up an object and to mark an object as tied to its underlying kernel structure. This pointer is protected by lock. Cf. landlock_release_inodes() and release_inode().

{unnamed_union}

anonymous

rcu_free

Enables lockless use of usage, lock and underobj from within an RCU read-side critical section. rcu_free and underops are only used by landlock_put_object().

underops

Enables landlock_put_object() to release the underlying object (e.g. inode).

Description

The goal of this structure is to enable to tie a set of ephemeral access rights (pertaining to different domains) to a kernel object (e.g an inode) in a safe way. This implies to handle concurrent use and modification.

The lifetime of a struct landlock_object depends on the rules referring to it.

Filesystem

struct landlock_inode_security

Inode security blob

Definition:

struct landlock_inode_security {
    struct landlock_object *object;
};

Members

object

Weak pointer to an allocated object. All assignments of a new object are protected by the underlying inode->i_lock. However, atomically disassociating object from the inode is only protected by object->lock, from the time object’s usage refcount drops to zero to the time this pointer is nulled out (cf. release_inode() and hook_sb_delete()). Indeed, such disassociation doesn’t require inode->i_lock thanks to the careful rcu_access_pointer() check performed by get_inode_object().

Description

Enable to reference a struct landlock_object tied to an inode (i.e. underlying object).

struct landlock_file_security

File security blob

Definition:

struct landlock_file_security {
    access_mask_t allowed_access;
#ifdef CONFIG_SECURITY_LANDLOCK_LOG;
    deny_masks_t deny_masks;
    optional_access_t quiet_optional_accesses;
    u8 fown_layer;
#endif ;
    struct landlock_cred_security fown_subject;
    struct pid *fown_tg;
};

Members

allowed_access

Access rights that were available at the time of opening the file. This is not necessarily the full set of access rights available at that time, but it’s the necessary subset as needed to authorize later operations on the open file.

deny_masks

Domain layer levels that deny an optional access (see _LANDLOCK_ACCESS_FS_OPTIONAL).

quiet_optional_accesses

Stores which optional accesses are covered by quiet rules within the layer referred to in deny_masks, one access per bit. Does not take into account whether the quiet access bits are actually set in the layer’s corresponding landlock_hierarchy.

fown_layer

Layer level of fown_subject->domain with LANDLOCK_SCOPE_SIGNAL.

fown_subject

Landlock credential of the task that set the PID that may receive a signal e.g., SIGURG when writing MSG_OOB to the related socket. This pointer is protected by the related file->f_owner->lock, as for fown_struct’s members: pid, uid, and euid.

fown_tg

Thread group of the task that set the file owner, pinned while fown_subject holds a domain. It lets hook_file_send_sigiotask() always allow a SIGIO delivered to the owner’s own process -- e.g. the thread-group leader reached through a process-group owner -- matching the same-process exemption of hook_task_kill(). NULL when no domain is recorded. Protected by file->f_owner->lock, like fown_subject.

Description

This information is populated when opening a file in hook_file_open, and tracks the relevant Landlock access rights that were available at the time of opening the file. Other LSM hooks use these rights in order to authorize operations on already opened files.

struct landlock_superblock_security

Superblock security blob

Definition:

struct landlock_superblock_security {
    atomic_long_t inode_refs;
};

Members

inode_refs

Number of pending inodes (from this superblock) that are being released by release_inode(). Cf. struct super_block->s_fsnotify_inode_refs .

Description

Enable hook_sb_delete() to wait for concurrent calls to release_inode().

const char *resolve_path_for_trace(const struct path *path, char *buf)

Resolve a path for tracepoint display

Parameters

const struct path *path

The path to resolve.

char *buf

A buffer of at least PATH_MAX bytes for the resolved path.

Description

Uses d_absolute_path() to produce a namespace-independent absolute path, unlike d_path() which resolves relative to the process’s chroot. This ensures trace output is deterministic regardless of the tracer’s mount namespace.

Return

A pointer into buf with the resolved path, or an error string (“<too_long>”, “<unreachable>”).

Namespace

Capability

u64 landlock_cap_to_bit(const int cap)

Convert a capability number to a compact bitmask

Parameters

const int cap

Capability number (CAP_*).

Return

BIT_ULL(cap), or 0 if cap is invalid (with a WARN).

u64 landlock_caps_to_bits(const u64 capabilities)

Validate and mask a capability bitmask

Parameters

const u64 capabilities

Bitmask of capabilities (e.g. from user space).

Return

capabilities masked to known capabilities. Warns if unknown bits are present (callers must pre-mask for user input).

Process credential

struct landlock_cred_security

Credential security blob

Definition:

struct landlock_cred_security {
    struct landlock_domain *domain;
#ifdef CONFIG_SECURITY_LANDLOCK_LOG;
    u16 domain_exec;
    u8 log_subdomains_off : 1;
#endif ;
};

Members

domain

Immutable domain enforced on a task.

domain_exec

Bitmask identifying the domain layers that were enforced by the current task’s executed file (i.e. no new execve(2) since landlock_restrict_self(2)).

log_subdomains_off

Set if the domain descendants’s log_status should be set to LANDLOCK_LOG_DISABLED. This is not a landlock_hierarchy configuration because it applies to future descendant domains and it does not require a current domain.

Description

This structure is packed to minimize the size of struct landlock_file_security. However, it is always aligned in the LSM cred blob, see lsm_set_blob_size().

When updating this, also update landlock_cred_copy() if needed.

const struct landlock_cred_security *landlock_get_applicable_subject(const struct cred *const cred, const struct access_masks masks, size_t *const handle_layer)

Return the subject’s Landlock credential if its enforced domain applies to (i.e. handles) at least one of the access rights specified in masks

Parameters

const struct cred *const cred

credential

const struct access_masks masks

access masks

size_t *const handle_layer

returned youngest layer handling a subset of masks. Not set if the function returns NULL.

Return

landlock_cred(cred) if any access rights specified in masks is handled, or NULL otherwise.

Ruleset and domain

A domain is a read-only ruleset tied to a set of subjects (i.e. tasks’ credentials). Each time a ruleset is enforced on a task, the current domain is duplicated and the ruleset is imported as a new layer of rules in the new domain. Indeed, once in a domain, each rule is tied to a layer level. To grant access to an object, at least one rule of each layer must allow the requested action on the object. A task can then only transit to a new domain that is the intersection of the constraints from the current domain and those of a ruleset provided by the task.

The definition of a subject is implicit for a task sandboxing itself, which makes the reasoning much easier and helps avoid pitfalls.

struct landlock_layer

Access rights for a given layer

Definition:

struct landlock_layer {
    u8 level;
    struct {
        u8 quiet : 1;
    } flags;
    access_mask_t access;
};

Members

level

Position of this layer in the layer stack. Starts from 1.

flags

Bitfield for special flags attached to this rule.

flags.quiet

Suppresses denial logs for the object covered by this rule in this domain. For filesystem rules, this inherits down the file hierarchy.

access

Bitfield of allowed actions on the kernel object. They are relative to the object type (e.g. LANDLOCK_ACTION_FS_READ).

union landlock_key

Key of a ruleset’s red-black tree

Definition:

union landlock_key {
    struct landlock_object *object;
    uintptr_t data;
};

Members

object

Pointer to identify a kernel object (e.g. an inode).

data

Raw data to identify an arbitrary 32-bit value (e.g. a TCP port).

enum landlock_key_type

Type of union landlock_key

Constants

LANDLOCK_KEY_INODE

Type of landlock_rules.root_inode’s node keys.

LANDLOCK_KEY_NET_PORT

Type of landlock_rules.root_net_port’s node keys.

struct landlock_id

Unique rule identifier for a ruleset

Definition:

struct landlock_id {
    union landlock_key key;
    const enum landlock_key_type type;
};

Members

key

Identifies either a kernel object (e.g. an inode) or a raw value (e.g. a TCP port).

type

Type of a landlock_ruleset’s root tree.

struct landlock_rule

Access rights tied to an object

Definition:

struct landlock_rule {
    struct rb_node node;
    union landlock_key key;
    u32 num_layers;
    struct landlock_layer layers[];
};

Members

node

Node in the ruleset’s red-black tree.

key

A union to identify either a kernel object (e.g. an inode) or a raw data value (e.g. a network socket port). This is used as a key for this ruleset element. The pointer is set once and never modified. It always points to an allocated object because each rule increments the refcount of its object.

num_layers

Number of entries in layers.

layers

Stack of layers, from the latest to the newest, implemented as a flexible array member (FAM).

struct landlock_rules

Red-black tree storage for Landlock rules

Definition:

struct landlock_rules {
    struct rb_root root_inode;
#if IS_ENABLED(CONFIG_INET);
    struct rb_root root_net_port;
#endif ;
    u32 num_rules;
};

Members

root_inode

Root of a red-black tree containing struct landlock_rule nodes with inode object. Immutable for domains.

root_net_port

Root of a red-black tree containing struct landlock_rule nodes with network port. Immutable for domains.

num_rules

Number of non-overlapping (i.e. not for the same object) rules in this tree storage.

Description

This structure holds the rule trees shared by both rulesets and domains.

struct landlock_ruleset

Landlock ruleset

Definition:

struct landlock_ruleset {
    struct landlock_rules rules;
    struct mutex lock;
    refcount_t usage;
#ifdef CONFIG_TRACEPOINTS;
    u64 version;
    u64 id;
#endif ;
    struct access_masks quiet_access;
#ifdef CONFIG_SECURITY_LANDLOCK_LOG;
    struct permission_masks quiet_permission;
#endif ;
    struct layer_config layer;
};

Members

rules

Red-black tree storage for rules.

lock

Protects against concurrent modifications of rules, if usage is greater than zero.

usage

Number of file descriptors referencing this ruleset.

version

Counter incremented on each successful landlock_add_rule(2), including when it only extends an existing rule’s access rights. Used by tracepoints to correlate a domain with the exact successful rule history it was created from. Protected by lock.

id

Unique identifier for this ruleset, used for tracing.

quiet_access

Stores the quiet flags for an unmerged ruleset. For a merged domain, this is stored in each layer’s struct landlock_hierarchy instead. Its permissions member is unused because permission quieting is per member rather than per permission.

quiet_permission

Per-member quiet bitmasks for permission types in this ruleset. A denied member whose bit is set here is not submitted to audit when this layer denies it.

layer

Access configuration for this ruleset’s single mutable layer.

Description

This data structure must contain unique entries, be updatable, and quick to match an object.

struct rb_root *landlock_get_rule_root(struct landlock_rules *const rules, const enum landlock_key_type key_type)

Get the root of a rule tree by key type

Parameters

struct landlock_rules *const rules

The rules storage to look up.

const enum landlock_key_type key_type

The type of key to select the tree for.

Return

A pointer to the rb_root, or ERR_PTR(-EINVAL) on unknown type.

struct landlock_details

Domain’s creation information

Definition:

struct landlock_details {
    struct pid *pid;
    uid_t uid;
    char comm[TASK_COMM_LEN];
    char exe_path[];
};

Members

pid

PID of the task that initially restricted itself. It still identifies the same task. Keeping a reference to this PID ensures that it will not be recycled.

uid

UID of the task that initially restricted itself, at creation time.

comm

Command line of the task that initially restricted itself, at creation time. Always NULL terminated.

exe_path

Executable path of the task that initially restricted itself, at creation time. Always NULL terminated, and never greater than LANDLOCK_PATH_MAX_SIZE.

Description

Rarely accessed, mainly when logging the first domain’s denial.

The contained pointers are initialized at the domain creation time and never changed again.

struct landlock_hierarchy

Node in a domain hierarchy

Definition:

struct landlock_hierarchy {
    struct landlock_hierarchy *parent;
    refcount_t usage;
#ifdef CONFIG_SECURITY_LANDLOCK_LOG;
    enum landlock_log_status log_status;
    atomic64_t num_denials;
    u64 id;
    const struct landlock_details *details;
    u32 log_same_exec : 1, log_new_exec : 1;
    struct access_masks quiet_access;
    struct permission_masks quiet_permission;
#endif ;
};

Members

parent

Pointer to the parent node, or NULL if it is a root Landlock domain.

usage

Number of potential children domains plus their parent domain.

log_status

Whether this domain should be logged or not. Because concurrent log entries may be created at the same time, it is still possible to have several domain records of the same domain.

num_denials

Number of access requests denied by this domain. Masked (i.e. never logged) denials are still counted.

id

Landlock domain ID, set once at domain creation time.

details

Information about the related domain.

log_same_exec

Set if the domain is not configured with LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF. Set to true by default.

log_new_exec

Set if the domain is configured with LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON. Set to false by default.

quiet_access

Bitmasks of access that should be quieted (i.e. not logged) if the related object is marked as quiet.

quiet_permission

Per-member quiet bitmasks for permission types in this layer.

struct landlock_domain

Immutable Landlock domain

Definition:

struct landlock_domain {
    struct landlock_rules rules;
    struct landlock_hierarchy *hierarchy;
    union {
        struct work_struct work_free;
        struct {
            refcount_t usage;
            u32 num_layers;
            struct layer_config layers[];
        };
    };
};

Members

rules

Red-black tree storage for rules.

hierarchy

Enables hierarchy identification even when a parent domain vanishes. This is needed for the ptrace and scope restrictions.

{unnamed_union}

anonymous

work_free

Enables to free a domain within a lockless section. This is only used by landlock_put_domain_deferred() when usage reaches zero. The fields usage, num_layers and layers are then unused.

{unnamed_struct}

anonymous

usage

Number of credentials referencing this domain.

num_layers

Number of layers that are used in this domain. This enables to check that all the layers allow an access request.

layers

Per-layer access configuration. A domain saves all layers of merged rulesets in a stack (FAM), starting from the first layer to the last one. These layers are used when merging rulesets, for user space backward compatibility (i.e. future-proof), and to properly handle merged rulesets without overlapping access rights. These layers are set once and never changed for the lifetime of the domain.

Not annotated with __counted_by(num_layers): clang miscomputes the counter address for a FAM nested in an anonymous struct within a union, which trips FORTIFY: https://github.com/llvm/llvm-project/pull/228309

Description

A domain is created from a ruleset by landlock_merge_ruleset() and enforced on a task. Once created, its rules and access masks are immutable. Unlike struct landlock_ruleset, a domain has no lock field.

struct access_masks landlock_union_access_masks(const struct landlock_domain *const domain)

Return all access rights handled in the domain

Parameters

const struct landlock_domain *const domain

Landlock domain

Return

An access_masks result of the OR of all the domain’s access masks.

size_t landlock_permission_is_denied(const struct landlock_domain *const domain, const access_mask_t permission_bit, const u64 request_value)

Check if a permission request is denied

Parameters

const struct landlock_domain *const domain

The enforced domain.

const access_mask_t permission_bit

The LANDLOCK_PERMISSION_* flag to check. Must have exactly one bit set.

const u64 request_value

Compact bitmask to look for (e.g. the result of landlock_ns_type_to_bit()). Must have exactly one bit set.

Description

Iterate from the youngest layer to the oldest. For each layer that handles permission_bit, check whether request_value is present in the layer’s allowed bitmask. Return on the first (youngest) denying layer.

Return

The youngest denying layer + 1, or 0 if allowed.

Denial logging

Access denials are logged through two independent channels: audit records and tracepoints. Both are managed by the common denial framework in log.c, compiled under CONFIG_SECURITY_LANDLOCK_LOG (automatically selected by CONFIG_AUDIT or CONFIG_TRACEPOINTS).

Audit records respect audit configuration, the domain’s Landlock log flags, and LANDLOCK_LOG_DISABLED. Tracepoints fire unconditionally, independent of these settings. The denial counter (num_denials) is always incremented regardless of logging configuration.

Each denial tracepoint carries a logged field reporting the audit-logging verdict: whether the denial would be written to the audit log if audit were configured and active. This verdict is the same whether or not the kernel is built with audit support, so a tracepoints-only build reports the selection audit would make. A quiet rule (LANDLOCK_ADD_RULE_QUIET with the access in the quiet_* fields of struct landlock_ruleset_attr) suppresses logging by setting logged=0 the same way, as do the per-member quiet_* masks of capability and namespace rules.

See Landlock: system-wide management for audit record format, tracepoint usage, and filtering examples.

Trace events

See Landlock Trace Events for trace event usage and format details; the full event reference lives there and is not duplicated here.

Additional documentation