<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux-stable.git/security/landlock, branch master</title>
<subtitle>Linux kernel stable tree</subtitle>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/'/>
<entry>
<title>landlock: Add tracepoints for ptrace and scope denials</title>
<updated>2026-08-17T08:17:16+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=bb91730f16c064f4eb0dc15ed27814c8f9aef670'/>
<id>bb91730f16c064f4eb0dc15ed27814c8f9aef670</id>
<content type='text'>
Scope and ptrace denials follow a different code path (a domain
hierarchy check) than access-right denials, so they need dedicated
tracepoints with type-specific TP_PROTO arguments.  Complete the denial
coverage with:
- landlock_deny_ptrace: ptrace access denied by a domain hierarchy
  mismatch.
- landlock_deny_scope_signal: signal delivery denied by
  LANDLOCK_SCOPE_SIGNAL.
- landlock_deny_scope_abstract_unix_socket: abstract unix socket access
  denied by LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET.

TP_PROTO passes the raw kernel object (struct task_struct or struct
sock) for eBPF BTF access; the comm and sun_path string fields use
__print_untrusted_str() because they hold untrusted input.  Unlike the
deny_access events, these omit the blockers field: each maps to exactly
one denial type named by the event, so the bitmask would always be zero.
Like the deny_access events they carry same_exec and logged.

Audit logs the task-targeted denials with generic field names (opid,
ocomm), but a strongly typed trace event can use role-prefixed names
(tracee_pid/tracee_comm, target_pid/target_comm) that match the mainline
task-name convention (sched_process_fork's parent_comm/child_comm) and
say whose name each field holds; a bare comm= would collide across
events.  The abstract-unix-socket event reports peer_pid instead, a
tracepoint-only field with no audit counterpart.

A scope or ptrace verdict compares the subject domain against the other
party's domain, so each event also reports that other party's Landlock
domain (tracee_domain=, target_domain=, or peer_domain=); the subject
domain= alone does not let a consumer redo domain_is_scoped() or
domain_ptrace().  It is reported as a scalar ID rather than a domain
pointer: a domain object is immutable, but the other task can replace
its credential and free the domain that credential referenced, so a
stored foreign pointer could dangle before the event is consumed.  The
scalar ID also honors the tracepoint no-nullable-pointer rule, since the
other party is frequently unsandboxed.  Passing the foreign domain
hierarchy object so an eBPF consumer could walk the other party's
ancestry live would lengthen the RCU section on the shared denial path
and needs a deferred refcount put, so it is left as a future
enhancement.  The relational domain-ID field (tracee_domain,
target_domain, or peer_domain) is trace-only and is not added to audit
records, so audit's denial format is unchanged by this series.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-14-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Scope and ptrace denials follow a different code path (a domain
hierarchy check) than access-right denials, so they need dedicated
tracepoints with type-specific TP_PROTO arguments.  Complete the denial
coverage with:
- landlock_deny_ptrace: ptrace access denied by a domain hierarchy
  mismatch.
- landlock_deny_scope_signal: signal delivery denied by
  LANDLOCK_SCOPE_SIGNAL.
- landlock_deny_scope_abstract_unix_socket: abstract unix socket access
  denied by LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET.

TP_PROTO passes the raw kernel object (struct task_struct or struct
sock) for eBPF BTF access; the comm and sun_path string fields use
__print_untrusted_str() because they hold untrusted input.  Unlike the
deny_access events, these omit the blockers field: each maps to exactly
one denial type named by the event, so the bitmask would always be zero.
Like the deny_access events they carry same_exec and logged.

