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