1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Landlock - Tracepoint helpers 4 * 5 * Copyright © 2025 Microsoft Corporation 6 * Copyright © 2026 Cloudflare, Inc. 7 */ 8 9 #include <linux/cleanup.h> 10 #include <linux/dcache.h> 11 #include <linux/err.h> 12 #include <linux/fs.h> 13 #include <linux/lsm_audit.h> 14 #include <net/sock.h> 15 16 #include "access.h" 17 #include "domain.h" 18 #include "fs.h" 19 #include "log.h" 20 #include "ruleset.h" 21 #include "trace.h" 22 23 /* 24 * Generates the tracepoint definitions in this translation unit. The trace 25 * event header dereferences the traced objects in TP_fast_assign, so the full 26 * struct definitions (e.g. ruleset.h, domain.h) must be included before it. 27 */ 28 #define CREATE_TRACE_POINTS 29 #include <trace/events/landlock.h> 30 31 /** 32 * landlock_trace_free_domain - Emit a tracepoint on domain deallocation 33 * 34 * @hierarchy: The domain's hierarchy being deallocated. 35 * 36 * Fires only for a hierarchy whose creation event was emitted, i.e. one that 37 * left LANDLOCK_LOG_UNCOMMITTED in landlock_restrict_self(). This keeps the 38 * create/free pair balanced: a hierarchy that never became observable is freed 39 * silently, while a domain that landlock_restrict_self() created and a 40 * thread-sync failure then aborted still fires free_domain, because its 41 * creation event already fired. 42 * 43 * Called from landlock_log_free_domain(). 44 */ 45 void landlock_trace_free_domain(const struct landlock_hierarchy *const hierarchy) 46 { 47 /* 48 * The log_status read is a correctness guard (keep the create/free pair 49 * balanced), not a cost guard, so this cold path needs no 50 * trace_..._enabled() check: the tracepoint is a static-branch no-op 51 * when disabled. The denial path guards trace_..._enabled() instead 52 * because it does expensive __getname()/path work before emitting. 53 */ 54 if (READ_ONCE(hierarchy->log_status) != LANDLOCK_LOG_UNCOMMITTED) 55 trace_landlock_free_domain(hierarchy); 56 } 57 58 /** 59 * landlock_trace_denial - Emit a tracepoint for a denied access request 60 * 61 * @request: Detail of the user space request. 62 * @youngest_denied: The youngest hierarchy node that denied the access. 63 * @missing: The set of denied access rights. 64 * @same_exec: Whether the current task is the same executable that called 65 * landlock_restrict_self() for the denying domain, as computed 66 * by landlock_log_denial(). 67 * @logged: Whether the domain's policy selects this denial for logging, as 68 * computed by landlock_log_denial(). 69 * 70 * Emits the tracepoint matching @request->type when its event is enabled. 71 * Unlike audit, fires regardless of @logged; the value is recorded in the event 72 * so consumers can filter on it. 73 * 74 * Called from landlock_log_denial(). 75 */ 76 void landlock_trace_denial( 77 const struct landlock_request *const request, 78 const struct landlock_hierarchy *const youngest_denied, 79 const access_mask_t missing, const bool same_exec, const bool logged) 80 { 81 switch (request->type) { 82 case LANDLOCK_REQUEST_FS_ACCESS: 83 case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY: 84 if (trace_landlock_deny_access_fs_enabled()) { 85 char *buf __free(__putname) = __getname(); 86 struct path dentry_path; 87 const char *pathname; 88 const struct path *path = NULL; 89 90 /* 91 * Selects the path from the audit data type, as 92 * dump_common_audit_data() does. A FS_ACCESS denial 93 * carries a file (hook_file_truncate) or an ioctl op 94 * (hook_file_ioctl) rather than a path; 95 * FS_CHANGE_TOPOLOGY carries a path or a bare dentry. 96 * Reading the wrong union member would dereference 97 * garbage, so every reachable type is handled here. 98 */ 99 switch (request->audit.type) { 100 case LSM_AUDIT_DATA_FILE: 101 path = &request->audit.u.file->f_path; 102 break; 103 case LSM_AUDIT_DATA_IOCTL_OP: 104 path = &request->audit.u.op->path; 105 break; 106 case LSM_AUDIT_DATA_DENTRY: 107 /* 108 * Build a path on the stack with the real 109 * dentry so TP_fast_assign can extract dev and 110 * ino; the mnt field is unused there. 111 */ 112 dentry_path = (struct path){ 113 .dentry = request->audit.u.dentry, 114 }; 115 path = &dentry_path; 116 break; 117 case LSM_AUDIT_DATA_PATH: 118 path = &request->audit.u.path; 119 break; 120 default: 121 WARN_ONCE(1, 122 "Unhandled Landlock FS audit type %d", 123 request->audit.type); 124 break; 125 } 126 127 if (!path) 128 break; 129 130 if (!buf) { 131 pathname = "<no_mem>"; 132 } else if (request->audit.type == 133 LSM_AUDIT_DATA_DENTRY) { 134 /* No vfsmount: render the dentry path alone. */ 135 pathname = dentry_path_raw( 136 request->audit.u.dentry, buf, PATH_MAX); 137 if (IS_ERR(pathname)) 138 pathname = 139 PTR_ERR(pathname) == 140 -ENAMETOOLONG ? 141 "<too_long>" : 142 "<unreachable>"; 143 } else { 144 pathname = resolve_path_for_trace(path, buf); 145 } 146 147 trace_landlock_deny_access_fs(youngest_denied, 148 same_exec, logged, 149 missing, path, pathname); 150 } 151 break; 152 case LANDLOCK_REQUEST_NET_ACCESS: 153 if (trace_landlock_deny_access_net_enabled()) 154 trace_landlock_deny_access_net( 155 youngest_denied, same_exec, logged, missing, 156 request->audit.u.net->sk, 157 ntohs(request->audit.u.net->sport), 158 ntohs(request->audit.u.net->dport)); 159 break; 160 case LANDLOCK_REQUEST_PTRACE: 161 if (trace_landlock_deny_ptrace_enabled()) 162 trace_landlock_deny_ptrace(youngest_denied, same_exec, 163 logged, 164 request->other_domain_id, 165 request->audit.u.tsk); 166 break; 167 case LANDLOCK_REQUEST_SCOPE_SIGNAL: 168 if (trace_landlock_deny_scope_signal_enabled()) 169 trace_landlock_deny_scope_signal( 170 youngest_denied, same_exec, logged, 171 request->other_domain_id, request->audit.u.tsk); 172 break; 173 case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET: 174 if (trace_landlock_deny_scope_abstract_unix_socket_enabled()) 175 trace_landlock_deny_scope_abstract_unix_socket( 176 youngest_denied, same_exec, logged, 177 request->other_domain_id, 178 request->audit.u.net->sk); 179 break; 180 default: 181 WARN_ONCE(1, "Unhandled Landlock request type %d", 182 request->type); 183 break; 184 } 185 } 186