Audit logs the task-targeted denials with generic field names (opid,
ocomm), but a strongly typed trace event can use role-prefixed names
(tracee_pid/tracee_comm, target_pid/target_comm) that match the mainline
task-name convention (sched_process_fork's parent_comm/child_comm) and
say whose name each field holds; a bare comm= would collide across
events.  The abstract-unix-socket event reports peer_pid instead, a
tracepoint-only field with no audit counterpart.

A scope or ptrace verdict compares the subject domain against the other
party's domain, so each event also reports that other party's Landlock
domain (tracee_domain=, target_domain=, or peer_domain=); the subject
domain= alone does not let a consumer redo domain_is_scoped() or
domain_ptrace().  It is reported as a scalar ID rather than a domain
pointer: a domain object is immutable, but the other task can replace
its credential and free the domain that credential referenced, so a
stored foreign pointer could dangle before the event is consumed.  The
scalar ID also honors the tracepoint no-nullable-pointer rule, since the
other party is frequently unsandboxed.  Passing the foreign domain
hierarchy object so an eBPF consumer could walk the other party's
ancestry live would lengthen the RCU section on the shared denial path
and needs a deferred refcount put, so it is left as a future
enhancement.  The relational domain-ID field (tracee_domain,
target_domain, or peer_domain) is trace-only and is not added to audit
records, so audit's denial format is unchanged by this series.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-14-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add landlock_deny_access_fs and landlock_deny_access_net</title>
<updated>2026-08-17T08:17:16+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=01ce260f5ccf0fe7e38d2fd548e776f594409cf6'/>
<id>01ce260f5ccf0fe7e38d2fd548e776f594409cf6</id>
<content type='text'>
Add per-type tracepoints emitted from landlock_log_denial() when an
access is denied: landlock_deny_access_fs for filesystem denials and
landlock_deny_access_net for network denials.  They use the "deny_"
prefix (rather than "check_") to mark that they fire only on a denial,
and they complement the check_rule events by making the
denial-by-absence case explicit (when no rule matches, no check_rule
event fires).

Unlike the audit records, these events fire regardless of the audit
configuration and the domain's log flags: the user's "disable logging"
intent applies to audit records, not to kernel tracing.  The logged
field records whether the domain's log policy would submit the denial to
audit; it is the decision computed once by landlock_log_denial() and
passed to both the audit and the tracing emitter, so a stateless ftrace
filter can select the audit-visible denials with logged==1.

TP_PROTO passes the denying hierarchy node, not the task's current
domain, so domain_id reports the specific node that blocked the access,
matching audit record semantics. (check_rule instead passes the current
domain, which it needs to size its per-layer array.) same_exec is also
passed explicitly because it is computed from the credential bitmask and
is not derivable from the hierarchy pointer alone.  The denial field is
named blockers to match the audit record field.

The filesystem path comes from the request's audit data.  Its type
selects which union member holds the object, exactly as
dump_common_audit_data() selects it (a path, a file's path, an ioctl
op's path, or a bare dentry); reading the wrong member would dereference
garbage, so every reachable type has an explicit case and an unexpected
one is flagged with WARN_ONCE() instead of misread.  Path-backed types
resolve via d_absolute_path() (as landlock_add_rule_fs does) and the
bare-dentry case via dentry_path_raw().

The inode number is read defensively.  A filesystem denial can carry a
negative dentry (no backing inode), for example a denied creation, so
the event mirrors the guard in dump_common_audit_data() and reports
inode 0 rather than dereferencing a NULL inode.  The sibling fs
tracepoints do not need the guard: a dentry that matches a rule during
an access check, or one opened to add a rule, always has a backing
inode.  Landlock tracepoints are reachable by unprivileged sandboxees,
so a denial on a negative dentry with the event enabled must not fault
the kernel.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-13-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add per-type tracepoints emitted from landlock_log_denial() when an
access is denied: landlock_deny_access_fs for filesystem denials and
landlock_deny_access_net for network denials.  They use the "deny_"
prefix (rather than "check_") to mark that they fire only on a denial,
and they complement the check_rule events by making the
denial-by-absence case explicit (when no rule matches, no check_rule
event fires).

Unlike the audit records, these events fire regardless of the audit
configuration and the domain's log flags: the user's "disable logging"
intent applies to audit records, not to kernel tracing.  The logged
field records whether the domain's log policy would submit the denial to
audit; it is the decision computed once by landlock_log_denial() and
passed to both the audit and the tracing emitter, so a stateless ftrace
filter can select the audit-visible denials with logged==1.

TP_PROTO passes the denying hierarchy node, not the task's current
domain, so domain_id reports the specific node that blocked the access,
matching audit record semantics. (check_rule instead passes the current
domain, which it needs to size its per-layer array.) same_exec is also
passed explicitly because it is computed from the credential bitmask and
is not derivable from the hierarchy pointer alone.  The denial field is
named blockers to match the audit record field.

The filesystem path comes from the request's audit data.  Its type
selects which union member holds the object, exactly as
dump_common_audit_data() selects it (a path, a file's path, an ioctl
op's path, or a bare dentry); reading the wrong member would dereference
garbage, so every reachable type has an explicit case and an unexpected
one is flagged with WARN_ONCE() instead of misread.  Path-backed types
resolve via d_absolute_path() (as landlock_add_rule_fs does) and the
bare-dentry case via dentry_path_raw().

The inode number is read defensively.  A filesystem denial can carry a
negative dentry (no backing inode), for example a denied creation, so
the event mirrors the guard in dump_common_audit_data() and reports
inode 0 rather than dereferencing a NULL inode.  The sibling fs
tracepoints do not need the guard: a dentry that matches a rule during
an access check, or one opened to add a rule, always has a backing
inode.  Landlock tracepoints are reachable by unprivileged sandboxees,
so a denial on a negative dentry with the event enabled must not fault
the kernel.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-13-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add tracepoints for rule checking</title>
<updated>2026-08-17T08:17:15+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=3f1f106e4c14071ad8cb8ae6775d2d11780a7d01'/>
<id>3f1f106e4c14071ad8cb8ae6775d2d11780a7d01</id>
<content type='text'>
Merge landlock_find_rule() into landlock_unmask_layers() so rule
pointers stay inside the domain implementation while unmask checking
gets the matched rule it needs for the check_rule tracepoint.
landlock_unmask_layers() now takes a landlock_id and the domain instead
of a rule pointer.  A rename or link evaluates the same dentry against
both renamed parents, so this path now looks the rule up once per
parent; collapsing that back to a single lookup is left to a follow-up.

Emit, via the per-type wrappers unmask_layers_fs() and
unmask_layers_net(), the rights each matching rule grants at every
domain layer.  The events carry this as a dynamic per-layer array (up to
LANDLOCK_MAX_NUM_LAYERS entries) reserved from the trace ring buffer,
not the caller's stack, and rendered symbolically per layer.  A
WARN_ON_ONCE() in __trace_landlock_fill_layers() flags a rule whose
layer levels fall outside the domain range or are unsorted, a
cannot-happen case; the zero-filled slots keep the rendered output and
the array bounds safe regardless.

Setting allowed_parent2 to true for non-dom-check requests when
get_inode_id() returns false preserves the pre-refactoring behavior: a
negative dentry (no backing inode) has no matching rule, so the access
is allowed at this path component.  Before the refactoring,
landlock_unmask_layers() with a NULL rule produced this result as a side
effect; now the caller must set it explicitly.

Name the trace-only check_rule fields so each printk label equals its
ring-buffer field name and works directly as an ftrace filter: the
request field is labelled access_request= and the per-layer array is
named grants.  Values audit also logs keep audit's label (domain=,
ruleset=) so a single filter works across trace and audit.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-12-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Merge landlock_find_rule() into landlock_unmask_layers() so rule
pointers stay inside the domain implementation while unmask checking
gets the matched rule it needs for the check_rule tracepoint.
landlock_unmask_layers() now takes a landlock_id and the domain instead
of a rule pointer.  A rename or link evaluates the same dentry against
both renamed parents, so this path now looks the rule up once per
parent; collapsing that back to a single lookup is left to a follow-up.

Emit, via the per-type wrappers unmask_layers_fs() and
unmask_layers_net(), the rights each matching rule grants at every
domain layer.  The events carry this as a dynamic per-layer array (up to
LANDLOCK_MAX_NUM_LAYERS entries) reserved from the trace ring buffer,
not the caller's stack, and rendered symbolically per layer.  A
WARN_ON_ONCE() in __trace_landlock_fill_layers() flags a rule whose
layer levels fall outside the domain range or are unsorted, a
cannot-happen case; the zero-filled slots keep the rendered output and
the array bounds safe regardless.

Setting allowed_parent2 to true for non-dom-check requests when
get_inode_id() returns false preserves the pre-refactoring behavior: a
negative dentry (no backing inode) has no matching rule, so the access
is allowed at this path component.  Before the refactoring,
landlock_unmask_layers() with a NULL rule produced this result as a side
effect; now the caller must set it explicitly.

Name the trace-only check_rule fields so each printk label equals its
ring-buffer field name and works directly as an ftrace filter: the
request field is labelled access_request= and the per-layer array is
named grants.  Values audit also logs keep audit's label (domain=,
ruleset=) so a single filter works across trace and audit.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-12-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add landlock_enforce_domain tracepoint</title>
<updated>2026-08-17T08:17:15+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=132d84b16b5fe729fd228b169fa9e55f3e56b7af'/>
<id>132d84b16b5fe729fd228b169fa9e55f3e56b7af</id>
<content type='text'>
The landlock_create_domain event records that a domain was created,
once, before thread-sync.  It cannot tell which threads end up enforcing
it: a successful landlock_restrict_self(2) with
LANDLOCK_RESTRICT_SELF_TSYNC applies the domain to the caller and every
eligible sibling.  Creation (the operation) and enforcement (the
per-thread outcome) are distinct.

Add landlock_enforce_domain(domain, complete, process_wide), emitted
once per thread the domain is applied to, strictly after that thread's
commit_creds(), so it fires only for a thread that is enforcing the
domain, never speculatively; an aborted operation emits none.  The
lifecycle now reads create -&gt; enforce* -&gt; free.

The two booleans name properties, not the implementation:
- complete: marks the single event that concludes the operation.  It
  names the outcome, the set is now enforced, not which thread
  finishes, which the contract leaves unspecified.
- process_wide: means every eligible thread of the process is
  covered.  It is set race-free by either establishing path,
  thread-sync or a single-threaded process, so
  complete &amp;&amp; process_wide is the whole-process-enforced guarantee.

The requesting thread and source ruleset are not repeated here: they are
on create_domain (joined via domain-&gt;hierarchy-&gt;id) and on the immutable
domain-&gt;hierarchy-&gt;details.  Source ruleset means the ruleset_id and
ruleset_version recorded on create_domain, not the ruleset object, which
the caller may close before enforcement.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-11-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The landlock_create_domain event records that a domain was created,
once, before thread-sync.  It cannot tell which threads end up enforcing
it: a successful landlock_restrict_self(2) with
LANDLOCK_RESTRICT_SELF_TSYNC applies the domain to the caller and every
eligible sibling.  Creation (the operation) and enforcement (the
per-thread outcome) are distinct.

Add landlock_enforce_domain(domain, complete, process_wide), emitted
once per thread the domain is applied to, strictly after that thread's
commit_creds(), so it fires only for a thread that is enforcing the
domain, never speculatively; an aborted operation emits none.  The
lifecycle now reads create -&gt; enforce* -&gt; free.

The two booleans name properties, not the implementation:
- complete: marks the single event that concludes the operation.  It
  names the outcome, the set is now enforced, not which thread
  finishes, which the contract leaves unspecified.
- process_wide: means every eligible thread of the process is
  covered.  It is set race-free by either establishing path,
  thread-sync or a single-threaded process, so
  complete &amp;&amp; process_wide is the whole-process-enforced guarantee.

The requesting thread and source ruleset are not repeated here: they are
on create_domain (joined via domain-&gt;hierarchy-&gt;id) and on the immutable
domain-&gt;hierarchy-&gt;details.  Source ruleset means the ruleset_id and
ruleset_version recorded on create_domain, not the ruleset object, which
the caller may close before enforcement.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-11-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add create_domain and free_domain tracepoints</title>
<updated>2026-08-17T08:17:14+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=67567f03a4bf75905684b333f518da8c21f58514'/>
<id>67567f03a4bf75905684b333f518da8c21f58514</id>
<content type='text'>
Add a landlock_create_domain tracepoint emitted from
landlock_restrict_self() after the new domain is created, so a consumer
can correlate the source ruleset with the resulting domain.  The
flags-only path (ruleset_fd == -1) creates no domain and emits no event.

Move the ruleset lock acquisition from landlock_merge_ruleset() to the
caller so the lock is held across both the merge and the tracepoint
emission, giving an eBPF program a consistent ruleset snapshot.  Release
it before the thread-sync: holding ruleset-&gt;lock across
landlock_restrict_sibling_threads() would deadlock a sibling blocked on
the same lock.  The event therefore fires before the (rare) thread-sync
failure path; when that path aborts the just-created domain, the
matching free_domain event fires so the create/free pair stays balanced.

Add a landlock_free_domain tracepoint that fires when a domain's
hierarchy node is freed.  The hierarchy node is the lifecycle boundary
because it represents the domain's identity and outlives the domain's
access masks, which may still be active in descendant domains.

A domain freed without ever being committed to a credential was never
visible to user space, so free_domain is suppressed for it.  This is
tracked by a new landlock_log_status value, LANDLOCK_LOG_UNCOMMITTED,
which is also the zero value so a hierarchy whose initialization failed
defaults to not observable.  A hierarchy is born UNCOMMITTED and is
promoted to LANDLOCK_LOG_PENDING (or LANDLOCK_LOG_DISABLED when logging
is off) right after its create_domain event fires; a thread-sync failure
does not reset it, so an aborted domain that already emitted
create_domain still emits the matching free_domain.  Promoting right
after the event, rather than at commit_creds() time, avoids a race: on a
successful thread-sync the sibling threads commit the new domain in
lockstep before landlock_restrict_self() returns, so the shared domain
may already have moved to LANDLOCK_LOG_RECORDED through a plain store,
and a late promotion would race that store and could unbalance the
domain allocation and deallocation audit records.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-10-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add a landlock_create_domain tracepoint emitted from
landlock_restrict_self() after the new domain is created, so a consumer
can correlate the source ruleset with the resulting domain.  The
flags-only path (ruleset_fd == -1) creates no domain and emits no event.

Move the ruleset lock acquisition from landlock_merge_ruleset() to the
caller so the lock is held across both the merge and the tracepoint
emission, giving an eBPF program a consistent ruleset snapshot.  Release
it before the thread-sync: holding ruleset-&gt;lock across
landlock_restrict_sibling_threads() would deadlock a sibling blocked on
the same lock.  The event therefore fires before the (rare) thread-sync
failure path; when that path aborts the just-created domain, the
matching free_domain event fires so the create/free pair stays balanced.

Add a landlock_free_domain tracepoint that fires when a domain's
hierarchy node is freed.  The hierarchy node is the lifecycle boundary
because it represents the domain's identity and outlives the domain's
access masks, which may still be active in descendant domains.

A domain freed without ever being committed to a credential was never
visible to user space, so free_domain is suppressed for it.  This is
tracked by a new landlock_log_status value, LANDLOCK_LOG_UNCOMMITTED,
which is also the zero value so a hierarchy whose initialization failed
defaults to not observable.  A hierarchy is born UNCOMMITTED and is
promoted to LANDLOCK_LOG_PENDING (or LANDLOCK_LOG_DISABLED when logging
is off) right after its create_domain event fires; a thread-sync failure
does not reset it, so an aborted domain that already emitted
create_domain still emits the matching free_domain.  Promoting right
after the event, rather than at commit_creds() time, avoids a race: on a
successful thread-sync the sibling threads commit the new domain in
lockstep before landlock_restrict_self() returns, so the shared domain
may already have moved to LANDLOCK_LOG_RECORDED through a plain store,
and a late promotion would race that store and could unbalance the
domain allocation and deallocation audit records.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-10-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add landlock_add_rule_fs and landlock_add_rule_net tracepoints</title>
<updated>2026-08-17T08:17:14+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:22+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=63747c94774d4a5a0a9d9e739da0df29937aebea'/>
<id>63747c94774d4a5a0a9d9e739da0df29937aebea</id>
<content type='text'>
Add tracepoints for Landlock rule addition, landlock_add_rule_fs for
filesystem rules and landlock_add_rule_net for network rules, so trace
consumers can correlate filesystem objects and network ports with their
rulesets.  Both are emitted under the ruleset lock (asserted in
TP_fast_assign) so an eBPF program reads the ruleset, including the rule
just inserted, in a consistent snapshot.

Add a version field to struct landlock_ruleset, gated on
CONFIG_TRACEPOINTS like the id field and incremented under the ruleset
lock on each successful landlock_add_rule(2), including when it only
extends an existing rule's access rights.  It fills the existing 4-byte
hole after usage, so the struct does not grow.  Pairing the ruleset ID
with the version lets a later restrict_self event record the exact
ruleset revision merged into a domain.

Resolve the filesystem rule's absolute path with d_absolute_path()
rather than the d_path() audit uses: d_absolute_path() produces
namespace-independent paths that do not depend on the tracer's chroot
state, making trace output deterministic regardless of mount namespace
configuration.  Distinguish the error cases as "&lt;too_long&gt;"
(-ENAMETOOLONG) and "&lt;unreachable&gt;" (anonymous files or detached
mounts).

Also add __trace_print_untrusted_str(), a static inline helper in the
header guarded by CREATE_TRACE_POINTS: it escapes separators, quotes,
backslashes, and non-printable bytes via string_escape_mem() so an
untrusted string (the path here, process names in later denial events)
cannot inject field separators or control characters into the ftrace
text output.

Cc: Christian Brauner &lt;brauner@kernel.org&gt;
Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-9-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add tracepoints for Landlock rule addition, landlock_add_rule_fs for
filesystem rules and landlock_add_rule_net for network rules, so trace
consumers can correlate filesystem objects and network ports with their
rulesets.  Both are emitted under the ruleset lock (asserted in
TP_fast_assign) so an eBPF program reads the ruleset, including the rule
just inserted, in a consistent snapshot.

Add a version field to struct landlock_ruleset, gated on
CONFIG_TRACEPOINTS like the id field and incremented under the ruleset
lock on each successful landlock_add_rule(2), including when it only
extends an existing rule's access rights.  It fills the existing 4-byte
hole after usage, so the struct does not grow.  Pairing the ruleset ID
with the version lets a later restrict_self event record the exact
ruleset revision merged into a domain.

Resolve the filesystem rule's absolute path with d_absolute_path()
rather than the d_path() audit uses: d_absolute_path() produces
namespace-independent paths that do not depend on the tracer's chroot
state, making trace output deterministic regardless of mount namespace
configuration.  Distinguish the error cases as "&lt;too_long&gt;"
(-ENAMETOOLONG) and "&lt;unreachable&gt;" (anonymous files or detached
mounts).

Also add __trace_print_untrusted_str(), a static inline helper in the
header guarded by CREATE_TRACE_POINTS: it escapes separators, quotes,
backslashes, and non-printable bytes via string_escape_mem() so an
untrusted string (the path here, process names in later denial events)
cannot inject field separators or control characters into the ftrace
text output.

Cc: Christian Brauner &lt;brauner@kernel.org&gt;
Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-9-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Add create_ruleset and free_ruleset tracepoints</title>
<updated>2026-08-17T08:17:13+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=b4540a72be4138a97c7cb74f803e57a7350a55ec'/>
<id>b4540a72be4138a97c7cb74f803e57a7350a55ec</id>
<content type='text'>
Add the first Landlock tracepoints, for ruleset lifecycle:
landlock_create_ruleset fires from the landlock_create_ruleset() syscall
handler, and landlock_free_ruleset fires in free_ruleset() before the
ruleset is freed.

These tracepoints, and the ones added by the following commits, share a
common design.  Rather than one polymorphic event distinguished by a
status field (as audit uses a shared record type with a "status="
field), each lifecycle transition and denial type gets its own event
with a type-safe TP_PROTO, giving precise ftrace filtering by event name
and type-safe eBPF access.  TP_PROTO passes the object pointer and the
fields are read from it in TP_fast_assign, so an eBPF program reads the
full object state (rules, access masks, hierarchy) via BTF from a single
pointer rather than from the flattened TP_STRUCT__entry fields.  The
whole cost is paid only when a tracer is attached; the static branch is
not taken otherwise.  Trace fields carry the bare access-right and scope
names (read_file), reusing the audit name tables; audit prepends the
category (fs.read_file), which the trace event name already conveys.
The trace header's DOC comment documents the consistency and locking
guarantees these events share.

create_ruleset needs no lock because the ruleset is not yet shared (its
file descriptor is not yet installed).  The deallocation events use the
"free_" prefix, not "drop_", because they fire when the object is
actually freed.

Add trace.c, built for CONFIG_TRACEPOINTS, which defines
CREATE_TRACE_POINTS, and extend CONFIG_SECURITY_LANDLOCK_LOG to also be
selected by CONFIG_TRACEPOINTS so the common log framework is available
to a tracepoints-only build.

Add an id field to struct landlock_ruleset, gated on CONFIG_TRACEPOINTS
and assigned from landlock_get_id_range() at creation.  Only the
tracepoints consume it (audit identifies domains, not rulesets), so it
does not exist in an audit-only build.  The Landlock ID is a stable u64
that names the ruleset across the trace stream and uses the same scheme
as audit, so a ruleset can be correlated between trace and audit
records.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-8-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add the first Landlock tracepoints, for ruleset lifecycle:
landlock_create_ruleset fires from the landlock_create_ruleset() syscall
handler, and landlock_free_ruleset fires in free_ruleset() before the
ruleset is freed.

These tracepoints, and the ones added by the following commits, share a
common design.  Rather than one polymorphic event distinguished by a
status field (as audit uses a shared record type with a "status="
field), each lifecycle transition and denial type gets its own event
with a type-safe TP_PROTO, giving precise ftrace filtering by event name
and type-safe eBPF access.  TP_PROTO passes the object pointer and the
fields are read from it in TP_fast_assign, so an eBPF program reads the
full object state (rules, access masks, hierarchy) via BTF from a single
pointer rather than from the flattened TP_STRUCT__entry fields.  The
whole cost is paid only when a tracer is attached; the static branch is
not taken otherwise.  Trace fields carry the bare access-right and scope
names (read_file), reusing the audit name tables; audit prepends the
category (fs.read_file), which the trace event name already conveys.
The trace header's DOC comment documents the consistency and locking
guarantees these events share.

create_ruleset needs no lock because the ruleset is not yet shared (its
file descriptor is not yet installed).  The deallocation events use the
"free_" prefix, not "drop_", because they fire when the object is
actually freed.

Add trace.c, built for CONFIG_TRACEPOINTS, which defines
CREATE_TRACE_POINTS, and extend CONFIG_SECURITY_LANDLOCK_LOG to also be
selected by CONFIG_TRACEPOINTS so the common log framework is available
to a tracepoints-only build.

Add an id field to struct landlock_ruleset, gated on CONFIG_TRACEPOINTS
and assigned from landlock_get_id_range() at creation.  Only the
tracepoints consume it (audit identifies domains, not rulesets), so it
does not exist in an audit-only build.  The Landlock ID is a stable u64
that names the ruleset across the trace stream and uses the same scheme
as audit, so a ruleset can be correlated between trace and audit
records.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Justin Suess &lt;utilityemal77@gmail.com&gt;
Cc: Masami Hiramatsu &lt;mhiramat@kernel.org&gt;
Cc: Mathieu Desnoyers &lt;mathieu.desnoyers@efficios.com&gt;
Cc: Steven Rostedt &lt;rostedt@goodmis.org&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-8-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Consolidate access-right and scope names in a shared header</title>
<updated>2026-08-17T08:17:13+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=bc62ec60343183713055cb6b6247efe0209d9cd6'/>
<id>bc62ec60343183713055cb6b6247efe0209d9cd6</id>
<content type='text'>
Audit formats denial records with per-right name strings.  A following
commit adds trace events that print the same access and scope masks with
__print_flags() and need the same names, but a trace event header cannot
include Landlock-internal headers, so the names cannot be shared from
the logging unit.

Define the filesystem, network, and scope names once, as the
_LANDLOCK_ACCESS_FS_NAMES, _LANDLOCK_ACCESS_NET_NAMES, and
_LANDLOCK_SCOPE_NAMES lists in the public Landlock header.  Each entry
is a _LANDLOCK_NAME_ENTRY() the consumer expands: audit maps it to a
"[bit] = name" array slot for an O(1) lookup, the trace events map it to
a __print_flags() { mask, name } pair.  The bit value comes only from
the LANDLOCK_* UAPI constant each entry references, so every bit-to-name
mapping has a single source and does not depend on entry order.

The shared names are unprefixed; blocker_prefix() prepends the
fs./net./scope. category for audit records, so the scope names move from
inline literals to the shared table too.  Audit records are unchanged.

No functional change.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-7-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Audit formats denial records with per-right name strings.  A following
commit adds trace events that print the same access and scope masks with
__print_flags() and need the same names, but a trace event header cannot
include Landlock-internal headers, so the names cannot be shared from
the logging unit.

Define the filesystem, network, and scope names once, as the
_LANDLOCK_ACCESS_FS_NAMES, _LANDLOCK_ACCESS_NET_NAMES, and
_LANDLOCK_SCOPE_NAMES lists in the public Landlock header.  Each entry
is a _LANDLOCK_NAME_ENTRY() the consumer expands: audit maps it to a
"[bit] = name" array slot for an O(1) lookup, the trace events map it to
a __print_flags() { mask, name } pair.  The bit value comes only from
the LANDLOCK_* UAPI constant each entry references, so every bit-to-name
mapping has a single source and does not depend on entry order.

The shared names are unprefixed; blocker_prefix() prepends the
fs./net./scope. category for audit records, so the scope names move from
inline literals to the shared table too.  Audit records are unchanged.

No functional change.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Cc: Tingmao Wang &lt;m@maowtm.org&gt;
Link: https://patch.msgid.link/20260811094338.288094-7-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Decouple the per-denial logging decision from CONFIG_AUDIT</title>
<updated>2026-08-17T08:17:12+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=69ca5782f812742e89faa44748968aad1a69e8b6'/>
<id>69ca5782f812742e89faa44748968aad1a69e8b6</id>
<content type='text'>
Until now, whether a denial is logged was decided inside
landlock_audit_denial(): a per-execution flag check (log_same_exec or
log_new_exec, selected by the credential's domain_exec bitmask),
preceded by a LANDLOCK_LOG_DISABLED early return in
landlock_log_denial() for domains an ancestor fully quieted.

Factor that decision into a single is_denial_logged() helper called once
by landlock_log_denial(), and pass its result to landlock_audit_denial()
as a "logged" boolean.  A following commit passes the same boolean to
the deny tracepoints, so audit and tracing share one decision that stays
correct as new log state is added, and a tracepoints-only build
(CONFIG_AUDIT=n) computes it identically.  Computing the logged verdict
once in the shared helper makes audit and tracing apply identical
filtering, so they cannot report different logged= values for the same
denial as log controls grow.

Move the LANDLOCK_LOG_DISABLED gate out of landlock_log_denial() into
the decision so num_denials counts every denial, including those a
domain quiets.  This was previously masked: the only reader of
num_denials is the audit "domain deallocated" record, emitted only for
domains that reached LANDLOCK_LOG_RECORDED; a fully quieted domain never
records, so its undercount was never observable.  A following commit
adds a free_domain tracepoint that reports num_denials, which needs the
full count.

This is not a functional change for audit: the logged decision and the
audit_enabled gate are preserved, so the emitted records are identical.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Link: https://patch.msgid.link/20260811094338.288094-6-mic@digikod.net
Reviewed-by: Tingmao Wang &lt;m@maowtm.org&gt;
[mic: Update copyright]
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Until now, whether a denial is logged was decided inside
landlock_audit_denial(): a per-execution flag check (log_same_exec or
log_new_exec, selected by the credential's domain_exec bitmask),
preceded by a LANDLOCK_LOG_DISABLED early return in
landlock_log_denial() for domains an ancestor fully quieted.

Factor that decision into a single is_denial_logged() helper called once
by landlock_log_denial(), and pass its result to landlock_audit_denial()
as a "logged" boolean.  A following commit passes the same boolean to
the deny tracepoints, so audit and tracing share one decision that stays
correct as new log state is added, and a tracepoints-only build
(CONFIG_AUDIT=n) computes it identically.  Computing the logged verdict
once in the shared helper makes audit and tracing apply identical
filtering, so they cannot report different logged= values for the same
denial as log controls grow.

Move the LANDLOCK_LOG_DISABLED gate out of landlock_log_denial() into
the decision so num_denials counts every denial, including those a
domain quiets.  This was previously masked: the only reader of
num_denials is the audit "domain deallocated" record, emitted only for
domains that reached LANDLOCK_LOG_RECORDED; a fully quieted domain never
records, so its undercount was never observable.  A following commit
adds a free_domain tracepoint that reports num_denials, which needs the
full count.

This is not a functional change for audit: the logged decision and the
audit_enabled gate are preserved, so the emitted records are identical.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Link: https://patch.msgid.link/20260811094338.288094-6-mic@digikod.net
Reviewed-by: Tingmao Wang &lt;m@maowtm.org&gt;
[mic: Update copyright]
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>landlock: Split denial logging from audit into common framework</title>
<updated>2026-08-17T08:17:11+00:00</updated>
<author>
<name>Mickaël Salaün</name>
<email>mic@digikod.net</email>
</author>
<published>2026-08-11T09:43:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux-stable.git/commit/?id=e761a88cedeb46de17b6d9e8c7c41c7671e83a6b'/>
<id>e761a88cedeb46de17b6d9e8c7c41c7671e83a6b</id>
<content type='text'>
Tracepoint emission requires the denial framework (layer identification,
request validation) without depending on CONFIG_AUDIT.  Separate the
denial logging infrastructure from the audit-specific code by
introducing a common log framework.

Create CONFIG_SECURITY_LANDLOCK_LOG, enabled by default when
CONFIG_AUDIT is set; a following commit extends it to CONFIG_TRACEPOINTS
when the first tracepoint consumer is added.  Move the common framework
(the request types, the layer identification and request validation, and
the landlock_log_denial() and landlock_log_free_domain() entry points)
into log.c and log.h, and keep the audit-specific record formatting in
audit.c. log.o is built for CONFIG_SECURITY_LANDLOCK_LOG and audit.o for
CONFIG_AUDIT, so the common framework is available to a tracepoints-only
build.  The entry points dispatch to no-op static inline audit stubs
without CONFIG_AUDIT, so the call sites stay unconditional.  Rename the
former landlock_log_drop_domain() to landlock_log_free_domain() to match
the landlock_free_domain tracepoint added in a following commit.

landlock_log_denial() counts denials even without audit, so its
declaration and no-op stub are guarded by CONFIG_SECURITY_LANDLOCK_LOG,
not CONFIG_AUDIT; a CONFIG_AUDIT guard would expose the stub and clash
with log.c's definition in a tracepoints-only build.

Widen the ID allocation (id.o and the landlock_init_id() /
landlock_get_id_range() declarations) and the log-state representation
(the domain_exec and log_subdomains_off credential fields, the
landlock_hierarchy log fields, and the code that maintains them) from
CONFIG_AUDIT to CONFIG_SECURITY_LANDLOCK_LOG, so each field and its
writer share one guard and are available to tracing without audit
support.

Widen the denial-path state that feeds the per-denial logging decision
the same way, so the "logged" verdict is computed identically whether or
not CONFIG_AUDIT is set.  Widening fown_layer is what keeps the
file-owner-signal path valid without audit: otherwise
hook_file_send_sigiotask() would leave layer_plus_one at zero, tripping
the is_valid_request() canary and dropping the LANDLOCK_SCOPE_SIGNAL
denial from tracing.

The ruleset-level quiet_masks stays on no CONFIG guard: it is builder
state validated and stored from user input, kept available so
LANDLOCK_ADD_RULE_QUIET flags are accepted and ignored, not rejected,
when CONFIG_SECURITY_LANDLOCK_LOG is disabled.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Link: https://patch.msgid.link/20260811094338.288094-5-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Tracepoint emission requires the denial framework (layer identification,
request validation) without depending on CONFIG_AUDIT.  Separate the
denial logging infrastructure from the audit-specific code by
introducing a common log framework.

Create CONFIG_SECURITY_LANDLOCK_LOG, enabled by default when
CONFIG_AUDIT is set; a following commit extends it to CONFIG_TRACEPOINTS
when the first tracepoint consumer is added.  Move the common framework
(the request types, the layer identification and request validation, and
the landlock_log_denial() and landlock_log_free_domain() entry points)
into log.c and log.h, and keep the audit-specific record formatting in
audit.c. log.o is built for CONFIG_SECURITY_LANDLOCK_LOG and audit.o for
CONFIG_AUDIT, so the common framework is available to a tracepoints-only
build.  The entry points dispatch to no-op static inline audit stubs
without CONFIG_AUDIT, so the call sites stay unconditional.  Rename the
former landlock_log_drop_domain() to landlock_log_free_domain() to match
the landlock_free_domain tracepoint added in a following commit.

landlock_log_denial() counts denials even without audit, so its
declaration and no-op stub are guarded by CONFIG_SECURITY_LANDLOCK_LOG,
not CONFIG_AUDIT; a CONFIG_AUDIT guard would expose the stub and clash
with log.c's definition in a tracepoints-only build.

Widen the ID allocation (id.o and the landlock_init_id() /
landlock_get_id_range() declarations) and the log-state representation
(the domain_exec and log_subdomains_off credential fields, the
landlock_hierarchy log fields, and the code that maintains them) from
CONFIG_AUDIT to CONFIG_SECURITY_LANDLOCK_LOG, so each field and its
writer share one guard and are available to tracing without audit
support.

Widen the denial-path state that feeds the per-denial logging decision
the same way, so the "logged" verdict is computed identically whether or
not CONFIG_AUDIT is set.  Widening fown_layer is what keeps the
file-owner-signal path valid without audit: otherwise
hook_file_send_sigiotask() would leave layer_plus_one at zero, tripping
the is_valid_request() canary and dropping the LANDLOCK_SCOPE_SIGNAL
denial from tracing.

The ruleset-level quiet_masks stays on no CONFIG guard: it is builder
state validated and stored from user input, kept available so
LANDLOCK_ADD_RULE_QUIET flags are accepted and ignored, not rejected,
when CONFIG_SECURITY_LANDLOCK_LOG is disabled.

Cc: Günther Noack &lt;gnoack@google.com&gt;
Link: https://patch.msgid.link/20260811094338.288094-5-mic@digikod.net
Signed-off-by: Mickaël Salaün &lt;mic@digikod.net&gt;
</pre>
</div>
</content>
</entry>
</feed>
