Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Landlock - Audit helpers
4 *
5 * Copyright © 2023-2025 Microsoft Corporation
6 */
7
8#include <kunit/test.h>
9#include <linux/audit.h>
10#include <linux/bitops.h>
11#include <linux/lsm_audit.h>
12#include <linux/pid.h>
13#include <uapi/linux/landlock.h>
14
15#include "access.h"
16#include "audit.h"
17#include "common.h"
18#include "cred.h"
19#include "domain.h"
20#include "limits.h"
21#include "ruleset.h"
22
23static const char *const fs_access_strings[] = {
24 [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = "fs.execute",
25 [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = "fs.write_file",
26 [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = "fs.read_file",
27 [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_DIR)] = "fs.read_dir",
28 [BIT_INDEX(LANDLOCK_ACCESS_FS_REMOVE_DIR)] = "fs.remove_dir",
29 [BIT_INDEX(LANDLOCK_ACCESS_FS_REMOVE_FILE)] = "fs.remove_file",
30 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_CHAR)] = "fs.make_char",
31 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_DIR)] = "fs.make_dir",
32 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_REG)] = "fs.make_reg",
33 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_SOCK)] = "fs.make_sock",
34 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_FIFO)] = "fs.make_fifo",
35 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_BLOCK)] = "fs.make_block",
36 [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_SYM)] = "fs.make_sym",
37 [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
38 [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
39 [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
40};
41
42static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
43
44static const char *const net_access_strings[] = {
45 [BIT_INDEX(LANDLOCK_ACCESS_NET_BIND_TCP)] = "net.bind_tcp",
46 [BIT_INDEX(LANDLOCK_ACCESS_NET_CONNECT_TCP)] = "net.connect_tcp",
47};
48
49static_assert(ARRAY_SIZE(net_access_strings) == LANDLOCK_NUM_ACCESS_NET);
50
51static __attribute_const__ const char *
52get_blocker(const enum landlock_request_type type,
53 const unsigned long access_bit)
54{
55 switch (type) {
56 case LANDLOCK_REQUEST_PTRACE:
57 WARN_ON_ONCE(access_bit != -1);
58 return "ptrace";
59
60 case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY:
61 WARN_ON_ONCE(access_bit != -1);
62 return "fs.change_topology";
63
64 case LANDLOCK_REQUEST_FS_ACCESS:
65 if (WARN_ON_ONCE(access_bit >= ARRAY_SIZE(fs_access_strings)))
66 return "unknown";
67 return fs_access_strings[access_bit];
68
69 case LANDLOCK_REQUEST_NET_ACCESS:
70 if (WARN_ON_ONCE(access_bit >= ARRAY_SIZE(net_access_strings)))
71 return "unknown";
72 return net_access_strings[access_bit];
73
74 case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET:
75 WARN_ON_ONCE(access_bit != -1);
76 return "scope.abstract_unix_socket";
77
78 case LANDLOCK_REQUEST_SCOPE_SIGNAL:
79 WARN_ON_ONCE(access_bit != -1);
80 return "scope.signal";
81 }
82
83 WARN_ON_ONCE(1);
84 return "unknown";
85}
86
87static void log_blockers(struct audit_buffer *const ab,
88 const enum landlock_request_type type,
89 const access_mask_t access)
90{
91 const unsigned long access_mask = access;
92 unsigned long access_bit;
93 bool is_first = true;
94
95 for_each_set_bit(access_bit, &access_mask, BITS_PER_TYPE(access)) {
96 audit_log_format(ab, "%s%s", is_first ? "" : ",",
97 get_blocker(type, access_bit));
98 is_first = false;
99 }
100 if (is_first)
101 audit_log_format(ab, "%s", get_blocker(type, -1));
102}
103
104static void log_domain(struct landlock_hierarchy *const hierarchy)
105{
106 struct audit_buffer *ab;
107
108 /* Ignores already logged domains. */
109 if (READ_ONCE(hierarchy->log_status) == LANDLOCK_LOG_RECORDED)
110 return;
111
112 /* Uses consistent allocation flags wrt common_lsm_audit(). */
113 ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
114 AUDIT_LANDLOCK_DOMAIN);
115 if (!ab)
116 return;
117
118 WARN_ON_ONCE(hierarchy->id == 0);
119 audit_log_format(
120 ab,
121 "domain=%llx status=allocated mode=enforcing pid=%d uid=%u exe=",
122 hierarchy->id, pid_nr(hierarchy->details->pid),
123 hierarchy->details->uid);
124 audit_log_untrustedstring(ab, hierarchy->details->exe_path);
125 audit_log_format(ab, " comm=");
126 audit_log_untrustedstring(ab, hierarchy->details->comm);
127 audit_log_end(ab);
128
129 /*
130 * There may be race condition leading to logging of the same domain
131 * several times but that is OK.
132 */
133 WRITE_ONCE(hierarchy->log_status, LANDLOCK_LOG_RECORDED);
134}
135
136static struct landlock_hierarchy *
137get_hierarchy(const struct landlock_ruleset *const domain, const size_t layer)
138{
139 struct landlock_hierarchy *hierarchy = domain->hierarchy;
140 ssize_t i;
141
142 if (WARN_ON_ONCE(layer >= domain->num_layers))
143 return hierarchy;
144
145 for (i = domain->num_layers - 1; i > layer; i--) {
146 if (WARN_ON_ONCE(!hierarchy->parent))
147 break;
148
149 hierarchy = hierarchy->parent;
150 }
151
152 return hierarchy;
153}
154
155#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
156
157static void test_get_hierarchy(struct kunit *const test)
158{
159 struct landlock_hierarchy dom0_hierarchy = {
160 .id = 10,
161 };
162 struct landlock_hierarchy dom1_hierarchy = {
163 .parent = &dom0_hierarchy,
164 .id = 20,
165 };
166 struct landlock_hierarchy dom2_hierarchy = {
167 .parent = &dom1_hierarchy,
168 .id = 30,
169 };
170 struct landlock_ruleset dom2 = {
171 .hierarchy = &dom2_hierarchy,
172 .num_layers = 3,
173 };
174
175 KUNIT_EXPECT_EQ(test, 10, get_hierarchy(&dom2, 0)->id);
176 KUNIT_EXPECT_EQ(test, 20, get_hierarchy(&dom2, 1)->id);
177 KUNIT_EXPECT_EQ(test, 30, get_hierarchy(&dom2, 2)->id);
178 /* KUNIT_EXPECT_EQ(test, 30, get_hierarchy(&dom2, -1)->id); */
179}
180
181#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
182
183/* Get the youngest layer that denied the access_request. */
184static size_t get_denied_layer(const struct landlock_ruleset *const domain,
185 access_mask_t *const access_request,
186 const struct layer_access_masks *masks)
187{
188 for (ssize_t i = ARRAY_SIZE(masks->access) - 1; i >= 0; i--) {
189 if (masks->access[i] & *access_request) {
190 *access_request &= masks->access[i];
191 return i;
192 }
193 }
194
195 /* Not found - fall back to default values */
196 *access_request = 0;
197 return domain->num_layers - 1;
198}
199
200#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
201
202static void test_get_denied_layer(struct kunit *const test)
203{
204 const struct landlock_ruleset dom = {
205 .num_layers = 5,
206 };
207 const struct layer_access_masks masks = {
208 .access[0] = LANDLOCK_ACCESS_FS_EXECUTE |
209 LANDLOCK_ACCESS_FS_READ_DIR,
210 .access[1] = LANDLOCK_ACCESS_FS_READ_FILE |
211 LANDLOCK_ACCESS_FS_READ_DIR,
212 .access[2] = LANDLOCK_ACCESS_FS_REMOVE_DIR,
213 };
214 access_mask_t access;
215
216 access = LANDLOCK_ACCESS_FS_EXECUTE;
217 KUNIT_EXPECT_EQ(test, 0, get_denied_layer(&dom, &access, &masks));
218 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_EXECUTE);
219
220 access = LANDLOCK_ACCESS_FS_READ_FILE;
221 KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
222 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_FILE);
223
224 access = LANDLOCK_ACCESS_FS_READ_DIR;
225 KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
226 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
227
228 access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR;
229 KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
230 KUNIT_EXPECT_EQ(test, access,
231 LANDLOCK_ACCESS_FS_READ_FILE |
232 LANDLOCK_ACCESS_FS_READ_DIR);
233
234 access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_DIR;
235 KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
236 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
237
238 access = LANDLOCK_ACCESS_FS_WRITE_FILE;
239 KUNIT_EXPECT_EQ(test, 4, get_denied_layer(&dom, &access, &masks));
240 KUNIT_EXPECT_EQ(test, access, 0);
241}
242
243#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
244
245static size_t
246get_layer_from_deny_masks(access_mask_t *const access_request,
247 const access_mask_t all_existing_optional_access,
248 const deny_masks_t deny_masks)
249{
250 const unsigned long access_opt = all_existing_optional_access;
251 const unsigned long access_req = *access_request;
252 access_mask_t missing = 0;
253 size_t youngest_layer = 0;
254 size_t access_index = 0;
255 unsigned long access_bit;
256
257 /* This will require change with new object types. */
258 WARN_ON_ONCE(access_opt != _LANDLOCK_ACCESS_FS_OPTIONAL);
259
260 for_each_set_bit(access_bit, &access_opt,
261 BITS_PER_TYPE(access_mask_t)) {
262 if (access_req & BIT(access_bit)) {
263 const size_t layer =
264 (deny_masks >> (access_index * 4)) &
265 (LANDLOCK_MAX_NUM_LAYERS - 1);
266
267 if (layer > youngest_layer) {
268 youngest_layer = layer;
269 missing = BIT(access_bit);
270 } else if (layer == youngest_layer) {
271 missing |= BIT(access_bit);
272 }
273 }
274 access_index++;
275 }
276
277 *access_request = missing;
278 return youngest_layer;
279}
280
281#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
282
283static void test_get_layer_from_deny_masks(struct kunit *const test)
284{
285 deny_masks_t deny_mask;
286 access_mask_t access;
287
288 /* truncate:0 ioctl_dev:2 */
289 deny_mask = 0x20;
290
291 access = LANDLOCK_ACCESS_FS_TRUNCATE;
292 KUNIT_EXPECT_EQ(test, 0,
293 get_layer_from_deny_masks(&access,
294 _LANDLOCK_ACCESS_FS_OPTIONAL,
295 deny_mask));
296 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_TRUNCATE);
297
298 access = LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_IOCTL_DEV;
299 KUNIT_EXPECT_EQ(test, 2,
300 get_layer_from_deny_masks(&access,
301 _LANDLOCK_ACCESS_FS_OPTIONAL,
302 deny_mask));
303 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_IOCTL_DEV);
304
305 /* truncate:15 ioctl_dev:15 */
306 deny_mask = 0xff;
307
308 access = LANDLOCK_ACCESS_FS_TRUNCATE;
309 KUNIT_EXPECT_EQ(test, 15,
310 get_layer_from_deny_masks(&access,
311 _LANDLOCK_ACCESS_FS_OPTIONAL,
312 deny_mask));
313 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_TRUNCATE);
314
315 access = LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_IOCTL_DEV;
316 KUNIT_EXPECT_EQ(test, 15,
317 get_layer_from_deny_masks(&access,
318 _LANDLOCK_ACCESS_FS_OPTIONAL,
319 deny_mask));
320 KUNIT_EXPECT_EQ(test, access,
321 LANDLOCK_ACCESS_FS_TRUNCATE |
322 LANDLOCK_ACCESS_FS_IOCTL_DEV);
323}
324
325#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
326
327static bool is_valid_request(const struct landlock_request *const request)
328{
329 if (WARN_ON_ONCE(request->layer_plus_one > LANDLOCK_MAX_NUM_LAYERS))
330 return false;
331
332 if (WARN_ON_ONCE(!(!!request->layer_plus_one ^ !!request->access)))
333 return false;
334
335 if (request->access) {
336 if (WARN_ON_ONCE(!(!!request->layer_masks ^
337 !!request->all_existing_optional_access)))
338 return false;
339 } else {
340 if (WARN_ON_ONCE(request->layer_masks ||
341 request->all_existing_optional_access))
342 return false;
343 }
344
345 if (request->deny_masks) {
346 if (WARN_ON_ONCE(!request->all_existing_optional_access))
347 return false;
348 }
349
350 return true;
351}
352
353/**
354 * landlock_log_denial - Create audit records related to a denial
355 *
356 * @subject: The Landlock subject's credential denying an action.
357 * @request: Detail of the user space request.
358 */
359void landlock_log_denial(const struct landlock_cred_security *const subject,
360 const struct landlock_request *const request)
361{
362 struct audit_buffer *ab;
363 struct landlock_hierarchy *youngest_denied;
364 size_t youngest_layer;
365 access_mask_t missing;
366
367 if (WARN_ON_ONCE(!subject || !subject->domain ||
368 !subject->domain->hierarchy || !request))
369 return;
370
371 if (!is_valid_request(request))
372 return;
373
374 missing = request->access;
375 if (missing) {
376 /* Gets the nearest domain that denies the request. */
377 if (request->layer_masks) {
378 youngest_layer = get_denied_layer(subject->domain,
379 &missing,
380 request->layer_masks);
381 } else {
382 youngest_layer = get_layer_from_deny_masks(
383 &missing, _LANDLOCK_ACCESS_FS_OPTIONAL,
384 request->deny_masks);
385 }
386 youngest_denied =
387 get_hierarchy(subject->domain, youngest_layer);
388 } else {
389 youngest_layer = request->layer_plus_one - 1;
390 youngest_denied =
391 get_hierarchy(subject->domain, youngest_layer);
392 }
393
394 if (READ_ONCE(youngest_denied->log_status) == LANDLOCK_LOG_DISABLED)
395 return;
396
397 /*
398 * Consistently keeps track of the number of denied access requests
399 * even if audit is currently disabled, or if audit rules currently
400 * exclude this record type, or if landlock_restrict_self(2)'s flags
401 * quiet logs.
402 */
403 atomic64_inc(&youngest_denied->num_denials);
404
405 if (!audit_enabled)
406 return;
407
408 /* Checks if the current exec was restricting itself. */
409 if (subject->domain_exec & BIT(youngest_layer)) {
410 /* Ignores denials for the same execution. */
411 if (!youngest_denied->log_same_exec)
412 return;
413 } else {
414 /* Ignores denials after a new execution. */
415 if (!youngest_denied->log_new_exec)
416 return;
417 }
418
419 /* Uses consistent allocation flags wrt common_lsm_audit(). */
420 ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
421 AUDIT_LANDLOCK_ACCESS);
422 if (!ab)
423 return;
424
425 audit_log_format(ab, "domain=%llx blockers=", youngest_denied->id);
426 log_blockers(ab, request->type, missing);
427 audit_log_lsm_data(ab, &request->audit);
428 audit_log_end(ab);
429
430 /* Logs this domain the first time it shows in log. */
431 log_domain(youngest_denied);
432}
433
434/**
435 * landlock_log_drop_domain - Create an audit record on domain deallocation
436 *
437 * @hierarchy: The domain's hierarchy being deallocated.
438 *
439 * Only domains which previously appeared in the audit logs are logged again.
440 * This is useful to know when a domain will never show again in the audit log.
441 *
442 * Called in a work queue scheduled by landlock_put_ruleset_deferred() called
443 * by hook_cred_free().
444 */
445void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy)
446{
447 struct audit_buffer *ab;
448
449 if (WARN_ON_ONCE(!hierarchy))
450 return;
451
452 if (!audit_enabled)
453 return;
454
455 /* Ignores domains that were not logged. */
456 if (READ_ONCE(hierarchy->log_status) != LANDLOCK_LOG_RECORDED)
457 return;
458
459 /*
460 * If logging of domain allocation succeeded, warns about failure to log
461 * domain deallocation to highlight unbalanced domain lifetime logs.
462 */
463 ab = audit_log_start(audit_context(), GFP_KERNEL,
464 AUDIT_LANDLOCK_DOMAIN);
465 if (!ab)
466 return;
467
468 audit_log_format(ab, "domain=%llx status=deallocated denials=%llu",
469 hierarchy->id, atomic64_read(&hierarchy->num_denials));
470 audit_log_end(ab);
471}
472
473#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
474
475static struct kunit_case test_cases[] = {
476 /* clang-format off */
477 KUNIT_CASE(test_get_hierarchy),
478 KUNIT_CASE(test_get_denied_layer),
479 KUNIT_CASE(test_get_layer_from_deny_masks),
480 {}
481 /* clang-format on */
482};
483
484static struct kunit_suite test_suite = {
485 .name = "landlock_audit",
486 .test_cases = test_cases,
487};
488
489kunit_test_suite(test_suite);
490
491#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */