LANDLOCK TRACE EVENTS(9)
π Landlock trace events
okay so bestie, welcome to Landlock trace events(9) β yes, the kernel API manual, section 9 β and it's literally the rules that every Landlock tracepoint has to follow. A new tracepoint must uphold these guarantees and constraints, and an eBPF consumer can 100% rely on them. no cap. π«Ά
πΈ Decision context
A denial event tells you which domain's policy denied the request, which Landlock operation and policy object got checked, and which blocker or domain relationship is responsible for the denial. When tracing starts with sandbox construction, ruleset and domain events give you the policy history you need to interpret those identifiers. The denying domain is the subject that enforced the policy β it is not necessarily current, bestie. Generic tracepoints can provide extra operational context too.
π¦ Lifecycle consistency
Lifecycle emission is balanced: a creation event always has a matching deallocation event, and vice versa. If a consumer observes an object's complete lifetime, it can model that object from this pair; a consumer that attaches late or loses exported records has to reconcile incomplete state. π
A creation event fires while the object is still private to the calling thread β landlock_create_ruleset fires before the ruleset's file descriptor is installed, so it cannot race a concurrent close(2). If fd installation later fails and the ruleset is freed, free_ruleset still fires, keeping the pair balanced. π
The domain pair (create_domain and free_domain) is balanced the same way: create_domain fires when the domain is created (under the ruleset lock, before thread-sync), and free_domain fires when it is freed. A rare thread-sync failure aborts the just-created domain, which then emits both events β its creation, then an immediate free. Denial events fire only for denials that actually happen. periodt. β¨
π§ Pointer access
All pointer arguments in TP_PROTO are guaranteed non-NULL by the caller, but pointers reached through them may still be NULL (e.g. hierarchy->parent at a root domain) and must be checked. eBPF programs read these pointers via BTF for richer introspection than the TP_STRUCT__entry fields, which serve TP_printk display only.
Mutable object pointers are passed while the caller holds the object's lock, so TP_fast_assign and a BTF reader see the exact object the event reports β a snapshot no concurrent writer can change. add_rule holds the modified ruleset's lock, and create_domain holds the ruleset lock across the emission (before the thread-sync wait) so the inspected ruleset is the one merged into the domain. Objects that are immutable at the emission site (a domain after creation, a hierarchy at its last reference) need no lock. π
A few values that no held lock protects are a best-effort lockless snapshot instead: a task's comm, and the deny_access_net struct sock (whose network hook holds no socket lock), matching how the sched and signal trace events sample comm. lowkey important, don't forget it. π
π Field encoding
Fields that mirror the Landlock UAPI preserve their widths and endianness (e.g. network ports are u64 in host endianness, like landlock_net_port_attr.port). Per-event details, such as where a value is byte-swapped, live in the field's own kdoc. iykyk. π
π Rule-check fields
The check_rule events fire during an access check, once per matching rule, before the final allow-or-deny verdict. They share domain (the enforcing domain being evaluated), access_request (the access mask being checked), and rule (the matching rule, with per-layer access masks).
π₯ Denial fields
Every denial event shares three fields. domain is the ID of the innermost domain that blocked the access. same_exec tells whether the current task is the same executable that entered that domain. logged is the domain's audit-logging decision for this denial (its log_status is enabled and the per-execution flag selected by same_exec is set); a stateless ftrace filter can select the denials the domain submits to audit with logged==1, without reconstructing it from the per-execution log flags. π
Denial events order their fields as domain, same_exec, logged, then blockers (deny_access events only), then the type-specific object fields, then any variable-length field.
π Relational referents
A scope or ptrace verdict compares two domains, so the other party's domain is part of the decision context. It is exposed as a scalar domain ID (0 when that party is unsandboxed): target_domain (signal), peer_domain (abstract unix socket), tracee_domain (ptrace). With both IDs in the stream, a consumer that tracked domain creation can relate the two parties without kernel-internal state.
The ID is a scalar snapshot, not a live domain pointer that could dangle: an optional relational referent is a scalar (0 sentinel), not a nullable pointer. Nonzero IDs are unique within one boot. For ptrace, same_exec instead describes the tracer, even for PTRACE_TRACEME, and may differ from the current task. π§ β¨
π Blocker fields
The filesystem and network blocker arguments identify the request type and carry its final missing access subset when applicable. The type determines how to interpret the access value.
π SEE ALSO
Kernel file: ./include/trace/events/landlock.h
trace_landlock_create_ruleset(9)trace_landlock_free_ruleset(9)trace_landlock_add_rule_path_beneath(9)trace_landlock_add_rule_net_port(9)trace_landlock_create_domain(9)trace_landlock_enforce_domain(9)trace_landlock_free_domain(9)trace_landlock_check_rule_inode(9)trace_landlock_check_rule_net_port(9)trace_landlock_deny_access_fs(9)trace_landlock_deny_access_net(9)trace_landlock_deny_ptrace(9)trace_landlock_deny_scope_signal(9)trace_landlock_deny_scope_abstract_unix_socket(9)
mwah π bestie, this page's source/version is ./include/trace/events and it's dated October 2026 β that's the cute little footer, and now you're all caught up. go trace something iconic! π
β¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms