File Index
Files and directories
Sign in
FILE

audit.c

File preview with syntax highlighting.

linux-6.19.14/security/landlock/audit.c C
  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
183static size_t get_denied_layer(const struct landlock_ruleset *const domain,
184			       access_mask_t *const access_request,
185			       const layer_mask_t (*const layer_masks)[],
186			       const size_t layer_masks_size)
187{
188	const unsigned long access_req = *access_request;
189	unsigned long access_bit;
190	access_mask_t missing = 0;
191	long youngest_layer = -1;
192
193	for_each_set_bit(access_bit, &access_req, layer_masks_size) {
194		const layer_mask_t mask = (*layer_masks)[access_bit];
195		long layer;
196
197		if (!mask)
198			continue;
199
200		/* __fls(1) == 0 */
201		layer = __fls(mask);
202		if (layer > youngest_layer) {
203			youngest_layer = layer;
204			missing = BIT(access_bit);
205		} else if (layer == youngest_layer) {
206			missing |= BIT(access_bit);
207		}
208	}
209
210	*access_request = missing;
211	if (youngest_layer == -1)
212		return domain->num_layers - 1;
213
214	return youngest_layer;
215}
216
217#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
218
219static void test_get_denied_layer(struct kunit *const test)
220{
221	const struct landlock_ruleset dom = {
222		.num_layers = 5,
223	};
224	const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {
225		[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT(0),
226		[BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = BIT(1),
227		[BIT_INDEX(LANDLOCK_ACCESS_FS_READ_DIR)] = BIT(1) | BIT(0),
228		[BIT_INDEX(LANDLOCK_ACCESS_FS_REMOVE_DIR)] = BIT(2),
229	};
230	access_mask_t access;
231
232	access = LANDLOCK_ACCESS_FS_EXECUTE;
233	KUNIT_EXPECT_EQ(test, 0,
234			get_denied_layer(&dom, &access, &layer_masks,
235					 sizeof(layer_masks)));
236	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_EXECUTE);
237
238	access = LANDLOCK_ACCESS_FS_READ_FILE;
239	KUNIT_EXPECT_EQ(test, 1,
240			get_denied_layer(&dom, &access, &layer_masks,
241					 sizeof(layer_masks)));
242	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_FILE);
243
244	access = LANDLOCK_ACCESS_FS_READ_DIR;
245	KUNIT_EXPECT_EQ(test, 1,
246			get_denied_layer(&dom, &access, &layer_masks,
247					 sizeof(layer_masks)));
248	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
249
250	access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR;
251	KUNIT_EXPECT_EQ(test, 1,
252			get_denied_layer(&dom, &access, &layer_masks,
253					 sizeof(layer_masks)));
254	KUNIT_EXPECT_EQ(test, access,
255			LANDLOCK_ACCESS_FS_READ_FILE |
256				LANDLOCK_ACCESS_FS_READ_DIR);
257
258	access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_DIR;
259	KUNIT_EXPECT_EQ(test, 1,
260			get_denied_layer(&dom, &access, &layer_masks,
261					 sizeof(layer_masks)));
262	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
263
264	access = LANDLOCK_ACCESS_FS_WRITE_FILE;
265	KUNIT_EXPECT_EQ(test, 4,
266			get_denied_layer(&dom, &access, &layer_masks,
267					 sizeof(layer_masks)));
268	KUNIT_EXPECT_EQ(test, access, 0);
269}
270
271#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
272
273static size_t
274get_layer_from_deny_masks(access_mask_t *const access_request,
275			  const access_mask_t all_existing_optional_access,
276			  const deny_masks_t deny_masks)
277{
278	const unsigned long access_opt = all_existing_optional_access;
279	const unsigned long access_req = *access_request;
280	access_mask_t missing = 0;
281	size_t youngest_layer = 0;
282	size_t access_index = 0;
283	unsigned long access_bit;
284
285	/* This will require change with new object types. */
286	WARN_ON_ONCE(access_opt != _LANDLOCK_ACCESS_FS_OPTIONAL);
287
288	for_each_set_bit(access_bit, &access_opt,
289			 BITS_PER_TYPE(access_mask_t)) {
290		if (access_req & BIT(access_bit)) {
291			const size_t layer =
292				(deny_masks >> (access_index * 4)) &
293				(LANDLOCK_MAX_NUM_LAYERS - 1);
294
295			if (layer > youngest_layer) {
296				youngest_layer = layer;
297				missing = BIT(access_bit);
298			} else if (layer == youngest_layer) {
299				missing |= BIT(access_bit);
300			}
301		}
302		access_index++;
303	}
304
305	*access_request = missing;
306	return youngest_layer;
307}
308
309#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
310
311static void test_get_layer_from_deny_masks(struct kunit *const test)
312{
313	deny_masks_t deny_mask;
314	access_mask_t access;
315
316	/* truncate:0 ioctl_dev:2 */
317	deny_mask = 0x20;
318
319	access = LANDLOCK_ACCESS_FS_TRUNCATE;
320	KUNIT_EXPECT_EQ(test, 0,
321			get_layer_from_deny_masks(&access,
322						  _LANDLOCK_ACCESS_FS_OPTIONAL,
323						  deny_mask));
324	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_TRUNCATE);
325
326	access = LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_IOCTL_DEV;
327	KUNIT_EXPECT_EQ(test, 2,
328			get_layer_from_deny_masks(&access,
329						  _LANDLOCK_ACCESS_FS_OPTIONAL,
330						  deny_mask));
331	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_IOCTL_DEV);
332
333	/* truncate:15 ioctl_dev:15 */
334	deny_mask = 0xff;
335
336	access = LANDLOCK_ACCESS_FS_TRUNCATE;
337	KUNIT_EXPECT_EQ(test, 15,
338			get_layer_from_deny_masks(&access,
339						  _LANDLOCK_ACCESS_FS_OPTIONAL,
340						  deny_mask));
341	KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_TRUNCATE);
342
343	access = LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_IOCTL_DEV;
344	KUNIT_EXPECT_EQ(test, 15,
345			get_layer_from_deny_masks(&access,
346						  _LANDLOCK_ACCESS_FS_OPTIONAL,
347						  deny_mask));
348	KUNIT_EXPECT_EQ(test, access,
349			LANDLOCK_ACCESS_FS_TRUNCATE |
350				LANDLOCK_ACCESS_FS_IOCTL_DEV);
351}
352
353#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
354
355static bool is_valid_request(const struct landlock_request *const request)
356{
357	if (WARN_ON_ONCE(request->layer_plus_one > LANDLOCK_MAX_NUM_LAYERS))
358		return false;
359
360	if (WARN_ON_ONCE(!(!!request->layer_plus_one ^ !!request->access)))
361		return false;
362
363	if (request->access) {
364		if (WARN_ON_ONCE(!(!!request->layer_masks ^
365				   !!request->all_existing_optional_access)))
366			return false;
367	} else {
368		if (WARN_ON_ONCE(request->layer_masks ||
369				 request->all_existing_optional_access))
370			return false;
371	}
372
373	if (WARN_ON_ONCE(!!request->layer_masks ^ !!request->layer_masks_size))
374		return false;
375
376	if (request->deny_masks) {
377		if (WARN_ON_ONCE(!request->all_existing_optional_access))
378			return false;
379	}
380
381	return true;
382}
383
384/**
385 * landlock_log_denial - Create audit records related to a denial
386 *
387 * @subject: The Landlock subject's credential denying an action.
388 * @request: Detail of the user space request.
389 */
390void landlock_log_denial(const struct landlock_cred_security *const subject,
391			 const struct landlock_request *const request)
392{
393	struct audit_buffer *ab;
394	struct landlock_hierarchy *youngest_denied;
395	size_t youngest_layer;
396	access_mask_t missing;
397
398	if (WARN_ON_ONCE(!subject || !subject->domain ||
399			 !subject->domain->hierarchy || !request))
400		return;
401
402	if (!is_valid_request(request))
403		return;
404
405	missing = request->access;
406	if (missing) {
407		/* Gets the nearest domain that denies the request. */
408		if (request->layer_masks) {
409			youngest_layer = get_denied_layer(
410				subject->domain, &missing, request->layer_masks,
411				request->layer_masks_size);
412		} else {
413			youngest_layer = get_layer_from_deny_masks(
414				&missing, request->all_existing_optional_access,
415				request->deny_masks);
416		}
417		youngest_denied =
418			get_hierarchy(subject->domain, youngest_layer);
419	} else {
420		youngest_layer = request->layer_plus_one - 1;
421		youngest_denied =
422			get_hierarchy(subject->domain, youngest_layer);
423	}
424
425	if (READ_ONCE(youngest_denied->log_status) == LANDLOCK_LOG_DISABLED)
426		return;
427
428	/*
429	 * Consistently keeps track of the number of denied access requests
430	 * even if audit is currently disabled, or if audit rules currently
431	 * exclude this record type, or if landlock_restrict_self(2)'s flags
432	 * quiet logs.
433	 */
434	atomic64_inc(&youngest_denied->num_denials);
435
436	if (!audit_enabled)
437		return;
438
439	/* Checks if the current exec was restricting itself. */
440	if (subject->domain_exec & BIT(youngest_layer)) {
441		/* Ignores denials for the same execution. */
442		if (!youngest_denied->log_same_exec)
443			return;
444	} else {
445		/* Ignores denials after a new execution. */
446		if (!youngest_denied->log_new_exec)
447			return;
448	}
449
450	/* Uses consistent allocation flags wrt common_lsm_audit(). */
451	ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
452			     AUDIT_LANDLOCK_ACCESS);
453	if (!ab)
454		return;
455
456	audit_log_format(ab, "domain=%llx blockers=", youngest_denied->id);
457	log_blockers(ab, request->type, missing);
458	audit_log_lsm_data(ab, &request->audit);
459	audit_log_end(ab);
460
461	/* Logs this domain the first time it shows in log. */
462	log_domain(youngest_denied);
463}
464
465/**
466 * landlock_log_drop_domain - Create an audit record on domain deallocation
467 *
468 * @hierarchy: The domain's hierarchy being deallocated.
469 *
470 * Only domains which previously appeared in the audit logs are logged again.
471 * This is useful to know when a domain will never show again in the audit log.
472 *
473 * Called in a work queue scheduled by landlock_put_ruleset_deferred() called
474 * by hook_cred_free().
475 */
476void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy)
477{
478	struct audit_buffer *ab;
479
480	if (WARN_ON_ONCE(!hierarchy))
481		return;
482
483	if (!audit_enabled)
484		return;
485
486	/* Ignores domains that were not logged.  */
487	if (READ_ONCE(hierarchy->log_status) != LANDLOCK_LOG_RECORDED)
488		return;
489
490	/*
491	 * If logging of domain allocation succeeded, warns about failure to log
492	 * domain deallocation to highlight unbalanced domain lifetime logs.
493	 */
494	ab = audit_log_start(audit_context(), GFP_KERNEL,
495			     AUDIT_LANDLOCK_DOMAIN);
496	if (!ab)
497		return;
498
499	audit_log_format(ab, "domain=%llx status=deallocated denials=%llu",
500			 hierarchy->id, atomic64_read(&hierarchy->num_denials));
501	audit_log_end(ab);
502}
503
504#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
505
506static struct kunit_case test_cases[] = {
507	/* clang-format off */
508	KUNIT_CASE(test_get_hierarchy),
509	KUNIT_CASE(test_get_denied_layer),
510	KUNIT_CASE(test_get_layer_from_deny_masks),
511	{}
512	/* clang-format on */
513};
514
515static struct kunit_suite test_suite = {
516	.name = "landlock_audit",
517	.test_cases = test_cases,
518};
519
520kunit_test_suite(test_suite);
521
522#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
~/ Read-only file preview.