xref: /linux/include/trace/events/landlock.h (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1b4540a72SMickaël Salaün /* SPDX-License-Identifier: GPL-2.0 */
2b4540a72SMickaël Salaün /*
3b4540a72SMickaël Salaün  * Copyright © 2025 Microsoft Corporation
4b4540a72SMickaël Salaün  * Copyright © 2026 Cloudflare, Inc.
5b4540a72SMickaël Salaün  */
6b4540a72SMickaël Salaün 
7b4540a72SMickaël Salaün #undef TRACE_SYSTEM
8b4540a72SMickaël Salaün #define TRACE_SYSTEM landlock
9b4540a72SMickaël Salaün 
10b4540a72SMickaël Salaün #if !defined(_TRACE_LANDLOCK_H) || defined(TRACE_HEADER_MULTI_READ)
11b4540a72SMickaël Salaün #define _TRACE_LANDLOCK_H
12b4540a72SMickaël Salaün 
13b4540a72SMickaël Salaün #include <linux/landlock.h>
1463747c94SMickaël Salaün #include <linux/string.h>
1563747c94SMickaël Salaün #include <linux/string_helpers.h>
16b4540a72SMickaël Salaün #include <linux/tracepoint.h>
1763747c94SMickaël Salaün #include <linux/trace_seq.h>
18*bb91730fSMickaël Salaün #include <net/af_unix.h>
19b4540a72SMickaël Salaün 
203f1f106eSMickaël Salaün struct dentry;
2167567f03SMickaël Salaün struct landlock_domain;
2267567f03SMickaël Salaün struct landlock_hierarchy;
233f1f106eSMickaël Salaün struct landlock_rule;
24b4540a72SMickaël Salaün struct landlock_ruleset;
2563747c94SMickaël Salaün struct path;
2601ce260fSMickaël Salaün struct sock;
27*bb91730fSMickaël Salaün struct task_struct;
2863747c94SMickaël Salaün 
2963747c94SMickaël Salaün #ifdef CREATE_TRACE_POINTS
3063747c94SMickaël Salaün 
3163747c94SMickaël Salaün /*
3263747c94SMickaël Salaün  * Escapes @len bytes of an untrusted string into the trace sequence @p so it
3363747c94SMickaël Salaün  * cannot inject field separators or control characters into the ftrace text
3463747c94SMickaël Salaün  * output, and can be unambiguously recovered.  Called from the TP_printk() of
3563747c94SMickaël Salaün  * the tracepoints that expose paths and process names.  @len is passed by the
3663747c94SMickaël Salaün  * caller (rather than derived with strlen()) so a name that is not
3763747c94SMickaël Salaün  * NUL-terminated or carries embedded NUL bytes (an abstract socket name) is
3863747c94SMickaël Salaün  * escaped in full instead of being truncated at the first NUL.
3963747c94SMickaël Salaün  *
4063747c94SMickaël Salaün  * Return: a pointer into @p's buffer, or NULL if @src is NULL or the buffer is
4163747c94SMickaël Salaün  * exhausted (normal when the trace buffer is full).
4263747c94SMickaël Salaün  */
4363747c94SMickaël Salaün static inline const char *
4463747c94SMickaël Salaün __trace_print_untrusted_str(struct trace_seq *p, const char *src, size_t len)
4563747c94SMickaël Salaün {
4663747c94SMickaël Salaün 	int escaped_size;
4763747c94SMickaël Salaün 	char *buf;
4863747c94SMickaël Salaün 	size_t buf_size = seq_buf_get_buf(&p->seq, &buf);
4963747c94SMickaël Salaün 	const char *ret = trace_seq_buffer_ptr(p);
5063747c94SMickaël Salaün 
5163747c94SMickaël Salaün 	/* Buffer exhaustion is normal when the trace buffer is full. */
5263747c94SMickaël Salaün 	if (!src || buf_size == 0)
5363747c94SMickaël Salaün 		return NULL;
5463747c94SMickaël Salaün 
5563747c94SMickaël Salaün 	escaped_size =
5663747c94SMickaël Salaün 		string_escape_mem(src, len, buf, buf_size,
5763747c94SMickaël Salaün 				  ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NAP |
5863747c94SMickaël Salaün 					  ESCAPE_APPEND | ESCAPE_OCTAL,
5963747c94SMickaël Salaün 				  " ='\"\\");
6063747c94SMickaël Salaün 	if (unlikely(escaped_size >= buf_size)) {
6163747c94SMickaël Salaün 		/* We need some room for the final '\0'. */
6263747c94SMickaël Salaün 		seq_buf_set_overflow(&p->seq);
6363747c94SMickaël Salaün 		p->full = 1;
6463747c94SMickaël Salaün 		return NULL;
6563747c94SMickaël Salaün 	}
6663747c94SMickaël Salaün 	seq_buf_commit(&p->seq, escaped_size);
6763747c94SMickaël Salaün 	trace_seq_putc(p, 0);
6863747c94SMickaël Salaün 	return ret;
6963747c94SMickaël Salaün }
7063747c94SMickaël Salaün 
713f1f106eSMickaël Salaün /*
723f1f106eSMickaël Salaün  * Fills the dense per-domain-layer array layers (one access mask per layer,
733f1f106eSMickaël Salaün  * indexed by level - 1) from rule's sparse layer stack, keeping only the
743f1f106eSMickaël Salaün  * requested rights (access_request).  Layers with no matching rule entry get
753f1f106eSMickaël Salaün  * a zero mask.  Shared by the check_rule_fs and check_rule_net events.
763f1f106eSMickaël Salaün  *
773f1f106eSMickaël Salaün  * rule->layers is sorted by ascending level, with levels in the domain's
783f1f106eSMickaël Salaün  * [1, num_layers] range (see landlock_merge_ruleset()), so every entry maps
793f1f106eSMickaël Salaün  * to a slot.  A leftover entry would be a malformed rule; the zero-filled
803f1f106eSMickaël Salaün  * slots keep the output and the array bounds safe regardless.
813f1f106eSMickaël Salaün  */
823f1f106eSMickaël Salaün static inline void
833f1f106eSMickaël Salaün __trace_landlock_fill_layers(access_mask_t *const layers,
843f1f106eSMickaël Salaün 			     const size_t num_layers,
853f1f106eSMickaël Salaün 			     const struct landlock_rule *const rule,
863f1f106eSMickaël Salaün 			     const access_mask_t access_request)
873f1f106eSMickaël Salaün {
883f1f106eSMickaël Salaün 	size_t i = 0;
893f1f106eSMickaël Salaün 
903f1f106eSMickaël Salaün 	for (size_t level = 1; level <= num_layers; level++) {
913f1f106eSMickaël Salaün 		access_mask_t grants = 0;
923f1f106eSMickaël Salaün 
933f1f106eSMickaël Salaün 		if (i < rule->num_layers && level == rule->layers[i].level) {
943f1f106eSMickaël Salaün 			grants = rule->layers[i].access & access_request;
953f1f106eSMickaël Salaün 			i++;
963f1f106eSMickaël Salaün 		}
973f1f106eSMickaël Salaün 		layers[level - 1] = grants;
983f1f106eSMickaël Salaün 	}
993f1f106eSMickaël Salaün 
1003f1f106eSMickaël Salaün 	/* A leftover entry means an out-of-range or unsorted rule level. */
1013f1f106eSMickaël Salaün 	WARN_ON_ONCE(i < rule->num_layers);
1023f1f106eSMickaël Salaün }
1033f1f106eSMickaël Salaün 
1043f1f106eSMickaël Salaün /*
1053f1f106eSMickaël Salaün  * Renders the dense per-domain-layer access array as symbolic flag names for
1063f1f106eSMickaël Salaün  * the grants field: layers wrapped in "{}", flags within a layer joined by
1073f1f106eSMickaël Salaün  * "|", layers separated by ",", an empty layer rendered as nothing.
1083f1f106eSMickaël Salaün  * Open-codes the flag walk because trace_print_flags_seq() NUL-terminates per
1093f1f106eSMickaël Salaün  * call and so cannot be chained into a single field.  The shared names table
1103f1f106eSMickaël Salaün  * covers every access right, so masked bits are always named.  Returns the
1113f1f106eSMickaël Salaün  * trace_seq position like __print_flags().
1123f1f106eSMickaël Salaün  */
1133f1f106eSMickaël Salaün static inline const char *__trace_landlock_print_layers(
1143f1f106eSMickaël Salaün 	struct trace_seq *p, const access_mask_t *const layers,
1153f1f106eSMickaël Salaün 	const size_t num_layers, const struct trace_print_flags *const names,
1163f1f106eSMickaël Salaün 	const size_t names_size)
1173f1f106eSMickaël Salaün {
1183f1f106eSMickaël Salaün 	const char *const ret = trace_seq_buffer_ptr(p);
1193f1f106eSMickaël Salaün 
1203f1f106eSMickaël Salaün 	trace_seq_putc(p, '{');
1213f1f106eSMickaël Salaün 	for (size_t i = 0; i < num_layers; i++) {
1223f1f106eSMickaël Salaün 		access_mask_t mask = layers[i];
1233f1f106eSMickaël Salaün 		bool first = true;
1243f1f106eSMickaël Salaün 
1253f1f106eSMickaël Salaün 		if (i)
1263f1f106eSMickaël Salaün 			trace_seq_putc(p, ',');
1273f1f106eSMickaël Salaün 		for (size_t j = 0; mask && j < names_size; j++) {
1283f1f106eSMickaël Salaün 			if ((mask & names[j].mask) != names[j].mask)
1293f1f106eSMickaël Salaün 				continue;
1303f1f106eSMickaël Salaün 			if (!first)
1313f1f106eSMickaël Salaün 				trace_seq_putc(p, '|');
1323f1f106eSMickaël Salaün 			trace_seq_puts(p, names[j].name);
1333f1f106eSMickaël Salaün 			mask &= ~names[j].mask;
1343f1f106eSMickaël Salaün 			first = false;
1353f1f106eSMickaël Salaün 		}
1363f1f106eSMickaël Salaün 	}
1373f1f106eSMickaël Salaün 	trace_seq_putc(p, '}');
1383f1f106eSMickaël Salaün 	trace_seq_putc(p, 0);
1393f1f106eSMickaël Salaün 	return ret;
1403f1f106eSMickaël Salaün }
1413f1f106eSMickaël Salaün 
14263747c94SMickaël Salaün #endif /* CREATE_TRACE_POINTS */
143b4540a72SMickaël Salaün 
144b4540a72SMickaël Salaün /* clang-format off */
145b4540a72SMickaël Salaün 
146b4540a72SMickaël Salaün /* Maps a shared _LANDLOCK_*_NAMES entry to a __print_flags() pair. */
147b4540a72SMickaël Salaün #define _LANDLOCK_NAME_ENTRY(mask, name) { mask, name }
148b4540a72SMickaël Salaün 
149b4540a72SMickaël Salaün /**
150b4540a72SMickaël Salaün  * DOC: Landlock trace events
151b4540a72SMickaël Salaün  *
152b4540a72SMickaël Salaün  * These guarantees and constraints hold for every Landlock tracepoint.
153b4540a72SMickaël Salaün  * A new tracepoint must uphold them, and an eBPF consumer can rely on
154b4540a72SMickaël Salaün  * them.
155b4540a72SMickaël Salaün  *
156*bb91730fSMickaël Salaün  * Decision context
157*bb91730fSMickaël Salaün  * ~~~~~~~~~~~~~~~~
158*bb91730fSMickaël Salaün  *
159*bb91730fSMickaël Salaün  * A denial event, together with the lifecycle events, exposes the full
160*bb91730fSMickaël Salaün  * set of inputs the verdict consumed, so a consumer that tracked domain
161*bb91730fSMickaël Salaün  * creation (landlock_create_ruleset, landlock_create_domain) can verify
162*bb91730fSMickaël Salaün  * or reproduce the Landlock decision rather than merely observe it
163*bb91730fSMickaël Salaün  * happened.  In who/what/why terms: who is the denying domain (the domain
164*bb91730fSMickaël Salaün  * field, always the subject that enforced the policy, never the current
165*bb91730fSMickaël Salaün  * task), what is the operation and its object, and why is every other
166*bb91730fSMickaël Salaün  * input the verdict weighed.
167*bb91730fSMickaël Salaün  *
168b4540a72SMickaël Salaün  * Lifecycle consistency
169b4540a72SMickaël Salaün  * ~~~~~~~~~~~~~~~~~~~~~~
170b4540a72SMickaël Salaün  *
171b4540a72SMickaël Salaün  * Lifecycle events are balanced: a creation event always has a matching
172b4540a72SMickaël Salaün  * deallocation event and vice versa, so an eBPF program can model object
173b4540a72SMickaël Salaün  * lifetimes from the trace stream without reconciliation logic.  A creation
174b4540a72SMickaël Salaün  * event fires while the object is still private to the calling thread
175b4540a72SMickaël Salaün  * (landlock_create_ruleset fires before the ruleset's file descriptor is
176b4540a72SMickaël Salaün  * installed, so it cannot race a concurrent :manpage:`close(2)`); if fd
177b4540a72SMickaël Salaün  * installation later fails and the ruleset is freed, free_ruleset still
178b4540a72SMickaël Salaün  * fires, keeping the pair balanced.  The domain pair (create_domain and
179b4540a72SMickaël Salaün  * free_domain) is balanced the same way: create_domain fires when the
180b4540a72SMickaël Salaün  * domain is created (under the ruleset lock, before thread-sync), and
181b4540a72SMickaël Salaün  * free_domain fires when it is freed.  A rare thread-sync failure aborts
182b4540a72SMickaël Salaün  * the just-created domain, which then emits both events (its creation, then
183b4540a72SMickaël Salaün  * an immediate free).  Denial events fire only for denials that actually
184b4540a72SMickaël Salaün  * happen.
185b4540a72SMickaël Salaün  *
186b4540a72SMickaël Salaün  * Pointer access
187b4540a72SMickaël Salaün  * ~~~~~~~~~~~~~~
188b4540a72SMickaël Salaün  *
189b4540a72SMickaël Salaün  * All pointer arguments in TP_PROTO are guaranteed non-NULL by the
190b4540a72SMickaël Salaün  * caller, but pointers reached through them may still be NULL (e.g.,
191b4540a72SMickaël Salaün  * hierarchy->parent at a root domain) and must be checked.  eBPF programs
192b4540a72SMickaël Salaün  * read these pointers via BTF for richer introspection than the
193b4540a72SMickaël Salaün  * TP_STRUCT__entry fields, which serve TP_printk display only.
194b4540a72SMickaël Salaün  *
195b4540a72SMickaël Salaün  * Mutable object pointers are passed while the caller holds the object's
196b4540a72SMickaël Salaün  * lock, so TP_fast_assign and a BTF reader see the exact object the event
197b4540a72SMickaël Salaün  * reports, a snapshot no concurrent writer can change: add_rule holds the
198b4540a72SMickaël Salaün  * modified ruleset's lock, and create_domain holds the ruleset lock across
199b4540a72SMickaël Salaün  * the emission (before the thread-sync wait) so the inspected ruleset is
200b4540a72SMickaël Salaün  * the one merged into the domain.  Objects immutable at the emission site
201b4540a72SMickaël Salaün  * (a domain after creation, a hierarchy at its last reference) need no
202b4540a72SMickaël Salaün  * lock.  A few values that no held lock protects are a best-effort
203b4540a72SMickaël Salaün  * lockless snapshot instead: a task's comm, and the deny_access_net struct
204b4540a72SMickaël Salaün  * sock (whose network hook holds no socket lock), matching how the sched
205b4540a72SMickaël Salaün  * and signal trace events sample comm.
20663747c94SMickaël Salaün  *
20763747c94SMickaël Salaün  * Field encoding
20863747c94SMickaël Salaün  * ~~~~~~~~~~~~~~
20963747c94SMickaël Salaün  *
21063747c94SMickaël Salaün  * Fields that mirror the Landlock UAPI use the same C types and endianness
21163747c94SMickaël Salaün  * (e.g. network ports are __u64 in host endianness, like
21263747c94SMickaël Salaün  * landlock_net_port_attr.port).  Per-event details, such as where a value
21363747c94SMickaël Salaün  * is byte-swapped, live in the field's own kdoc.
2143f1f106eSMickaël Salaün  *
2153f1f106eSMickaël Salaün  * Rule-check fields
2163f1f106eSMickaël Salaün  * ~~~~~~~~~~~~~~~~~
2173f1f106eSMickaël Salaün  *
2183f1f106eSMickaël Salaün  * The check_rule events fire during an access check, once per matching
2193f1f106eSMickaël Salaün  * rule, before the final allow-or-deny verdict.  They share domain (the
2203f1f106eSMickaël Salaün  * enforcing domain being evaluated), access_request (the access mask being
2213f1f106eSMickaël Salaün  * checked), and rule (the matching rule, with per-layer access masks).
22201ce260fSMickaël Salaün  *
22301ce260fSMickaël Salaün  * Denial fields
22401ce260fSMickaël Salaün  * ~~~~~~~~~~~~~
22501ce260fSMickaël Salaün  *
22601ce260fSMickaël Salaün  * Every denial event shares three fields.  domain is the ID of the
22701ce260fSMickaël Salaün  * innermost domain that blocked the access.  same_exec tells whether the
22801ce260fSMickaël Salaün  * current task is the same executable that entered that domain.  logged is
22901ce260fSMickaël Salaün  * the domain's audit-logging decision for this denial (its log_status is
23001ce260fSMickaël Salaün  * enabled and the per-execution flag selected by same_exec is set); a
23101ce260fSMickaël Salaün  * stateless ftrace filter can select the denials the domain submits to
23201ce260fSMickaël Salaün  * audit with logged==1, without reconstructing it from the per-execution
23301ce260fSMickaël Salaün  * log flags.  Denial events order their fields as domain, same_exec,
23401ce260fSMickaël Salaün  * logged, then blockers (deny_access events only), then the type-specific
23501ce260fSMickaël Salaün  * object fields, then any variable-length field.
236*bb91730fSMickaël Salaün  *
237*bb91730fSMickaël Salaün  * Relational referents
238*bb91730fSMickaël Salaün  * ~~~~~~~~~~~~~~~~~~~~~
239*bb91730fSMickaël Salaün  *
240*bb91730fSMickaël Salaün  * A scope or ptrace verdict compares two domains, so the other party's
241*bb91730fSMickaël Salaün  * domain is part of the decision context.  It is exposed as a scalar
242*bb91730fSMickaël Salaün  * domain ID (0 when that party is unsandboxed): target_domain (signal),
243*bb91730fSMickaël Salaün  * peer_domain (abstract unix socket), tracee_domain (ptrace).  With both
244*bb91730fSMickaël Salaün  * IDs in the stream, a consumer that tracked domain creation can relate
245*bb91730fSMickaël Salaün  * the two parties without kernel-internal state.  The ID is a scalar
246*bb91730fSMickaël Salaün  * snapshot, not a live domain pointer that could dangle: an optional
247*bb91730fSMickaël Salaün  * relational referent is a scalar (0 sentinel), not a nullable pointer.
248b4540a72SMickaël Salaün  */
249b4540a72SMickaël Salaün 
2503f1f106eSMickaël Salaün /*
2513f1f106eSMickaël Salaün  * Prints a per-layer access mask array (the dynamic array @array) as symbolic
2523f1f106eSMickaël Salaün  * flag names using the shared @flag_names list (a _LANDLOCK_*_NAMES macro).
2533f1f106eSMickaël Salaün  * Stays outside CREATE_TRACE_POINTS: TP_printk is expanded in the print-output
2543f1f106eSMickaël Salaün  * pass where that macro is undefined.
2553f1f106eSMickaël Salaün  */
2563f1f106eSMickaël Salaün #define __print_landlock_layers(array, flag_names...)			\
2573f1f106eSMickaël Salaün 	({								\
2583f1f106eSMickaël Salaün 		static const struct trace_print_flags __layer_names[] = { \
2593f1f106eSMickaël Salaün 			flag_names					\
2603f1f106eSMickaël Salaün 		};							\
2613f1f106eSMickaël Salaün 		__trace_landlock_print_layers(				\
2623f1f106eSMickaël Salaün 			p, __get_dynamic_array(array),			\
2633f1f106eSMickaël Salaün 			__get_dynamic_array_len(array) /		\
2643f1f106eSMickaël Salaün 				sizeof(access_mask_t),			\
2653f1f106eSMickaël Salaün 			__layer_names, ARRAY_SIZE(__layer_names));	\
2663f1f106eSMickaël Salaün 	})
2673f1f106eSMickaël Salaün 
268b4540a72SMickaël Salaün /**
269b4540a72SMickaël Salaün  * landlock_create_ruleset - New ruleset created
270b4540a72SMickaël Salaün  *
271b4540a72SMickaël Salaün  * @ruleset: Newly created ruleset (never NULL); not yet shared via an fd,
272b4540a72SMickaël Salaün  *           so no lock is needed.
273b4540a72SMickaël Salaün  *
274b4540a72SMickaël Salaün  * Emitted by sys_landlock_create_ruleset() while the new ruleset is still
275b4540a72SMickaël Salaün  * private to the calling thread, before its file descriptor is installed,
276b4540a72SMickaël Salaün  * so it cannot race a concurrent :manpage:`close(2)`.  Balanced by a
277b4540a72SMickaël Salaün  * matching landlock_free_ruleset event.
278b4540a72SMickaël Salaün  */
279b4540a72SMickaël Salaün TRACE_EVENT(landlock_create_ruleset,
280b4540a72SMickaël Salaün 
281b4540a72SMickaël Salaün 	TP_PROTO(const struct landlock_ruleset *ruleset),
282b4540a72SMickaël Salaün 
283b4540a72SMickaël Salaün 	TP_ARGS(ruleset),
284b4540a72SMickaël Salaün 
285b4540a72SMickaël Salaün 	TP_STRUCT__entry(
286b4540a72SMickaël Salaün 		__field(	__u64,		ruleset_id	)
28763747c94SMickaël Salaün 		__field(	__u32,		ruleset_version	)
288b4540a72SMickaël Salaün 		__field(	access_mask_t,	handled_fs	)
289b4540a72SMickaël Salaün 		__field(	access_mask_t,	handled_net	)
290b4540a72SMickaël Salaün 		__field(	access_mask_t,	scoped		)
291b4540a72SMickaël Salaün 	),
292b4540a72SMickaël Salaün 
293b4540a72SMickaël Salaün 	TP_fast_assign(
294b4540a72SMickaël Salaün 		__entry->ruleset_id	= ruleset->id;
29563747c94SMickaël Salaün 		__entry->ruleset_version = ruleset->version;
296b4540a72SMickaël Salaün 		__entry->handled_fs	= ruleset->handled_masks.fs;
297b4540a72SMickaël Salaün 		__entry->handled_net	= ruleset->handled_masks.net;
298b4540a72SMickaël Salaün 		__entry->scoped		= ruleset->handled_masks.scope;
299b4540a72SMickaël Salaün 	),
300b4540a72SMickaël Salaün 
30163747c94SMickaël Salaün 	TP_printk("ruleset=%llx.%u handled_fs=%s handled_net=%s scoped=%s",
30263747c94SMickaël Salaün 		__entry->ruleset_id, __entry->ruleset_version,
303b4540a72SMickaël Salaün 		__print_flags(__entry->handled_fs, "|", _LANDLOCK_ACCESS_FS_NAMES),
304b4540a72SMickaël Salaün 		__print_flags(__entry->handled_net, "|", _LANDLOCK_ACCESS_NET_NAMES),
305b4540a72SMickaël Salaün 		__print_flags(__entry->scoped, "|", _LANDLOCK_SCOPE_NAMES))
306b4540a72SMickaël Salaün );
307b4540a72SMickaël Salaün 
308b4540a72SMickaël Salaün /**
309b4540a72SMickaël Salaün  * landlock_free_ruleset - Ruleset freed
310b4540a72SMickaël Salaün  *
311b4540a72SMickaël Salaün  * @ruleset: Ruleset being freed (never NULL); at its last reference, so no
312b4540a72SMickaël Salaün  *           lock is needed.
313b4540a72SMickaël Salaün  *
314b4540a72SMickaël Salaün  * Emitted when a ruleset's last reference is dropped (typically when
315b4540a72SMickaël Salaün  * the creating process closes the ruleset file descriptor).  Fires even
316b4540a72SMickaël Salaün  * when file-descriptor installation failed after creation, keeping the
317b4540a72SMickaël Salaün  * create/free pair balanced.
318b4540a72SMickaël Salaün  */
319b4540a72SMickaël Salaün TRACE_EVENT(landlock_free_ruleset,
320b4540a72SMickaël Salaün 
321b4540a72SMickaël Salaün 	TP_PROTO(const struct landlock_ruleset *ruleset),
322b4540a72SMickaël Salaün 
323b4540a72SMickaël Salaün 	TP_ARGS(ruleset),
324b4540a72SMickaël Salaün 
325b4540a72SMickaël Salaün 	TP_STRUCT__entry(
326b4540a72SMickaël Salaün 		__field(	__u64,		ruleset_id	)
32763747c94SMickaël Salaün 		__field(	__u32,		ruleset_version	)
328b4540a72SMickaël Salaün 	),
329b4540a72SMickaël Salaün 
330b4540a72SMickaël Salaün 	TP_fast_assign(
331b4540a72SMickaël Salaün 		__entry->ruleset_id	= ruleset->id;
33263747c94SMickaël Salaün 		__entry->ruleset_version = ruleset->version;
333b4540a72SMickaël Salaün 	),
334b4540a72SMickaël Salaün 
33563747c94SMickaël Salaün 	TP_printk("ruleset=%llx.%u",
33663747c94SMickaël Salaün 		__entry->ruleset_id, __entry->ruleset_version)
33763747c94SMickaël Salaün );
33863747c94SMickaël Salaün 
33963747c94SMickaël Salaün /**
34063747c94SMickaël Salaün  * landlock_add_rule_fs - Filesystem rule added to a ruleset
34163747c94SMickaël Salaün  *
34263747c94SMickaël Salaün  * @ruleset: Source ruleset (never NULL).
34363747c94SMickaël Salaün  * @access_rights: Effective access mask stored in the rule, not the raw
34463747c94SMickaël Salaün  *                 sys_landlock_add_rule() argument (unhandled rights
34563747c94SMickaël Salaün  *                 added).
34663747c94SMickaël Salaün  * @path: Filesystem path for the rule (never NULL).
34763747c94SMickaël Salaün  * @pathname: Resolved absolute path string (never NULL; error placeholder
34863747c94SMickaël Salaün  *            on resolution failure).
34963747c94SMickaël Salaün  *
35063747c94SMickaël Salaün  * Emitted by sys_landlock_add_rule() under the modified ruleset's lock, so
35163747c94SMickaël Salaün  * the reported ruleset is a stable snapshot that no concurrent writer can
35263747c94SMickaël Salaün  * change.
35363747c94SMickaël Salaün  */
35463747c94SMickaël Salaün TRACE_EVENT(landlock_add_rule_fs,
35563747c94SMickaël Salaün 
35663747c94SMickaël Salaün 	TP_PROTO(const struct landlock_ruleset *ruleset,
35763747c94SMickaël Salaün 		 access_mask_t access_rights, const struct path *path,
35863747c94SMickaël Salaün 		 const char *pathname),
35963747c94SMickaël Salaün 
36063747c94SMickaël Salaün 	TP_ARGS(ruleset, access_rights, path, pathname),
36163747c94SMickaël Salaün 
36263747c94SMickaël Salaün 	TP_STRUCT__entry(
36363747c94SMickaël Salaün 		__field(	__u64,		ruleset_id	)
36463747c94SMickaël Salaün 		__field(	__u32,		ruleset_version	)
36563747c94SMickaël Salaün 		__field(	access_mask_t,	access_rights	)
36663747c94SMickaël Salaün 		__field(	dev_t,		dev		)
36763747c94SMickaël Salaün 		__field(	ino_t,		ino		)
36863747c94SMickaël Salaün 		__string(	pathname,	pathname	)
36963747c94SMickaël Salaün 	),
37063747c94SMickaël Salaün 
37163747c94SMickaël Salaün 	TP_fast_assign(
37263747c94SMickaël Salaün 		lockdep_assert_held(&ruleset->lock);
37363747c94SMickaël Salaün 		__entry->ruleset_id	= ruleset->id;
37463747c94SMickaël Salaün 		__entry->ruleset_version = ruleset->version;
37563747c94SMickaël Salaün 		__entry->access_rights	= access_rights;
37663747c94SMickaël Salaün 		__entry->dev		= path->dentry->d_sb->s_dev;
37763747c94SMickaël Salaün 		/*
37863747c94SMickaël Salaün 		 * The inode number may not be the user-visible one,
37963747c94SMickaël Salaün 		 * but it will be the same used by audit.
38063747c94SMickaël Salaün 		 */
38163747c94SMickaël Salaün 		__entry->ino		= d_backing_inode(path->dentry)->i_ino;
38263747c94SMickaël Salaün 		__assign_str(pathname);
38363747c94SMickaël Salaün 	),
38463747c94SMickaël Salaün 
38563747c94SMickaël Salaün 	TP_printk("ruleset=%llx.%u access_rights=%s dev=%u:%u ino=%lu path=%s",
38663747c94SMickaël Salaün 		__entry->ruleset_id, __entry->ruleset_version,
38763747c94SMickaël Salaün 		__print_flags(__entry->access_rights, "|", _LANDLOCK_ACCESS_FS_NAMES),
38863747c94SMickaël Salaün 		MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino,
38963747c94SMickaël Salaün 		__trace_print_untrusted_str(p, __get_str(pathname),
39063747c94SMickaël Salaün 					    __get_dynamic_array_len(pathname) - 1))
39163747c94SMickaël Salaün );
39263747c94SMickaël Salaün 
39363747c94SMickaël Salaün /**
39463747c94SMickaël Salaün  * landlock_add_rule_net - Network port rule added to a ruleset
39563747c94SMickaël Salaün  *
39663747c94SMickaël Salaün  * @ruleset: Source ruleset (never NULL).
39763747c94SMickaël Salaün  * @access_rights: Effective access mask stored in the rule, not the raw
39863747c94SMickaël Salaün  *                 sys_landlock_add_rule() argument (unhandled rights
39963747c94SMickaël Salaün  *                 added).
40063747c94SMickaël Salaün  * @port: Network port, the landlock_net_port_attr.port UAPI value
40163747c94SMickaël Salaün  *        forwarded directly.
40263747c94SMickaël Salaün  *
40363747c94SMickaël Salaün  * Emitted by sys_landlock_add_rule() under the modified ruleset's lock, so
40463747c94SMickaël Salaün  * the reported ruleset is a stable snapshot that no concurrent writer can
40563747c94SMickaël Salaün  * change.
40663747c94SMickaël Salaün  */
40763747c94SMickaël Salaün TRACE_EVENT(landlock_add_rule_net,
40863747c94SMickaël Salaün 
40963747c94SMickaël Salaün 	TP_PROTO(const struct landlock_ruleset *ruleset,
41063747c94SMickaël Salaün 		 access_mask_t access_rights, __u64 port),
41163747c94SMickaël Salaün 
41263747c94SMickaël Salaün 	TP_ARGS(ruleset, access_rights, port),
41363747c94SMickaël Salaün 
41463747c94SMickaël Salaün 	TP_STRUCT__entry(
41563747c94SMickaël Salaün 		__field(	__u64,		ruleset_id	)
41663747c94SMickaël Salaün 		__field(	__u32,		ruleset_version	)
41763747c94SMickaël Salaün 		__field(	access_mask_t,	access_rights	)
41863747c94SMickaël Salaün 		__field(	__u64,		port		)
41963747c94SMickaël Salaün 	),
42063747c94SMickaël Salaün 
42163747c94SMickaël Salaün 	TP_fast_assign(
42263747c94SMickaël Salaün 		lockdep_assert_held(&ruleset->lock);
42363747c94SMickaël Salaün 		__entry->ruleset_id	= ruleset->id;
42463747c94SMickaël Salaün 		__entry->ruleset_version = ruleset->version;
42563747c94SMickaël Salaün 		__entry->access_rights	= access_rights;
42663747c94SMickaël Salaün 		__entry->port		= port;
42763747c94SMickaël Salaün 	),
42863747c94SMickaël Salaün 
42963747c94SMickaël Salaün 	TP_printk("ruleset=%llx.%u access_rights=%s port=%llu",
43063747c94SMickaël Salaün 		__entry->ruleset_id, __entry->ruleset_version,
43163747c94SMickaël Salaün 		__print_flags(__entry->access_rights, "|", _LANDLOCK_ACCESS_NET_NAMES),
43263747c94SMickaël Salaün 		__entry->port)
433b4540a72SMickaël Salaün );
434b4540a72SMickaël Salaün 
43567567f03SMickaël Salaün /**
43667567f03SMickaël Salaün  * landlock_create_domain - New domain created
43767567f03SMickaël Salaün  *
43867567f03SMickaël Salaün  * @domain: Newly created domain (never NULL, immutable after creation).
43967567f03SMickaël Salaün  *          @domain->hierarchy->id is its unique ID, shared with the
44067567f03SMickaël Salaün  *          landlock_enforce_domain and landlock_free_domain events;
44167567f03SMickaël Salaün  *          @domain->hierarchy->details holds the requesting process.
44267567f03SMickaël Salaün  * @ruleset: Source ruleset frozen into the domain (never NULL).  The
44367567f03SMickaël Salaün  *           ruleset lock is held across the emission, so a BPF program
44467567f03SMickaël Salaün  *           reading it via BTF sees the exact merged ruleset;
44567567f03SMickaël Salaün  *           @ruleset->id / @ruleset->version identify it.
44667567f03SMickaël Salaün  *
44767567f03SMickaël Salaün  * Emitted by sys_landlock_restrict_self() once, in the requesting
44867567f03SMickaël Salaün  * thread's context, right after the merge and before thread-sync.  The
44967567f03SMickaël Salaün  * flags-only path (ruleset_fd == -1) creates no domain and does not
45067567f03SMickaël Salaün  * emit this event.  Paired with the per-thread landlock_enforce_domain
45167567f03SMickaël Salaün  * (join on @domain->hierarchy->id) and balanced by a matching
45267567f03SMickaël Salaün  * landlock_free_domain event.
45367567f03SMickaël Salaün  */
45467567f03SMickaël Salaün TRACE_EVENT(landlock_create_domain,
45567567f03SMickaël Salaün 
45667567f03SMickaël Salaün 	TP_PROTO(const struct landlock_domain *domain,
45767567f03SMickaël Salaün 		 const struct landlock_ruleset *ruleset),
45867567f03SMickaël Salaün 
45967567f03SMickaël Salaün 	TP_ARGS(domain, ruleset),
46067567f03SMickaël Salaün 
46167567f03SMickaël Salaün 	TP_STRUCT__entry(
46267567f03SMickaël Salaün 		__field(	__u64,		domain_id	)
46367567f03SMickaël Salaün 		__field(	__u64,		parent_id	)
46467567f03SMickaël Salaün 		__field(	__u64,		ruleset_id	)
46567567f03SMickaël Salaün 		__field(	__u32,		ruleset_version	)
46667567f03SMickaël Salaün 	),
46767567f03SMickaël Salaün 
46867567f03SMickaël Salaün 	TP_fast_assign(
46967567f03SMickaël Salaün 		lockdep_assert_held(&ruleset->lock);
47067567f03SMickaël Salaün 		__entry->domain_id	= domain->hierarchy->id;
47167567f03SMickaël Salaün 		__entry->parent_id	= domain->hierarchy->parent ?
47267567f03SMickaël Salaün 					  domain->hierarchy->parent->id : 0;
47367567f03SMickaël Salaün 		__entry->ruleset_id	= ruleset->id;
47467567f03SMickaël Salaün 		__entry->ruleset_version = ruleset->version;
47567567f03SMickaël Salaün 	),
47667567f03SMickaël Salaün 
47767567f03SMickaël Salaün 	TP_printk("domain=%llx parent=%llx ruleset=%llx.%u",
47867567f03SMickaël Salaün 		__entry->domain_id, __entry->parent_id,
47967567f03SMickaël Salaün 		__entry->ruleset_id, __entry->ruleset_version)
48067567f03SMickaël Salaün );
48167567f03SMickaël Salaün 
48267567f03SMickaël Salaün /**
483132d84b1SMickaël Salaün  * landlock_enforce_domain - Domain enforced on a thread
484132d84b1SMickaël Salaün  *
485132d84b1SMickaël Salaün  * @domain: Domain now enforced on the current thread (never NULL,
486132d84b1SMickaël Salaün  *          immutable; read locklessly).  Correlate to
487132d84b1SMickaël Salaün  *          landlock_create_domain via @domain->hierarchy->id for the
488132d84b1SMickaël Salaün  *          source ruleset and requesting thread, or read
489132d84b1SMickaël Salaün  *          @domain->hierarchy->details for the requesting process.
490132d84b1SMickaël Salaün  * @complete: Set on the single event that concludes the operation, after
491132d84b1SMickaël Salaün  *            all its other enforcements; filter on it for one event per
492132d84b1SMickaël Salaün  *            operation.
493132d84b1SMickaël Salaün  * @process_wide: The enforcement covers every eligible (non-exiting)
494132d84b1SMickaël Salaün  *                thread of the process: set when the caller used
495132d84b1SMickaël Salaün  *                %LANDLOCK_RESTRICT_SELF_TSYNC or the process is
496132d84b1SMickaël Salaün  *                single-threaded.  A lone thread whose group still
497132d84b1SMickaël Salaün  *                holds a zombie leader is not counted single-threaded,
498132d84b1SMickaël Salaün  *                so process_wide == 0 never proves the opposite.
499132d84b1SMickaël Salaün  * @no_new_privs: The enforcing thread's no_new_privs state at
500132d84b1SMickaël Salaün  *                enforcement time: 1 if set (by a prior
501132d84b1SMickaël Salaün  *                :manpage:`prctl(2)` %PR_SET_NO_NEW_PRIVS or by
502132d84b1SMickaël Salaün  *                %LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS), 0 if the domain
503132d84b1SMickaël Salaün  *                was enforced with %CAP_SYS_ADMIN instead.
504132d84b1SMickaël Salaün  *
505132d84b1SMickaël Salaün  * Emitted for each thread sys_landlock_restrict_self() enforces the
506132d84b1SMickaël Salaün  * domain on, in that thread's own context, right after its
507132d84b1SMickaël Salaün  * commit_creds(), so it fires only once the thread is irreversibly
508132d84b1SMickaël Salaün  * enforcing the domain (aborted operations emit none).  Not
509132d84b1SMickaël Salaün  * balanced; every enforcement falls between the domain's
510132d84b1SMickaël Salaün  * landlock_create_domain and landlock_free_domain events.
511132d84b1SMickaël Salaün  *
512132d84b1SMickaël Salaün  * @complete == 1 && @process_wide == 1 means the whole process is
513132d84b1SMickaël Salaün  * sandboxed by @domain, durably (Landlock domains are monotonic and
514132d84b1SMickaël Salaün  * inherited on :manpage:`clone(2)`).
515132d84b1SMickaël Salaün  */
516132d84b1SMickaël Salaün TRACE_EVENT(landlock_enforce_domain,
517132d84b1SMickaël Salaün 
518132d84b1SMickaël Salaün 	TP_PROTO(const struct landlock_domain *domain, bool complete,
519132d84b1SMickaël Salaün 		 bool process_wide, bool no_new_privs),
520132d84b1SMickaël Salaün 
521132d84b1SMickaël Salaün 	TP_ARGS(domain, complete, process_wide, no_new_privs),
522132d84b1SMickaël Salaün 
523132d84b1SMickaël Salaün 	TP_STRUCT__entry(
524132d84b1SMickaël Salaün 		__field(	__u64,		domain_id	)
525132d84b1SMickaël Salaün 		__field(	bool,		complete	)
526132d84b1SMickaël Salaün 		__field(	bool,		process_wide	)
527132d84b1SMickaël Salaün 		__field(	bool,		no_new_privs	)
528132d84b1SMickaël Salaün 	),
529132d84b1SMickaël Salaün 
530132d84b1SMickaël Salaün 	TP_fast_assign(
531132d84b1SMickaël Salaün 		__entry->domain_id	= domain->hierarchy->id;
532132d84b1SMickaël Salaün 		__entry->complete	= complete;
533132d84b1SMickaël Salaün 		__entry->process_wide	= process_wide;
534132d84b1SMickaël Salaün 		__entry->no_new_privs	= no_new_privs;
535132d84b1SMickaël Salaün 	),
536132d84b1SMickaël Salaün 
537132d84b1SMickaël Salaün 	TP_printk("domain=%llx complete=%d process_wide=%d no_new_privs=%d",
538132d84b1SMickaël Salaün 		__entry->domain_id, __entry->complete, __entry->process_wide,
539132d84b1SMickaël Salaün 		__entry->no_new_privs)
540132d84b1SMickaël Salaün );
541132d84b1SMickaël Salaün 
542132d84b1SMickaël Salaün /**
54367567f03SMickaël Salaün  * landlock_free_domain - Domain freed
54467567f03SMickaël Salaün  *
54567567f03SMickaël Salaün  * @hierarchy: Hierarchy node being freed (never NULL).
54667567f03SMickaël Salaün  *
54767567f03SMickaël Salaün  * Emitted when the hierarchy node's last reference is dropped: its
54867567f03SMickaël Salaün  * refcount reaches zero after all child domains have released their
54967567f03SMickaël Salaün  * parent reference.  A committed domain is
55067567f03SMickaël Salaün  * freed from a kworker via landlock_put_domain_deferred() (the credential
55167567f03SMickaël Salaün  * free path runs in RCU context, where sleeping is forbidden), so the
55267567f03SMickaël Salaün  * current task is not the sandboxed task that triggered the free.  Balanced
55367567f03SMickaël Salaün  * by a matching landlock_create_domain event.
55467567f03SMickaël Salaün  */
55567567f03SMickaël Salaün TRACE_EVENT(landlock_free_domain,
55667567f03SMickaël Salaün 
55767567f03SMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy),
55867567f03SMickaël Salaün 
55967567f03SMickaël Salaün 	TP_ARGS(hierarchy),
56067567f03SMickaël Salaün 
56167567f03SMickaël Salaün 	TP_STRUCT__entry(
56267567f03SMickaël Salaün 		__field(	__u64,		domain_id	)
56367567f03SMickaël Salaün 		__field(	__u64,		denials		)
56467567f03SMickaël Salaün 	),
56567567f03SMickaël Salaün 
56667567f03SMickaël Salaün 	TP_fast_assign(
56767567f03SMickaël Salaün 		__entry->domain_id	= hierarchy->id;
56867567f03SMickaël Salaün 		__entry->denials	= atomic64_read(&hierarchy->num_denials);
56967567f03SMickaël Salaün 	),
57067567f03SMickaël Salaün 
57167567f03SMickaël Salaün 	TP_printk("domain=%llx denials=%llu",
57267567f03SMickaël Salaün 		__entry->domain_id, __entry->denials)
57367567f03SMickaël Salaün );
57467567f03SMickaël Salaün 
5753f1f106eSMickaël Salaün /**
5763f1f106eSMickaël Salaün  * landlock_check_rule_fs - Filesystem rule evaluated during access check
5773f1f106eSMickaël Salaün  *
5783f1f106eSMickaël Salaün  * @domain: Enforcing domain (never NULL).
5793f1f106eSMickaël Salaün  * @rule: Matching rule with per-layer access masks (never NULL).
5803f1f106eSMickaël Salaün  * @access_request: Access mask evaluated against the rule (the domain's
5813f1f106eSMickaël Salaün  *                   handled mask during rename/link double-checks).
5823f1f106eSMickaël Salaün  * @dentry: Filesystem dentry being checked (never NULL).
5833f1f106eSMickaël Salaün  *
5843f1f106eSMickaël Salaün  * Emitted for each rule that matches during a filesystem access check.
5853f1f106eSMickaël Salaün  * The grants array shows the requested rights the rule grants at each
5863f1f106eSMickaël Salaün  * domain layer.  See Documentation/trace/events-landlock.rst for how to
5873f1f106eSMickaël Salaün  * interpret it.
5883f1f106eSMickaël Salaün  */
5893f1f106eSMickaël Salaün TRACE_EVENT(landlock_check_rule_fs,
5903f1f106eSMickaël Salaün 
5913f1f106eSMickaël Salaün 	TP_PROTO(const struct landlock_domain *domain,
5923f1f106eSMickaël Salaün 		 const struct landlock_rule *rule,
5933f1f106eSMickaël Salaün 		 access_mask_t access_request, const struct dentry *dentry),
5943f1f106eSMickaël Salaün 
5953f1f106eSMickaël Salaün 	TP_ARGS(domain, rule, access_request, dentry),
5963f1f106eSMickaël Salaün 
5973f1f106eSMickaël Salaün 	TP_STRUCT__entry(
5983f1f106eSMickaël Salaün 		__field(	__u64,		domain_id	)
5993f1f106eSMickaël Salaün 		__field(	access_mask_t,	access_request	)
6003f1f106eSMickaël Salaün 		__field(	dev_t,		dev		)
6013f1f106eSMickaël Salaün 		__field(	ino_t,		ino		)
6023f1f106eSMickaël Salaün 		__dynamic_array(access_mask_t,	grants,
6033f1f106eSMickaël Salaün 				domain->num_layers)
6043f1f106eSMickaël Salaün 	),
6053f1f106eSMickaël Salaün 
6063f1f106eSMickaël Salaün 	TP_fast_assign(
6073f1f106eSMickaël Salaün 		__entry->domain_id	= domain->hierarchy->id;
6083f1f106eSMickaël Salaün 		__entry->access_request	= access_request;
6093f1f106eSMickaël Salaün 		__entry->dev		= dentry->d_sb->s_dev;
6103f1f106eSMickaël Salaün 		__entry->ino		= d_backing_inode(dentry)->i_ino;
6113f1f106eSMickaël Salaün 
6123f1f106eSMickaël Salaün 		__trace_landlock_fill_layers(__get_dynamic_array(grants),
6133f1f106eSMickaël Salaün 					     __get_dynamic_array_len(grants) /
6143f1f106eSMickaël Salaün 						     sizeof(access_mask_t),
6153f1f106eSMickaël Salaün 					     rule, access_request);
6163f1f106eSMickaël Salaün 	),
6173f1f106eSMickaël Salaün 
6183f1f106eSMickaël Salaün 	TP_printk("domain=%llx access_request=%s dev=%u:%u ino=%lu grants=%s",
6193f1f106eSMickaël Salaün 		__entry->domain_id,
6203f1f106eSMickaël Salaün 		__print_flags(__entry->access_request, "|", _LANDLOCK_ACCESS_FS_NAMES),
6213f1f106eSMickaël Salaün 		MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino,
6223f1f106eSMickaël Salaün 		__print_landlock_layers(grants, _LANDLOCK_ACCESS_FS_NAMES))
6233f1f106eSMickaël Salaün );
6243f1f106eSMickaël Salaün 
6253f1f106eSMickaël Salaün /**
6263f1f106eSMickaël Salaün  * landlock_check_rule_net - Network port rule evaluated during access check
6273f1f106eSMickaël Salaün  *
6283f1f106eSMickaël Salaün  * @domain: Enforcing domain (never NULL).
6293f1f106eSMickaël Salaün  * @rule: Matching rule with per-layer access masks (never NULL).
6303f1f106eSMickaël Salaün  * @access_request: Access mask being requested.
6313f1f106eSMickaël Salaün  * @port: Network port being checked (host endianness).
6323f1f106eSMickaël Salaün  *
6333f1f106eSMickaël Salaün  * Emitted for each rule that matches during a network access check.  The
6343f1f106eSMickaël Salaün  * grants array shows the requested rights the rule grants at each domain
6353f1f106eSMickaël Salaün  * layer.  See Documentation/trace/events-landlock.rst for how to
6363f1f106eSMickaël Salaün  * interpret it.
6373f1f106eSMickaël Salaün  */
6383f1f106eSMickaël Salaün TRACE_EVENT(landlock_check_rule_net,
6393f1f106eSMickaël Salaün 
6403f1f106eSMickaël Salaün 	TP_PROTO(const struct landlock_domain *domain,
6413f1f106eSMickaël Salaün 		 const struct landlock_rule *rule,
6423f1f106eSMickaël Salaün 		 access_mask_t access_request, __u64 port),
6433f1f106eSMickaël Salaün 
6443f1f106eSMickaël Salaün 	TP_ARGS(domain, rule, access_request, port),
6453f1f106eSMickaël Salaün 
6463f1f106eSMickaël Salaün 	TP_STRUCT__entry(
6473f1f106eSMickaël Salaün 		__field(	__u64,		domain_id	)
6483f1f106eSMickaël Salaün 		__field(	access_mask_t,	access_request	)
6493f1f106eSMickaël Salaün 		__field(	__u64,		port		)
6503f1f106eSMickaël Salaün 		__dynamic_array(access_mask_t,	grants,
6513f1f106eSMickaël Salaün 				domain->num_layers)
6523f1f106eSMickaël Salaün 	),
6533f1f106eSMickaël Salaün 
6543f1f106eSMickaël Salaün 	TP_fast_assign(
6553f1f106eSMickaël Salaün 		__entry->domain_id	= domain->hierarchy->id;
6563f1f106eSMickaël Salaün 		__entry->access_request	= access_request;
6573f1f106eSMickaël Salaün 		__entry->port		= port;
6583f1f106eSMickaël Salaün 
6593f1f106eSMickaël Salaün 		__trace_landlock_fill_layers(__get_dynamic_array(grants),
6603f1f106eSMickaël Salaün 					     __get_dynamic_array_len(grants) /
6613f1f106eSMickaël Salaün 						     sizeof(access_mask_t),
6623f1f106eSMickaël Salaün 					     rule, access_request);
6633f1f106eSMickaël Salaün 	),
6643f1f106eSMickaël Salaün 
6653f1f106eSMickaël Salaün 	TP_printk("domain=%llx access_request=%s port=%llu grants=%s",
6663f1f106eSMickaël Salaün 		__entry->domain_id,
6673f1f106eSMickaël Salaün 		__print_flags(__entry->access_request, "|", _LANDLOCK_ACCESS_NET_NAMES),
6683f1f106eSMickaël Salaün 		__entry->port,
6693f1f106eSMickaël Salaün 		__print_landlock_layers(grants, _LANDLOCK_ACCESS_NET_NAMES))
6703f1f106eSMickaël Salaün );
6713f1f106eSMickaël Salaün 
67201ce260fSMickaël Salaün /**
67301ce260fSMickaël Salaün  * landlock_deny_access_fs - Filesystem access denied
67401ce260fSMickaël Salaün  *
67501ce260fSMickaël Salaün  * @hierarchy: Denying domain's hierarchy node (never NULL); its id is the
67601ce260fSMickaël Salaün  *             domain field.
67701ce260fSMickaël Salaün  * @same_exec: Whether the current task entered the denying domain itself.
67801ce260fSMickaël Salaün  * @logged: The domain's audit-logging decision for this denial.
67901ce260fSMickaël Salaün  * @blockers: Access mask that was blocked (zero for a mount-topology
68001ce260fSMickaël Salaün  *            change, whose only blocker is the operation itself).
68101ce260fSMickaël Salaün  * @path: Filesystem path that was denied (never NULL).
68201ce260fSMickaël Salaün  * @pathname: Resolved path string (never NULL; an error placeholder on
68301ce260fSMickaël Salaün  *            resolution failure).
68401ce260fSMickaël Salaün  *
68501ce260fSMickaël Salaün  * Emitted when a Landlock domain denies a filesystem access.
68601ce260fSMickaël Salaün  */
68701ce260fSMickaël Salaün TRACE_EVENT(landlock_deny_access_fs,
68801ce260fSMickaël Salaün 
68901ce260fSMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy, bool same_exec,
69001ce260fSMickaël Salaün 		 bool logged, access_mask_t blockers, const struct path *path,
69101ce260fSMickaël Salaün 		 const char *pathname),
69201ce260fSMickaël Salaün 
69301ce260fSMickaël Salaün 	TP_ARGS(hierarchy, same_exec, logged, blockers, path, pathname),
69401ce260fSMickaël Salaün 
69501ce260fSMickaël Salaün 	TP_STRUCT__entry(
69601ce260fSMickaël Salaün 		__field(	__u64,		domain_id	)
69701ce260fSMickaël Salaün 		__field(	bool,		same_exec	)
69801ce260fSMickaël Salaün 		__field(	bool,		logged		)
69901ce260fSMickaël Salaün 		__field(	access_mask_t,	blockers	)
70001ce260fSMickaël Salaün 		__field(	dev_t,		dev		)
70101ce260fSMickaël Salaün 		__field(	ino_t,		ino		)
70201ce260fSMickaël Salaün 		__string(	pathname,	pathname	)
70301ce260fSMickaël Salaün 	),
70401ce260fSMickaël Salaün 
70501ce260fSMickaël Salaün 	TP_fast_assign(
70601ce260fSMickaël Salaün 		const struct inode *inode = d_backing_inode(path->dentry);
70701ce260fSMickaël Salaün 
70801ce260fSMickaël Salaün 		__entry->domain_id	= hierarchy->id;
70901ce260fSMickaël Salaün 		__entry->same_exec	= same_exec;
71001ce260fSMickaël Salaün 		__entry->logged		= logged;
71101ce260fSMickaël Salaün 		__entry->blockers	= blockers;
71201ce260fSMickaël Salaün 		__entry->dev		= path->dentry->d_sb->s_dev;
71301ce260fSMickaël Salaün 		/*
71401ce260fSMickaël Salaün 		 * A negative dentry has no backing inode, so mirror the
71501ce260fSMickaël Salaün 		 * guard in dump_common_audit_data() and report inode 0.
71601ce260fSMickaël Salaün 		 */
71701ce260fSMickaël Salaün 		__entry->ino		= inode ? inode->i_ino : 0;
71801ce260fSMickaël Salaün 		__assign_str(pathname);
71901ce260fSMickaël Salaün 	),
72001ce260fSMickaël Salaün 
72101ce260fSMickaël Salaün 	TP_printk("domain=%llx same_exec=%d logged=%d blockers=%s dev=%u:%u ino=%lu path=%s",
72201ce260fSMickaël Salaün 		__entry->domain_id, __entry->same_exec, __entry->logged,
72301ce260fSMickaël Salaün 		__print_flags(__entry->blockers, "|", _LANDLOCK_ACCESS_FS_NAMES),
72401ce260fSMickaël Salaün 		MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino,
72501ce260fSMickaël Salaün 		__trace_print_untrusted_str(p, __get_str(pathname),
72601ce260fSMickaël Salaün 					    __get_dynamic_array_len(pathname) - 1))
72701ce260fSMickaël Salaün );
72801ce260fSMickaël Salaün 
72901ce260fSMickaël Salaün /**
73001ce260fSMickaël Salaün  * landlock_deny_access_net - Network access denied
73101ce260fSMickaël Salaün  *
73201ce260fSMickaël Salaün  * @hierarchy: Denying domain's hierarchy node (never NULL); its id is the
73301ce260fSMickaël Salaün  *             domain field.
73401ce260fSMickaël Salaün  * @same_exec: Whether the current task entered the denying domain itself.
73501ce260fSMickaël Salaün  * @logged: The domain's audit-logging decision for this denial.
73601ce260fSMickaël Salaün  * @blockers: Access mask that was blocked.
73701ce260fSMickaël Salaün  * @sk: Socket object (never NULL), read without a socket lock, so its
73801ce260fSMickaël Salaün  *      fields are a best-effort snapshot.  The denied endpoint is not
73901ce260fSMickaël Salaün  *      available: the hook runs before :manpage:`bind(2)` /
74001ce260fSMickaël Salaün  *      :manpage:`connect(2)` sets the socket addresses.
74101ce260fSMickaël Salaün  * @sport: Source port in host endianness, set for bind denials (zero for
74201ce260fSMickaël Salaün  *         an autobind/ephemeral port); zero for connect and send denials.
74301ce260fSMickaël Salaün  * @dport: Destination port in host endianness, set for connect and send
74401ce260fSMickaël Salaün  *         denials; zero for bind denials, and also zero for a UDP send to
74501ce260fSMickaël Salaün  *         an AF_UNSPEC address on an IPv6 socket (indistinguishable from a
74601ce260fSMickaël Salaün  *         real destination port 0).  The bind-vs-connect direction is
74701ce260fSMickaël Salaün  *         given by @blockers, not by which port is set.
74801ce260fSMickaël Salaün  *
74901ce260fSMickaël Salaün  * Emitted when a Landlock domain denies a network operation.
75001ce260fSMickaël Salaün  *
75101ce260fSMickaël Salaün  * The port fields are converted from the socket's network byte order to
75201ce260fSMickaël Salaün  * host endianness before emitting.
75301ce260fSMickaël Salaün  */
75401ce260fSMickaël Salaün TRACE_EVENT(landlock_deny_access_net,
75501ce260fSMickaël Salaün 
75601ce260fSMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy, bool same_exec,
75701ce260fSMickaël Salaün 		 bool logged, access_mask_t blockers, const struct sock *sk,
75801ce260fSMickaël Salaün 		 __u64 sport, __u64 dport),
75901ce260fSMickaël Salaün 
76001ce260fSMickaël Salaün 	TP_ARGS(hierarchy, same_exec, logged, blockers, sk, sport, dport),
76101ce260fSMickaël Salaün 
76201ce260fSMickaël Salaün 	TP_STRUCT__entry(
76301ce260fSMickaël Salaün 		__field(	__u64,		domain_id	)
76401ce260fSMickaël Salaün 		__field(	bool,		same_exec	)
76501ce260fSMickaël Salaün 		__field(	bool,		logged		)
76601ce260fSMickaël Salaün 		__field(	access_mask_t,	blockers	)
76701ce260fSMickaël Salaün 		__field(	__u64,		sport		)
76801ce260fSMickaël Salaün 		__field(	__u64,		dport		)
76901ce260fSMickaël Salaün 	),
77001ce260fSMickaël Salaün 
77101ce260fSMickaël Salaün 	TP_fast_assign(
77201ce260fSMickaël Salaün 		__entry->domain_id	= hierarchy->id;
77301ce260fSMickaël Salaün 		__entry->same_exec	= same_exec;
77401ce260fSMickaël Salaün 		__entry->logged		= logged;
77501ce260fSMickaël Salaün 		__entry->blockers	= blockers;
77601ce260fSMickaël Salaün 		__entry->sport		= sport;
77701ce260fSMickaël Salaün 		__entry->dport		= dport;
77801ce260fSMickaël Salaün 	),
77901ce260fSMickaël Salaün 
78001ce260fSMickaël Salaün 	TP_printk("domain=%llx same_exec=%d logged=%d blockers=%s sport=%llu dport=%llu",
78101ce260fSMickaël Salaün 		__entry->domain_id, __entry->same_exec, __entry->logged,
78201ce260fSMickaël Salaün 		__print_flags(__entry->blockers, "|", _LANDLOCK_ACCESS_NET_NAMES),
78301ce260fSMickaël Salaün 		__entry->sport, __entry->dport)
78401ce260fSMickaël Salaün );
78501ce260fSMickaël Salaün 
786*bb91730fSMickaël Salaün /**
787*bb91730fSMickaël Salaün  * landlock_deny_ptrace - Ptrace access denied by a Landlock domain
788*bb91730fSMickaël Salaün  *
789*bb91730fSMickaël Salaün  * @hierarchy: Denying domain's hierarchy node (never NULL); its id is the
790*bb91730fSMickaël Salaün  *             domain field.
791*bb91730fSMickaël Salaün  * @same_exec: Whether the current task entered the denying domain itself.
792*bb91730fSMickaël Salaün  * @logged: The domain's audit-logging decision for this denial.
793*bb91730fSMickaël Salaün  * @tracee_domain_id: The tracee's Landlock domain ID, or 0 if the tracee
794*bb91730fSMickaël Salaün  *                    is unsandboxed.
795*bb91730fSMickaël Salaün  * @tracee: The target task ptrace acted on (never NULL).  tracee_pid is
796*bb91730fSMickaël Salaün  *          the init-namespace TGID (like audit's opid).
797*bb91730fSMickaël Salaün  *
798*bb91730fSMickaël Salaün  * Emitted when a Landlock domain denies a ptrace operation.
799*bb91730fSMickaël Salaün  */
800*bb91730fSMickaël Salaün TRACE_EVENT(landlock_deny_ptrace,
801*bb91730fSMickaël Salaün 
802*bb91730fSMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy, bool same_exec,
803*bb91730fSMickaël Salaün 		 bool logged, u64 tracee_domain_id,
804*bb91730fSMickaël Salaün 		 const struct task_struct *tracee),
805*bb91730fSMickaël Salaün 
806*bb91730fSMickaël Salaün 	TP_ARGS(hierarchy, same_exec, logged, tracee_domain_id, tracee),
807*bb91730fSMickaël Salaün 
808*bb91730fSMickaël Salaün 	TP_STRUCT__entry(
809*bb91730fSMickaël Salaün 		__field(	__u64,		domain_id	)
810*bb91730fSMickaël Salaün 		__field(	bool,		same_exec	)
811*bb91730fSMickaël Salaün 		__field(	bool,		logged		)
812*bb91730fSMickaël Salaün 		__field(	__u64,		tracee_domain_id)
813*bb91730fSMickaël Salaün 		__field(	pid_t,		tracee_pid	)
814*bb91730fSMickaël Salaün 		__string(	tracee_comm,	tracee->comm	)
815*bb91730fSMickaël Salaün 	),
816*bb91730fSMickaël Salaün 
817*bb91730fSMickaël Salaün 	TP_fast_assign(
818*bb91730fSMickaël Salaün 		__entry->domain_id	= hierarchy->id;
819*bb91730fSMickaël Salaün 		__entry->same_exec	= same_exec;
820*bb91730fSMickaël Salaün 		__entry->logged		= logged;
821*bb91730fSMickaël Salaün 		__entry->tracee_domain_id = tracee_domain_id;
822*bb91730fSMickaël Salaün 		__entry->tracee_pid	= task_tgid_nr((struct task_struct *)tracee);
823*bb91730fSMickaël Salaün 		__assign_str(tracee_comm);
824*bb91730fSMickaël Salaün 	),
825*bb91730fSMickaël Salaün 
826*bb91730fSMickaël Salaün 	TP_printk("domain=%llx same_exec=%d logged=%d tracee_domain=%llx tracee_pid=%d tracee_comm=%s",
827*bb91730fSMickaël Salaün 		__entry->domain_id, __entry->same_exec, __entry->logged,
828*bb91730fSMickaël Salaün 		__entry->tracee_domain_id, __entry->tracee_pid,
829*bb91730fSMickaël Salaün 		__trace_print_untrusted_str(p, __get_str(tracee_comm),
830*bb91730fSMickaël Salaün 					    __get_dynamic_array_len(tracee_comm) - 1))
831*bb91730fSMickaël Salaün );
832*bb91730fSMickaël Salaün 
833*bb91730fSMickaël Salaün /**
834*bb91730fSMickaël Salaün  * landlock_deny_scope_signal - Signal delivery denied by
835*bb91730fSMickaël Salaün  *                               LANDLOCK_SCOPE_SIGNAL
836*bb91730fSMickaël Salaün  *
837*bb91730fSMickaël Salaün  * @hierarchy: Denying domain's hierarchy node (never NULL); its id is the
838*bb91730fSMickaël Salaün  *             domain field.
839*bb91730fSMickaël Salaün  * @same_exec: Whether the current task entered the denying domain itself.
840*bb91730fSMickaël Salaün  * @logged: The domain's audit-logging decision for this denial.
841*bb91730fSMickaël Salaün  * @target_domain_id: The target's Landlock domain ID, or 0 if the target
842*bb91730fSMickaël Salaün  *                    is unsandboxed.
843*bb91730fSMickaël Salaün  * @target: The task the signal was aimed at (never NULL).  target_pid is
844*bb91730fSMickaël Salaün  *          the init-namespace TGID (like audit's opid).
845*bb91730fSMickaël Salaün  *
846*bb91730fSMickaël Salaün  * Emitted when a Landlock domain denies signal delivery to a scoped-out
847*bb91730fSMickaël Salaün  * target.
848*bb91730fSMickaël Salaün  */
849*bb91730fSMickaël Salaün TRACE_EVENT(landlock_deny_scope_signal,
850*bb91730fSMickaël Salaün 
851*bb91730fSMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy, bool same_exec,
852*bb91730fSMickaël Salaün 		 bool logged, u64 target_domain_id,
853*bb91730fSMickaël Salaün 		 const struct task_struct *target),
854*bb91730fSMickaël Salaün 
855*bb91730fSMickaël Salaün 	TP_ARGS(hierarchy, same_exec, logged, target_domain_id, target),
856*bb91730fSMickaël Salaün 
857*bb91730fSMickaël Salaün 	TP_STRUCT__entry(
858*bb91730fSMickaël Salaün 		__field(	__u64,		domain_id	)
859*bb91730fSMickaël Salaün 		__field(	bool,		same_exec	)
860*bb91730fSMickaël Salaün 		__field(	bool,		logged		)
861*bb91730fSMickaël Salaün 		__field(	__u64,		target_domain_id)
862*bb91730fSMickaël Salaün 		__field(	pid_t,		target_pid	)
863*bb91730fSMickaël Salaün 		__string(	target_comm,	target->comm	)
864*bb91730fSMickaël Salaün 	),
865*bb91730fSMickaël Salaün 
866*bb91730fSMickaël Salaün 	TP_fast_assign(
867*bb91730fSMickaël Salaün 		__entry->domain_id	= hierarchy->id;
868*bb91730fSMickaël Salaün 		__entry->same_exec	= same_exec;
869*bb91730fSMickaël Salaün 		__entry->logged		= logged;
870*bb91730fSMickaël Salaün 		__entry->target_domain_id = target_domain_id;
871*bb91730fSMickaël Salaün 		__entry->target_pid	= task_tgid_nr((struct task_struct *)target);
872*bb91730fSMickaël Salaün 		__assign_str(target_comm);
873*bb91730fSMickaël Salaün 	),
874*bb91730fSMickaël Salaün 
875*bb91730fSMickaël Salaün 	TP_printk("domain=%llx same_exec=%d logged=%d target_domain=%llx target_pid=%d target_comm=%s",
876*bb91730fSMickaël Salaün 		__entry->domain_id, __entry->same_exec, __entry->logged,
877*bb91730fSMickaël Salaün 		__entry->target_domain_id, __entry->target_pid,
878*bb91730fSMickaël Salaün 		__trace_print_untrusted_str(p, __get_str(target_comm),
879*bb91730fSMickaël Salaün 					    __get_dynamic_array_len(target_comm) - 1))
880*bb91730fSMickaël Salaün );
881*bb91730fSMickaël Salaün 
882*bb91730fSMickaël Salaün /**
883*bb91730fSMickaël Salaün  * landlock_deny_scope_abstract_unix_socket - Abstract unix socket access
884*bb91730fSMickaël Salaün  *     denied by LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
885*bb91730fSMickaël Salaün  *
886*bb91730fSMickaël Salaün  * @hierarchy: Denying domain's hierarchy node (never NULL); its id is the
887*bb91730fSMickaël Salaün  *             domain field.
888*bb91730fSMickaël Salaün  * @same_exec: Whether the current task entered the denying domain itself.
889*bb91730fSMickaël Salaün  * @logged: The domain's audit-logging decision for this denial.
890*bb91730fSMickaël Salaün  * @peer_domain_id: The peer's Landlock domain ID, or 0 if the peer is
891*bb91730fSMickaël Salaün  *                  unsandboxed.
892*bb91730fSMickaël Salaün  * @peer: Peer socket (never NULL).  peer_pid is best-effort: it is 0 for
893*bb91730fSMickaël Salaün  *        a datagram peer (no SO_PEERCRED), so sun_path is the reliable
894*bb91730fSMickaël Salaün  *        peer identifier.
895*bb91730fSMickaël Salaün  *
896*bb91730fSMickaël Salaün  * Emitted when a Landlock domain denies access to a scoped-out abstract
897*bb91730fSMickaël Salaün  * unix socket.
898*bb91730fSMickaël Salaün  */
899*bb91730fSMickaël Salaün TRACE_EVENT(landlock_deny_scope_abstract_unix_socket,
900*bb91730fSMickaël Salaün 
901*bb91730fSMickaël Salaün 	TP_PROTO(const struct landlock_hierarchy *hierarchy, bool same_exec,
902*bb91730fSMickaël Salaün 		 bool logged, u64 peer_domain_id, const struct sock *peer),
903*bb91730fSMickaël Salaün 
904*bb91730fSMickaël Salaün 	TP_ARGS(hierarchy, same_exec, logged, peer_domain_id, peer),
905*bb91730fSMickaël Salaün 
906*bb91730fSMickaël Salaün 	TP_STRUCT__entry(
907*bb91730fSMickaël Salaün 		__field(	__u64,		domain_id	)
908*bb91730fSMickaël Salaün 		__field(	bool,		same_exec	)
909*bb91730fSMickaël Salaün 		__field(	bool,		logged		)
910*bb91730fSMickaël Salaün 		__field(	__u64,		peer_domain_id	)
911*bb91730fSMickaël Salaün 		__field(	pid_t,		peer_pid	)
912*bb91730fSMickaël Salaün 		/*
913*bb91730fSMickaël Salaün 		 * Abstract socket names are untrusted binary data from
914*bb91730fSMickaël Salaün 		 * user space.  Use __string_len because abstract names
915*bb91730fSMickaël Salaün 		 * are not NUL-terminated; their length is determined by
916*bb91730fSMickaël Salaün 		 * addr->len.  unix_sk(peer)->addr is stable here because
917*bb91730fSMickaël Salaün 		 * the caller (hook_unix_stream_connect or
918*bb91730fSMickaël Salaün 		 * hook_unix_may_send) holds unix_state_lock(peer).
919*bb91730fSMickaël Salaün 		 */
920*bb91730fSMickaël Salaün 		__string_len(	sun_path,
921*bb91730fSMickaël Salaün 				unix_sk(peer)->addr ?
922*bb91730fSMickaël Salaün 					unix_sk(peer)->addr->name->sun_path + 1 :
923*bb91730fSMickaël Salaün 					"",
924*bb91730fSMickaël Salaün 				unix_sk(peer)->addr ?
925*bb91730fSMickaël Salaün 					unix_sk(peer)->addr->len -
926*bb91730fSMickaël Salaün 						offsetof(struct sockaddr_un,
927*bb91730fSMickaël Salaün 							 sun_path) - 1 :
928*bb91730fSMickaël Salaün 					0)
929*bb91730fSMickaël Salaün 	),
930*bb91730fSMickaël Salaün 
931*bb91730fSMickaël Salaün 	TP_fast_assign(
932*bb91730fSMickaël Salaün 		struct pid *peer_pid;
933*bb91730fSMickaël Salaün 
934*bb91730fSMickaël Salaün 		lockdep_assert_held(&unix_sk(peer)->lock);
935*bb91730fSMickaël Salaün 		__entry->domain_id	= hierarchy->id;
936*bb91730fSMickaël Salaün 		__entry->same_exec	= same_exec;
937*bb91730fSMickaël Salaün 		__entry->logged		= logged;
938*bb91730fSMickaël Salaün 		__entry->peer_domain_id	= peer_domain_id;
939*bb91730fSMickaël Salaün 		/*
940*bb91730fSMickaël Salaün 		 * Best-effort (0 for a datagram peer).  sk_peer_pid is
941*bb91730fSMickaël Salaün 		 * canonically guarded by sk->sk_peer_lock, but the target
942*bb91730fSMickaël Salaün 		 * peer's peercred is set once and not updated concurrently in
943*bb91730fSMickaël Salaün 		 * these hooks, so this READ_ONCE() is safe; sun_path is the
944*bb91730fSMickaël Salaün 		 * reliable identifier.
945*bb91730fSMickaël Salaün 		 */
946*bb91730fSMickaël Salaün 		peer_pid		= READ_ONCE(peer->sk_peer_pid);
947*bb91730fSMickaël Salaün 		__entry->peer_pid	= peer_pid ? pid_nr(peer_pid) : 0;
948*bb91730fSMickaël Salaün 		__assign_str(sun_path);
949*bb91730fSMickaël Salaün 	),
950*bb91730fSMickaël Salaün 
951*bb91730fSMickaël Salaün 	TP_printk("domain=%llx same_exec=%d logged=%d peer_domain=%llx peer_pid=%d sun_path=%s",
952*bb91730fSMickaël Salaün 		__entry->domain_id, __entry->same_exec, __entry->logged,
953*bb91730fSMickaël Salaün 		__entry->peer_domain_id, __entry->peer_pid,
954*bb91730fSMickaël Salaün 		__trace_print_untrusted_str(p, __get_str(sun_path),
955*bb91730fSMickaël Salaün 					    __get_dynamic_array_len(sun_path) - 1))
956*bb91730fSMickaël Salaün );
957*bb91730fSMickaël Salaün 
958b4540a72SMickaël Salaün #undef _LANDLOCK_NAME_ENTRY
959b4540a72SMickaël Salaün 
960b4540a72SMickaël Salaün #endif /* _TRACE_LANDLOCK_H */
961b4540a72SMickaël Salaün 
962b4540a72SMickaël Salaün /* This part must be outside protection */
963b4540a72SMickaël Salaün #include <trace/define_trace.h>
964b4540a72SMickaël Salaün 
965b4540a72SMickaël Salaün /* clang-format on */
966