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 <kunit/test.h> 10 #include <linux/cleanup.h> 11 #include <linux/dcache.h> 12 #include <linux/err.h> 13 #include <linux/fs.h> 14 #include <linux/lsm_audit.h> 15 #include <linux/socket.h> 16 #include <net/sock.h> 17 18 #include "access.h" 19 #include "domain.h" 20 #include "fs.h" 21 #include "log.h" 22 #include "ruleset.h" 23 #include "trace.h" 24 25 /* 26 * Generates the tracepoint definitions in this translation unit. The trace 27 * event header dereferences the traced objects in TP_fast_assign, so the full 28 * struct definitions (e.g. ruleset.h, domain.h) must be included before it. 29 */ 30 #define CREATE_TRACE_POINTS 31 #include <trace/events/landlock.h> 32 33 /** 34 * landlock_trace_free_domain - Emit a tracepoint on domain deallocation 35 * 36 * @hierarchy: The domain's hierarchy being deallocated. 37 * 38 * Fires only for a hierarchy whose creation event was emitted, i.e. one that 39 * left LANDLOCK_LOG_UNCOMMITTED in landlock_restrict_self(). This keeps the 40 * create/free pair balanced: a hierarchy that never became observable is freed 41 * silently, while a domain that landlock_restrict_self() created and a 42 * thread-sync failure then aborted still fires free_domain, because its 43 * creation event already fired. 44 * 45 * Called from landlock_log_free_domain(). 46 */ 47 void landlock_trace_free_domain(const struct landlock_hierarchy *const hierarchy) 48 { 49 /* 50 * The log_status read is a correctness guard (keep the create/free pair 51 * balanced), not a cost guard, so this cold path needs no 52 * trace_..._enabled() check: the tracepoint is a static-branch no-op 53 * when disabled. The denial path guards trace_..._enabled() instead 54 * because it does expensive __getname()/path work before emitting. 55 */ 56 if (READ_ONCE(hierarchy->log_status) != LANDLOCK_LOG_UNCOMMITTED) 57 trace_landlock_free_domain(hierarchy); 58 } 59 60 /** 61 * landlock_trace_denial - Emit a tracepoint for a denied access request 62 * 63 * @request: Detail of the user space request. 64 * @youngest_denied: The youngest hierarchy node that denied the access. 65 * @missing: The final missing access or permission subset, when applicable. 66 * @same_exec: Whether the policy subject is the same executable that called 67 * landlock_restrict_self() for the denying domain, as computed 68 * by landlock_log_denial(). 69 * @logged: Whether the domain's policy selects this denial for logging, as 70 * computed by landlock_log_denial(). 71 * 72 * Emits the tracepoint matching @request->type when its event is enabled. 73 * Unlike audit, fires regardless of @logged; the value is recorded in the event 74 * so consumers can filter on it. 75 * 76 * Called from landlock_log_denial(). 77 */ 78 void landlock_trace_denial( 79 const struct landlock_request *const request, 80 const struct landlock_hierarchy *const youngest_denied, 81 const access_mask_t missing, const bool same_exec, const bool logged) 82 { 83 switch (request->type) { 84 case LANDLOCK_REQUEST_NAMESPACE: 85 if (trace_landlock_deny_permission_namespace_enabled()) { 86 const struct landlock_blockers blockers = { 87 .access = missing, 88 .type = request->type, 89 }; 90 91 trace_landlock_deny_permission_namespace( 92 youngest_denied, same_exec, logged, &blockers, 93 request->audit.u.ns.ns_type, 94 request->audit.u.ns.ns_id); 95 } 96 break; 97 case LANDLOCK_REQUEST_CAPABILITY: 98 if (trace_landlock_deny_permission_capability_enabled()) { 99 const struct landlock_blockers blockers = { 100 .access = missing, 101 .type = request->type, 102 }; 103 104 trace_landlock_deny_permission_capability( 105 youngest_denied, same_exec, logged, &blockers, 106 request->audit.u.cap); 107 } 108 break; 109 case LANDLOCK_REQUEST_FS_ACCESS: 110 case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY: 111 if (trace_landlock_deny_access_fs_enabled()) { 112 const struct landlock_blockers blockers = { 113 .access = missing, 114 .type = request->type, 115 }; 116 char *buf __free(__putname) = __getname(); 117 struct path dentry_path; 118 const char *pathname; 119 const struct path *path = NULL; 120 121 /* 122 * Selects the path from the audit data type, as 123 * dump_common_audit_data() does. A FS_ACCESS denial 124 * carries a file (hook_file_truncate) or an ioctl op 125 * (hook_file_ioctl) rather than a path; 126 * FS_CHANGE_TOPOLOGY carries a path or a bare dentry. 127 * Reading the wrong union member would dereference 128 * garbage, so every reachable type is handled here. 129 */ 130 switch (request->audit.type) { 131 case LSM_AUDIT_DATA_FILE: 132 path = &request->audit.u.file->f_path; 133 break; 134 case LSM_AUDIT_DATA_IOCTL_OP: 135 path = &request->audit.u.op->path; 136 break; 137 case LSM_AUDIT_DATA_DENTRY: 138 /* 139 * Build a path on the stack with the real 140 * dentry so TP_fast_assign can extract dev and 141 * ino; the mnt field is unused there. 142 */ 143 dentry_path = (struct path){ 144 .dentry = request->audit.u.dentry, 145 }; 146 path = &dentry_path; 147 break; 148 case LSM_AUDIT_DATA_PATH: 149 path = &request->audit.u.path; 150 break; 151 default: 152 WARN_ONCE(1, 153 "Unhandled Landlock FS audit type %d", 154 request->audit.type); 155 break; 156 } 157 158 if (!path) 159 break; 160 161 if (!buf) { 162 pathname = "<no_mem>"; 163 } else if (request->audit.type == 164 LSM_AUDIT_DATA_DENTRY) { 165 /* No vfsmount: render the dentry path alone. */ 166 pathname = dentry_path_raw( 167 request->audit.u.dentry, buf, PATH_MAX); 168 if (IS_ERR(pathname)) 169 pathname = 170 PTR_ERR(pathname) == 171 -ENAMETOOLONG ? 172 "<too_long>" : 173 "<unreachable>"; 174 } else { 175 pathname = resolve_path_for_trace(path, buf); 176 } 177 178 trace_landlock_deny_access_fs(youngest_denied, 179 same_exec, logged, 180 &blockers, path, 181 pathname); 182 } 183 break; 184 case LANDLOCK_REQUEST_NET_ACCESS: 185 if (trace_landlock_deny_access_net_enabled()) { 186 const struct landlock_net_trace *const trace_net = 187 request->trace_net; 188 const struct landlock_blockers blockers = { 189 .access = missing, 190 .type = request->type, 191 }; 192 struct sockaddr_storage address = {}; 193 194 if (WARN_ON_ONCE(!trace_net || !trace_net->address)) 195 return; 196 197 if (WARN_ON_ONCE( 198 trace_net->addrlen < 199 (int)offsetofend(struct sockaddr, 200 sa_family) || 201 trace_net->addrlen > (int)sizeof(address))) 202 return; 203 204 memcpy(&address, trace_net->address, 205 trace_net->addrlen); 206 trace_landlock_deny_access_net( 207 youngest_denied, same_exec, logged, &blockers, 208 request->audit.u.net->sk, 209 trace_net->socket_family, &address, 210 trace_net->addrlen); 211 } 212 break; 213 case LANDLOCK_REQUEST_PTRACE: 214 if (trace_landlock_deny_ptrace_enabled()) { 215 const struct landlock_ptrace_trace *const trace_ptrace = 216 request->trace_ptrace; 217 218 if (WARN_ON_ONCE(!trace_ptrace || 219 !trace_ptrace->tracer)) 220 return; 221 222 trace_landlock_deny_ptrace( 223 youngest_denied, same_exec, logged, 224 trace_ptrace->tracee_domain_id, 225 request->audit.u.tsk, trace_ptrace->tracer); 226 } 227 break; 228 case LANDLOCK_REQUEST_SCOPE_SIGNAL: 229 if (trace_landlock_deny_scope_signal_enabled()) { 230 const struct landlock_signal_trace *const trace_signal = 231 request->trace_signal; 232 233 if (WARN_ON_ONCE(!trace_signal)) 234 return; 235 236 trace_landlock_deny_scope_signal( 237 youngest_denied, same_exec, logged, 238 trace_signal->target_domain_id, 239 request->audit.u.tsk, trace_signal->signal); 240 } 241 break; 242 case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET: 243 if (trace_landlock_deny_scope_abstract_unix_socket_enabled()) 244 trace_landlock_deny_scope_abstract_unix_socket( 245 youngest_denied, same_exec, logged, 246 request->other_domain_id, 247 request->audit.u.net->sk); 248 break; 249 default: 250 WARN_ONCE(1, "Unhandled Landlock request type %d", 251 request->type); 252 break; 253 } 254 } 255 256 #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST 257 258 static void test_trace_seq_init(struct trace_seq *const seq, const size_t size) 259 { 260 memset(seq, 0, sizeof(*seq)); 261 seq_buf_init(&seq->seq, seq->buffer, size); 262 } 263 264 static void test_untrusted_str_data(struct kunit *const test) 265 { 266 const char binary[] = { 'a', '\0', '<' }; 267 static const char ellipsis[] = "\xe2\x80\xa6"; 268 struct trace_seq *const seq = 269 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 270 const char *output; 271 272 KUNIT_ASSERT_NOT_NULL(test, seq); 273 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 274 output = __trace_print_untrusted_str(seq, "<too_long>", 10); 275 KUNIT_ASSERT_NOT_NULL(test, output); 276 KUNIT_EXPECT_STREQ(test, output, "<too_long>"); 277 278 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 279 output = __trace_print_untrusted_str(seq, binary, sizeof(binary)); 280 KUNIT_ASSERT_NOT_NULL(test, output); 281 KUNIT_EXPECT_STREQ(test, output, "a\\000<"); 282 283 /* Input ellipsis bytes are escaped and cannot mimic the raw marker. */ 284 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 285 output = __trace_print_untrusted_str(seq, ellipsis, 286 sizeof(ellipsis) - 1); 287 KUNIT_ASSERT_NOT_NULL(test, output); 288 KUNIT_EXPECT_STREQ(test, output, "\\342\\200\\246"); 289 } 290 291 static void test_untrusted_str_boundaries(struct kunit *const test) 292 { 293 static const char escaped_space[] = "\\040"; 294 const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE; 295 const size_t marker_len = sizeof(TRACE_TRUNCATION_MARKER) - 1; 296 const size_t escape_len = sizeof(escaped_space) - 1; 297 const size_t exact_prefix_len = 298 output_size - marker_len - 1 - escape_len; 299 const size_t short_prefix_len = exact_prefix_len + 1; 300 struct trace_seq *const seq = 301 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 302 char *const input = kunit_kmalloc(test, output_size + 1, GFP_KERNEL); 303 char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL); 304 const char *output; 305 306 KUNIT_ASSERT_NOT_NULL(test, seq); 307 KUNIT_ASSERT_NOT_NULL(test, input); 308 KUNIT_ASSERT_NOT_NULL(test, expected); 309 310 /* The escaped string and its trailing NUL exactly fit the limit. */ 311 memset(input, 'a', output_size - 1); 312 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 313 output = __trace_print_untrusted_str(seq, input, output_size - 1); 314 KUNIT_ASSERT_NOT_NULL(test, output); 315 KUNIT_EXPECT_EQ(test, seq->seq.len, output_size); 316 KUNIT_EXPECT_EQ(test, memcmp(output, input, output_size - 1), 0); 317 318 /* Stop before a four-byte escape when only three bytes remain. */ 319 memset(input, 'a', short_prefix_len); 320 input[short_prefix_len] = ' '; 321 memset(input + short_prefix_len + 1, 'b', 5); 322 memset(expected, 'a', short_prefix_len); 323 memcpy(expected + short_prefix_len, TRACE_TRUNCATION_MARKER, 324 marker_len + 1); 325 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 326 output = __trace_print_untrusted_str(seq, input, short_prefix_len + 6); 327 KUNIT_ASSERT_NOT_NULL(test, output); 328 KUNIT_EXPECT_STREQ(test, output, expected); 329 330 /* Include a four-byte escape that exactly fills the prefix capacity. */ 331 memset(input, 'a', exact_prefix_len); 332 input[exact_prefix_len] = ' '; 333 memset(input + exact_prefix_len + 1, 'b', marker_len + 1); 334 memset(expected, 'a', exact_prefix_len); 335 memcpy(expected + exact_prefix_len, escaped_space, escape_len); 336 memcpy(expected + exact_prefix_len + escape_len, 337 TRACE_TRUNCATION_MARKER, marker_len + 1); 338 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 339 output = __trace_print_untrusted_str(seq, input, 340 exact_prefix_len + marker_len + 2); 341 KUNIT_ASSERT_NOT_NULL(test, output); 342 KUNIT_EXPECT_STREQ(test, output, expected); 343 344 /* Literal backslashes remain escaped in complete output. */ 345 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 346 output = __trace_print_untrusted_str(seq, "/\\000", 5); 347 KUNIT_ASSERT_NOT_NULL(test, output); 348 KUNIT_EXPECT_STREQ(test, output, "/\\\\000"); 349 } 350 351 static void test_untrusted_str_cursor(struct kunit *const test) 352 { 353 const size_t padding_len = 354 TRACE_SEQ_BUFFER_SIZE - TRACE_UNTRUSTED_STR_OUTPUT_SIZE + 1; 355 struct trace_seq *const seq = 356 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 357 char *const padding = kunit_kzalloc(test, padding_len, GFP_KERNEL); 358 const char *output; 359 360 KUNIT_ASSERT_NOT_NULL(test, seq); 361 KUNIT_ASSERT_NOT_NULL(test, padding); 362 363 /* Accept available space exactly equal to the fixed reservation. */ 364 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 365 trace_seq_putmem(seq, padding, padding_len - 1); 366 output = __trace_print_untrusted_str(seq, "/a", 2); 367 KUNIT_ASSERT_NOT_NULL(test, output); 368 KUNIT_EXPECT_STREQ(test, output, "/a"); 369 KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len - 1 + sizeof("/a")); 370 371 /* Reject one byte less without changing the scratch cursor. */ 372 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 373 trace_seq_putmem(seq, padding, padding_len); 374 output = __trace_print_untrusted_str(seq, "/a", 2); 375 KUNIT_EXPECT_NULL(test, output); 376 KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len); 377 } 378 379 static void test_untrusted_str_composition(struct kunit *const test) 380 { 381 static const struct trace_print_flags flags[] = { 382 { .mask = 1, .name = "read" }, 383 }; 384 const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE; 385 const size_t prefix_len = output_size - sizeof(TRACE_TRUNCATION_MARKER); 386 struct trace_seq *const seq = 387 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 388 char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL); 389 char *const path = kunit_kmalloc(test, output_size, GFP_KERNEL); 390 const char *flags_output, *path_output; 391 392 KUNIT_ASSERT_NOT_NULL(test, seq); 393 KUNIT_ASSERT_NOT_NULL(test, expected); 394 KUNIT_ASSERT_NOT_NULL(test, path); 395 memset(path, 'a', output_size); 396 memset(expected, 'a', prefix_len); 397 memcpy(expected + prefix_len, TRACE_TRUNCATION_MARKER, 398 sizeof(TRACE_TRUNCATION_MARKER)); 399 400 /* Exercise both legal TP_printk() sibling evaluation orders. */ 401 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 402 path_output = __trace_print_untrusted_str(seq, path, output_size); 403 flags_output = 404 trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags)); 405 KUNIT_ASSERT_NOT_NULL(test, path_output); 406 KUNIT_EXPECT_STREQ(test, path_output, expected); 407 KUNIT_EXPECT_STREQ(test, flags_output, "read"); 408 409 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 410 flags_output = 411 trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags)); 412 path_output = __trace_print_untrusted_str(seq, path, output_size); 413 KUNIT_ASSERT_NOT_NULL(test, path_output); 414 KUNIT_EXPECT_STREQ(test, path_output, expected); 415 KUNIT_EXPECT_STREQ(test, flags_output, "read"); 416 } 417 418 static struct kunit_case test_cases[] = { 419 /* clang-format off */ 420 KUNIT_CASE(test_untrusted_str_data), 421 KUNIT_CASE(test_untrusted_str_boundaries), 422 KUNIT_CASE(test_untrusted_str_cursor), 423 KUNIT_CASE(test_untrusted_str_composition), 424 {} 425 /* clang-format on */ 426 }; 427 428 static struct kunit_suite test_suite = { 429 .name = "landlock_trace", 430 .test_cases = test_cases, 431 }; 432 433 kunit_test_suite(test_suite); 434 435 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ 436