xref: /linux/security/landlock/trace.c (revision 97c8386f1d744e9689cd3e72347f980d9af4f59f)
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