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 */
landlock_trace_free_domain(const struct landlock_hierarchy * const hierarchy)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 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 */
landlock_trace_denial(const struct landlock_request * const request,const struct landlock_hierarchy * const youngest_denied,const access_mask_t missing,const bool same_exec,const bool logged)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_FS_ACCESS:
85 case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY:
86 if (trace_landlock_deny_access_fs_enabled()) {
87 const struct landlock_blockers blockers = {
88 .access = missing,
89 .type = request->type,
90 };
91 char *buf __free(__putname) = __getname();
92 struct path dentry_path;
93 const char *pathname;
94 const struct path *path = NULL;
95
96 /*
97 * Selects the path from the audit data type, as
98 * dump_common_audit_data() does. A FS_ACCESS denial
99 * carries a file (hook_file_truncate) or an ioctl op
100 * (hook_file_ioctl) rather than a path;
101 * FS_CHANGE_TOPOLOGY carries a path or a bare dentry.
102 * Reading the wrong union member would dereference
103 * garbage, so every reachable type is handled here.
104 */
105 switch (request->audit.type) {
106 case LSM_AUDIT_DATA_FILE:
107 path = &request->audit.u.file->f_path;
108 break;
109 case LSM_AUDIT_DATA_IOCTL_OP:
110 path = &request->audit.u.op->path;
111 break;
112 case LSM_AUDIT_DATA_DENTRY:
113 /*
114 * Build a path on the stack with the real
115 * dentry so TP_fast_assign can extract dev and
116 * ino; the mnt field is unused there.
117 */
118 dentry_path = (struct path){
119 .dentry = request->audit.u.dentry,
120 };
121 path = &dentry_path;
122 break;
123 case LSM_AUDIT_DATA_PATH:
124 path = &request->audit.u.path;
125 break;
126 default:
127 WARN_ONCE(1,
128 "Unhandled Landlock FS audit type %d",
129 request->audit.type);
130 break;
131 }
132
133 if (!path)
134 break;
135
136 if (!buf) {
137 pathname = "<no_mem>";
138 } else if (request->audit.type ==
139 LSM_AUDIT_DATA_DENTRY) {
140 /* No vfsmount: render the dentry path alone. */
141 pathname = dentry_path_raw(
142 request->audit.u.dentry, buf, PATH_MAX);
143 if (IS_ERR(pathname))
144 pathname =
145 PTR_ERR(pathname) ==
146 -ENAMETOOLONG ?
147 "<too_long>" :
148 "<unreachable>";
149 } else {
150 pathname = resolve_path_for_trace(path, buf);
151 }
152
153 trace_landlock_deny_access_fs(youngest_denied,
154 same_exec, logged,
155 &blockers, path,
156 pathname);
157 }
158 break;
159 case LANDLOCK_REQUEST_NET_ACCESS:
160 if (trace_landlock_deny_access_net_enabled()) {
161 const struct landlock_net_trace *const trace_net =
162 request->trace_net;
163 const struct landlock_blockers blockers = {
164 .access = missing,
165 .type = request->type,
166 };
167 struct sockaddr_storage address = {};
168
169 if (WARN_ON_ONCE(!trace_net || !trace_net->address))
170 return;
171
172 if (WARN_ON_ONCE(
173 trace_net->addrlen <
174 (int)offsetofend(struct sockaddr,
175 sa_family) ||
176 trace_net->addrlen > (int)sizeof(address)))
177 return;
178
179 memcpy(&address, trace_net->address,
180 trace_net->addrlen);
181 trace_landlock_deny_access_net(
182 youngest_denied, same_exec, logged, &blockers,
183 request->audit.u.net->sk,
184 trace_net->socket_family, &address,
185 trace_net->addrlen);
186 }
187 break;
188 case LANDLOCK_REQUEST_PTRACE:
189 if (trace_landlock_deny_ptrace_enabled()) {
190 const struct landlock_ptrace_trace *const trace_ptrace =
191 request->trace_ptrace;
192
193 if (WARN_ON_ONCE(!trace_ptrace ||
194 !trace_ptrace->tracer))
195 return;
196
197 trace_landlock_deny_ptrace(
198 youngest_denied, same_exec, logged,
199 trace_ptrace->tracee_domain_id,
200 request->audit.u.tsk, trace_ptrace->tracer);
201 }
202 break;
203 case LANDLOCK_REQUEST_SCOPE_SIGNAL:
204 if (trace_landlock_deny_scope_signal_enabled()) {
205 const struct landlock_signal_trace *const trace_signal =
206 request->trace_signal;
207
208 if (WARN_ON_ONCE(!trace_signal))
209 return;
210
211 trace_landlock_deny_scope_signal(
212 youngest_denied, same_exec, logged,
213 trace_signal->target_domain_id,
214 request->audit.u.tsk, trace_signal->signal);
215 }
216 break;
217 case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET:
218 if (trace_landlock_deny_scope_abstract_unix_socket_enabled())
219 trace_landlock_deny_scope_abstract_unix_socket(
220 youngest_denied, same_exec, logged,
221 request->other_domain_id,
222 request->audit.u.net->sk);
223 break;
224 default:
225 WARN_ONCE(1, "Unhandled Landlock request type %d",
226 request->type);
227 break;
228 }
229 }
230
231 #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
232
test_trace_seq_init(struct trace_seq * const seq,const size_t size)233 static void test_trace_seq_init(struct trace_seq *const seq, const size_t size)
234 {
235 memset(seq, 0, sizeof(*seq));
236 seq_buf_init(&seq->seq, seq->buffer, size);
237 }
238
test_untrusted_str_data(struct kunit * const test)239 static void test_untrusted_str_data(struct kunit *const test)
240 {
241 const char binary[] = { 'a', '\0', '<' };
242 static const char ellipsis[] = "\xe2\x80\xa6";
243 struct trace_seq *const seq =
244 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL);
245 const char *output;
246
247 KUNIT_ASSERT_NOT_NULL(test, seq);
248 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
249 output = __trace_print_untrusted_str(seq, "<too_long>", 10);
250 KUNIT_ASSERT_NOT_NULL(test, output);
251 KUNIT_EXPECT_STREQ(test, output, "<too_long>");
252
253 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
254 output = __trace_print_untrusted_str(seq, binary, sizeof(binary));
255 KUNIT_ASSERT_NOT_NULL(test, output);
256 KUNIT_EXPECT_STREQ(test, output, "a\\000<");
257
258 /* Input ellipsis bytes are escaped and cannot mimic the raw marker. */
259 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
260 output = __trace_print_untrusted_str(seq, ellipsis,
261 sizeof(ellipsis) - 1);
262 KUNIT_ASSERT_NOT_NULL(test, output);
263 KUNIT_EXPECT_STREQ(test, output, "\\342\\200\\246");
264 }
265
test_untrusted_str_boundaries(struct kunit * const test)266 static void test_untrusted_str_boundaries(struct kunit *const test)
267 {
268 static const char escaped_space[] = "\\040";
269 const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE;
270 const size_t marker_len = sizeof(TRACE_TRUNCATION_MARKER) - 1;
271 const size_t escape_len = sizeof(escaped_space) - 1;
272 const size_t exact_prefix_len =
273 output_size - marker_len - 1 - escape_len;
274 const size_t short_prefix_len = exact_prefix_len + 1;
275 struct trace_seq *const seq =
276 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL);
277 char *const input = kunit_kmalloc(test, output_size + 1, GFP_KERNEL);
278 char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL);
279 const char *output;
280
281 KUNIT_ASSERT_NOT_NULL(test, seq);
282 KUNIT_ASSERT_NOT_NULL(test, input);
283 KUNIT_ASSERT_NOT_NULL(test, expected);
284
285 /* The escaped string and its trailing NUL exactly fit the limit. */
286 memset(input, 'a', output_size - 1);
287 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
288 output = __trace_print_untrusted_str(seq, input, output_size - 1);
289 KUNIT_ASSERT_NOT_NULL(test, output);
290 KUNIT_EXPECT_EQ(test, seq->seq.len, output_size);
291 KUNIT_EXPECT_EQ(test, memcmp(output, input, output_size - 1), 0);
292
293 /* Stop before a four-byte escape when only three bytes remain. */
294 memset(input, 'a', short_prefix_len);
295 input[short_prefix_len] = ' ';
296 memset(input + short_prefix_len + 1, 'b', 5);
297 memset(expected, 'a', short_prefix_len);
298 memcpy(expected + short_prefix_len, TRACE_TRUNCATION_MARKER,
299 marker_len + 1);
300 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
301 output = __trace_print_untrusted_str(seq, input, short_prefix_len + 6);
302 KUNIT_ASSERT_NOT_NULL(test, output);
303 KUNIT_EXPECT_STREQ(test, output, expected);
304
305 /* Include a four-byte escape that exactly fills the prefix capacity. */
306 memset(input, 'a', exact_prefix_len);
307 input[exact_prefix_len] = ' ';
308 memset(input + exact_prefix_len + 1, 'b', marker_len + 1);
309 memset(expected, 'a', exact_prefix_len);
310 memcpy(expected + exact_prefix_len, escaped_space, escape_len);
311 memcpy(expected + exact_prefix_len + escape_len,
312 TRACE_TRUNCATION_MARKER, marker_len + 1);
313 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
314 output = __trace_print_untrusted_str(seq, input,
315 exact_prefix_len + marker_len + 2);
316 KUNIT_ASSERT_NOT_NULL(test, output);
317 KUNIT_EXPECT_STREQ(test, output, expected);
318
319 /* Literal backslashes remain escaped in complete output. */
320 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
321 output = __trace_print_untrusted_str(seq, "/\\000", 5);
322 KUNIT_ASSERT_NOT_NULL(test, output);
323 KUNIT_EXPECT_STREQ(test, output, "/\\\\000");
324 }
325
test_untrusted_str_cursor(struct kunit * const test)326 static void test_untrusted_str_cursor(struct kunit *const test)
327 {
328 const size_t padding_len =
329 TRACE_SEQ_BUFFER_SIZE - TRACE_UNTRUSTED_STR_OUTPUT_SIZE + 1;
330 struct trace_seq *const seq =
331 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL);
332 char *const padding = kunit_kzalloc(test, padding_len, GFP_KERNEL);
333 const char *output;
334
335 KUNIT_ASSERT_NOT_NULL(test, seq);
336 KUNIT_ASSERT_NOT_NULL(test, padding);
337
338 /* Accept available space exactly equal to the fixed reservation. */
339 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
340 trace_seq_putmem(seq, padding, padding_len - 1);
341 output = __trace_print_untrusted_str(seq, "/a", 2);
342 KUNIT_ASSERT_NOT_NULL(test, output);
343 KUNIT_EXPECT_STREQ(test, output, "/a");
344 KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len - 1 + sizeof("/a"));
345
346 /* Reject one byte less without changing the scratch cursor. */
347 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
348 trace_seq_putmem(seq, padding, padding_len);
349 output = __trace_print_untrusted_str(seq, "/a", 2);
350 KUNIT_EXPECT_NULL(test, output);
351 KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len);
352 }
353
test_untrusted_str_composition(struct kunit * const test)354 static void test_untrusted_str_composition(struct kunit *const test)
355 {
356 static const struct trace_print_flags flags[] = {
357 { .mask = 1, .name = "read" },
358 };
359 const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE;
360 const size_t prefix_len = output_size - sizeof(TRACE_TRUNCATION_MARKER);
361 struct trace_seq *const seq =
362 kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL);
363 char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL);
364 char *const path = kunit_kmalloc(test, output_size, GFP_KERNEL);
365 const char *flags_output, *path_output;
366
367 KUNIT_ASSERT_NOT_NULL(test, seq);
368 KUNIT_ASSERT_NOT_NULL(test, expected);
369 KUNIT_ASSERT_NOT_NULL(test, path);
370 memset(path, 'a', output_size);
371 memset(expected, 'a', prefix_len);
372 memcpy(expected + prefix_len, TRACE_TRUNCATION_MARKER,
373 sizeof(TRACE_TRUNCATION_MARKER));
374
375 /* Exercise both legal TP_printk() sibling evaluation orders. */
376 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
377 path_output = __trace_print_untrusted_str(seq, path, output_size);
378 flags_output =
379 trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags));
380 KUNIT_ASSERT_NOT_NULL(test, path_output);
381 KUNIT_EXPECT_STREQ(test, path_output, expected);
382 KUNIT_EXPECT_STREQ(test, flags_output, "read");
383
384 test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE);
385 flags_output =
386 trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags));
387 path_output = __trace_print_untrusted_str(seq, path, output_size);
388 KUNIT_ASSERT_NOT_NULL(test, path_output);
389 KUNIT_EXPECT_STREQ(test, path_output, expected);
390 KUNIT_EXPECT_STREQ(test, flags_output, "read");
391 }
392
393 static struct kunit_case test_cases[] = {
394 /* clang-format off */
395 KUNIT_CASE(test_untrusted_str_data),
396 KUNIT_CASE(test_untrusted_str_boundaries),
397 KUNIT_CASE(test_untrusted_str_cursor),
398 KUNIT_CASE(test_untrusted_str_composition),
399 {}
400 /* clang-format on */
401 };
402
403 static struct kunit_suite test_suite = {
404 .name = "landlock_trace",
405 .test_cases = test_cases,
406 };
407
408 kunit_test_suite(test_suite);
409
410 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
411