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