xref: /linux/tools/testing/selftests/landlock/audit.h (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Landlock audit helpers
4  *
5  * Copyright © 2024-2025 Microsoft Corporation
6  */
7 
8 #define _GNU_SOURCE
9 #include <errno.h>
10 #include <linux/audit.h>
11 #include <linux/limits.h>
12 #include <linux/netlink.h>
13 #include <regex.h>
14 #include <stdbool.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/socket.h>
20 #include <sys/time.h>
21 #include <unistd.h>
22 
23 #include "kselftest.h"
24 
25 #ifndef ARRAY_SIZE
26 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
27 #endif
28 
29 #define REGEX_LANDLOCK_PREFIX "^audit([0-9.:]\\+): domain=\\([0-9a-f]\\+\\)"
30 
31 struct audit_filter {
32 	__u32 record_type;
33 	size_t exe_len;
34 	char exe[PATH_MAX];
35 };
36 
37 struct audit_message {
38 	struct nlmsghdr header;
39 	union {
40 		struct audit_status status;
41 		struct audit_features features;
42 		struct audit_rule_data rule;
43 		struct nlmsgerr err;
44 		char data[PATH_MAX + 200];
45 	};
46 };
47 
48 static const struct timeval audit_tv_default = {
49 	/*
50 	 * Default socket timeout for audit_match_record() callers that expect a
51 	 * record to arrive.  Asynchronous kauditd delivery can exceed 1 usec
52 	 * under heavy debug configs (KASAN, lockdep), where kauditd_thread
53 	 * scheduling between audit_log_end() and netlink_unicast() takes longer
54 	 * than the previous 1 usec timeout. 1 second is a generous ceiling: on
55 	 * the happy path, kauditd delivers within dozens of usec.
56 	 */
57 	.tv_sec = 1,
58 };
59 
60 static const struct timeval audit_tv_fast = {
61 	/*
62 	 * Fast timeout for paths that expect no record (audit_init() drain,
63 	 * audit_count_records(), probes).  Causes audit_recv() to return
64 	 * -EAGAIN once the socket buffer is empty, naturally terminating the
65 	 * read loop.
66 	 */
67 	.tv_usec = 1,
68 };
69 
70 static int audit_send(const int fd, const struct audit_message *const msg)
71 {
72 	struct sockaddr_nl addr = {
73 		.nl_family = AF_NETLINK,
74 	};
75 	int ret;
76 
77 	do {
78 		ret = sendto(fd, msg, msg->header.nlmsg_len, 0,
79 			     (struct sockaddr *)&addr, sizeof(addr));
80 	} while (ret < 0 && errno == EINTR);
81 
82 	if (ret < 0)
83 		return -errno;
84 
85 	if (ret != msg->header.nlmsg_len)
86 		return -E2BIG;
87 
88 	return 0;
89 }
90 
91 static int audit_recv(const int fd, struct audit_message *msg)
92 {
93 	struct sockaddr_nl addr;
94 	socklen_t addrlen = sizeof(addr);
95 	struct audit_message msg_tmp;
96 	int err;
97 
98 	if (!msg)
99 		msg = &msg_tmp;
100 
101 	do {
102 		err = recvfrom(fd, msg, sizeof(*msg), 0,
103 			       (struct sockaddr *)&addr, &addrlen);
104 	} while (err < 0 && errno == EINTR);
105 
106 	if (err < 0)
107 		return -errno;
108 
109 	if (addrlen != sizeof(addr) || addr.nl_pid != 0)
110 		return -EINVAL;
111 
112 	/* Checks Netlink error or end of messages. */
113 	if (msg->header.nlmsg_type == NLMSG_ERROR)
114 		return msg->err.error;
115 
116 	return 0;
117 }
118 
119 static int audit_request(const int fd,
120 			 const struct audit_message *const request,
121 			 struct audit_message *reply)
122 {
123 	struct audit_message msg_tmp;
124 	bool first_reply = true;
125 	int err;
126 
127 	err = audit_send(fd, request);
128 	if (err)
129 		return err;
130 
131 	if (!reply)
132 		reply = &msg_tmp;
133 
134 	do {
135 		if (first_reply)
136 			first_reply = false;
137 		else
138 			reply = &msg_tmp;
139 
140 		err = audit_recv(fd, reply);
141 		if (err)
142 			return err;
143 	} while (reply->header.nlmsg_type != NLMSG_ERROR &&
144 		 reply->err.msg.nlmsg_type != request->header.nlmsg_type);
145 
146 	return reply->err.error;
147 }
148 
149 static int audit_filter_exe(const int audit_fd,
150 			    const struct audit_filter *const filter,
151 			    const __u16 type)
152 {
153 	struct audit_message msg = {
154 		.header = {
155 			.nlmsg_len = NLMSG_SPACE(sizeof(msg.rule)) +
156 				     NLMSG_ALIGN(filter->exe_len),
157 			.nlmsg_type = type,
158 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
159 		},
160 		.rule = {
161 			.flags = AUDIT_FILTER_EXCLUDE,
162 			.action = AUDIT_NEVER,
163 			.field_count = 1,
164 			.fields[0] = filter->record_type,
165 			.fieldflags[0] = AUDIT_NOT_EQUAL,
166 			.values[0] = filter->exe_len,
167 			.buflen = filter->exe_len,
168 		}
169 	};
170 
171 	if (filter->record_type != AUDIT_EXE)
172 		return -EINVAL;
173 
174 	memcpy(msg.rule.buf, filter->exe, filter->exe_len);
175 	return audit_request(audit_fd, &msg, NULL);
176 }
177 
178 static int audit_filter_drop(const int audit_fd, const __u16 type)
179 {
180 	struct audit_message msg = {
181 		.header = {
182 			.nlmsg_len = NLMSG_SPACE(sizeof(msg.rule)),
183 			.nlmsg_type = type,
184 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
185 		},
186 		.rule = {
187 			.flags = AUDIT_FILTER_EXCLUDE,
188 			.action = AUDIT_NEVER,
189 			.field_count = 1,
190 			.fields[0] = AUDIT_MSGTYPE,
191 			.fieldflags[0] = AUDIT_NOT_EQUAL,
192 			.values[0] = AUDIT_LANDLOCK_DOMAIN,
193 		}
194 	};
195 
196 	return audit_request(audit_fd, &msg, NULL);
197 }
198 
199 static int audit_set_status(int fd, __u32 key, __u32 val)
200 {
201 	const struct audit_message msg = {
202 		.header = {
203 			.nlmsg_len = NLMSG_SPACE(sizeof(msg.status)),
204 			.nlmsg_type = AUDIT_SET,
205 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
206 		},
207 		.status = {
208 			.mask = key,
209 			.enabled = key == AUDIT_STATUS_ENABLED ? val : 0,
210 			.pid = key == AUDIT_STATUS_PID ? val : 0,
211 		}
212 	};
213 
214 	return audit_request(fd, &msg, NULL);
215 }
216 
217 /* Returns a pointer to the last filled character of @dst, which is `\0`.  */
218 static __maybe_unused char *regex_escape(const char *const src, char *dst,
219 					 size_t dst_size)
220 {
221 	char *d = dst;
222 
223 	for (const char *s = src; *s; s++) {
224 		switch (*s) {
225 		case '$':
226 		case '*':
227 		case '.':
228 		case '[':
229 		case '\\':
230 		case ']':
231 		case '^':
232 			if (d >= dst + dst_size - 2)
233 				return (char *)-ENOMEM;
234 
235 			*d++ = '\\';
236 			*d++ = *s;
237 			break;
238 		default:
239 			if (d >= dst + dst_size - 1)
240 				return (char *)-ENOMEM;
241 
242 			*d++ = *s;
243 		}
244 	}
245 	if (d >= dst + dst_size - 1)
246 		return (char *)-ENOMEM;
247 
248 	*d = '\0';
249 	return d;
250 }
251 
252 /*
253  * @domain_id: The domain ID extracted from the audit message (if the first part
254  * of @pattern is REGEX_LANDLOCK_PREFIX).  It is set to 0 if the domain ID is
255  * not found.
256  */
257 static int audit_match_record(int audit_fd, const __u16 type,
258 			      const char *const pattern, __u64 *domain_id)
259 {
260 	struct audit_message msg, last_mismatch = {};
261 	int ret, err = 0;
262 	int num_type_match = 0;
263 	regmatch_t matches[2];
264 	regex_t regex;
265 
266 	ret = regcomp(&regex, pattern, 0);
267 	if (ret)
268 		return -EINVAL;
269 
270 	/*
271 	 * Reads records until one matches both the expected type and the
272 	 * pattern.  Type-matching records with non-matching content are
273 	 * silently consumed, which handles stale domain deallocation records
274 	 * from a previous test emitted asynchronously by kworker threads.
275 	 */
276 	while (true) {
277 		memset(&msg, 0, sizeof(msg));
278 		err = audit_recv(audit_fd, &msg);
279 		if (err) {
280 			if (num_type_match) {
281 				printf("DATA: %s\n", last_mismatch.data);
282 				printf("ERROR: %d record(s) matched type %u"
283 				       " but not pattern: %s\n",
284 				       num_type_match, type, pattern);
285 			}
286 			goto out;
287 		}
288 
289 		if (type && msg.header.nlmsg_type != type)
290 			continue;
291 
292 		ret = regexec(&regex, msg.data, ARRAY_SIZE(matches), matches,
293 			      0);
294 		if (!ret)
295 			break;
296 
297 		num_type_match++;
298 		last_mismatch = msg;
299 	}
300 
301 	if (domain_id) {
302 		*domain_id = 0;
303 		if (matches[1].rm_so != -1) {
304 			int match_len = matches[1].rm_eo - matches[1].rm_so;
305 			/* The maximal characters of a 2^64 hexadecimal number is 17. */
306 			char dom_id[18];
307 
308 			if (match_len > 0 && match_len < sizeof(dom_id)) {
309 				memcpy(dom_id, msg.data + matches[1].rm_so,
310 				       match_len);
311 				dom_id[match_len] = '\0';
312 				if (domain_id)
313 					*domain_id = strtoull(dom_id, NULL, 16);
314 			}
315 		}
316 	}
317 
318 out:
319 	regfree(&regex);
320 	return err;
321 }
322 
323 static int __maybe_unused matches_log_domain_allocated(int audit_fd, pid_t pid,
324 						       __u64 *domain_id)
325 {
326 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
327 		" status=allocated mode=enforcing pid=%d uid=[0-9]\\+"
328 		" exe=\"[^\"]\\+\" comm=\".*_test\"$";
329 	char log_match[sizeof(log_template) + 10];
330 	int log_match_len;
331 
332 	log_match_len =
333 		snprintf(log_match, sizeof(log_match), log_template, pid);
334 	if (log_match_len >= sizeof(log_match))
335 		return -E2BIG;
336 
337 	return audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match,
338 				  domain_id);
339 }
340 
341 /*
342  * Matches a domain deallocation record.  When expected_domain_id is non-zero,
343  * the pattern includes the specific domain ID so that stale deallocation
344  * records from a previous test (with a different domain ID) are skipped by
345  * audit_match_record(), waiting for the asynchronous kworker deallocation with
346  * the default patient timeout.
347  *
348  * When expected_domain_id is zero, the caller is probing for any dealloc record
349  * that may or may not arrive.  Temporarily lowers the socket timeout to
350  * audit_tv_fast for this probe so it returns promptly when no record is
351  * pending; restores audit_tv_default after.
352  */
353 static int __maybe_unused
354 matches_log_domain_deallocated(int audit_fd, unsigned int num_denials,
355 			       __u64 expected_domain_id, __u64 *domain_id)
356 {
357 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
358 		" status=deallocated denials=%u$";
359 	static const char log_template_with_id[] =
360 		"^audit([0-9.:]\\+): domain=\\(%llx\\)"
361 		" status=deallocated denials=%u$";
362 	char log_match[sizeof(log_template_with_id) + 32];
363 	int log_match_len, err;
364 
365 	if (expected_domain_id)
366 		log_match_len = snprintf(log_match, sizeof(log_match),
367 					 log_template_with_id,
368 					 (unsigned long long)expected_domain_id,
369 					 num_denials);
370 	else
371 		log_match_len = snprintf(log_match, sizeof(log_match),
372 					 log_template, num_denials);
373 
374 	if (log_match_len >= sizeof(log_match))
375 		return -E2BIG;
376 
377 	if (!expected_domain_id) {
378 		if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO,
379 			       &audit_tv_fast, sizeof(audit_tv_fast)))
380 			return -errno;
381 	}
382 
383 	err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match,
384 				 domain_id);
385 
386 	if (!expected_domain_id) {
387 		if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO,
388 			       &audit_tv_default, sizeof(audit_tv_default)) &&
389 		    !err)
390 			err = -errno;
391 	}
392 
393 	return err;
394 }
395 
396 struct audit_records {
397 	size_t access;
398 	size_t domain;
399 };
400 
401 /*
402  * Counts remaining audit records by type, skipping domain deallocation records.
403  * Deallocation records are emitted asynchronously from kworker threads after a
404  * previous test's child has exited, so they can arrive after the drain in
405  * audit_init() and after the preceding audit_match_record() call.  Allocation
406  * records are emitted synchronously during landlock_log_denial() in the current
407  * test's syscall context, so only those are counted in records->domain.
408  *
409  * Temporarily lowers SO_RCVTIMEO to audit_tv_fast for the read loop: this is a
410  * "no record expected" path that should terminate on the first -EAGAIN.  The
411  * default patient timeout is restored on exit for subsequent
412  * audit_match_record() callers.
413  */
414 static int audit_count_records(int audit_fd, struct audit_records *records)
415 {
416 	static const char dealloc_pattern[] = REGEX_LANDLOCK_PREFIX
417 		" status=deallocated ";
418 	struct audit_message msg;
419 	regex_t dealloc_re;
420 	int ret, err = 0;
421 
422 	ret = regcomp(&dealloc_re, dealloc_pattern, 0);
423 	if (ret)
424 		return -ENOMEM;
425 
426 	records->access = 0;
427 	records->domain = 0;
428 
429 	if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast,
430 		       sizeof(audit_tv_fast))) {
431 		err = -errno;
432 		goto out;
433 	}
434 
435 	do {
436 		memset(&msg, 0, sizeof(msg));
437 		err = audit_recv(audit_fd, &msg);
438 		if (err) {
439 			if (err == -EAGAIN)
440 				err = 0;
441 			break;
442 		}
443 
444 		switch (msg.header.nlmsg_type) {
445 		case AUDIT_LANDLOCK_ACCESS:
446 			records->access++;
447 			break;
448 		case AUDIT_LANDLOCK_DOMAIN:
449 			ret = regexec(&dealloc_re, msg.data, 0, NULL, 0);
450 			if (ret == REG_NOMATCH) {
451 				records->domain++;
452 			} else if (ret != 0) {
453 				err = -EIO;
454 				goto out;
455 			}
456 			break;
457 		}
458 	} while (true);
459 
460 out:
461 	if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
462 		       sizeof(audit_tv_default)) &&
463 	    !err)
464 		err = -errno;
465 	regfree(&dealloc_re);
466 	return err;
467 }
468 
469 static int audit_init(void)
470 {
471 	int fd, err;
472 
473 	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
474 	if (fd < 0)
475 		return -errno;
476 
477 	err = audit_set_status(fd, AUDIT_STATUS_ENABLED, 1);
478 	if (err)
479 		goto err_close;
480 
481 	err = audit_set_status(fd, AUDIT_STATUS_PID, getpid());
482 	if (err)
483 		goto err_close;
484 
485 	/* Uses the fast timeout to drain stale records below. */
486 	err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast,
487 			 sizeof(audit_tv_fast));
488 	if (err) {
489 		err = -errno;
490 		goto err_close;
491 	}
492 
493 	/*
494 	 * Drains stale audit records that accumulated in the kernel backlog
495 	 * while no audit daemon socket was open.  This happens when non-audit
496 	 * Landlock tests generate records while audit_enabled is non-zero (e.g.
497 	 * from boot configuration), or when domain deallocation records arrive
498 	 * asynchronously after a previous test's socket was closed.
499 	 */
500 	while (audit_recv(fd, NULL) == 0)
501 		;
502 
503 	/*
504 	 * Restores the default timeout for audit_match_record() callers that
505 	 * expect a record to arrive.  Paths that expect no record restore the
506 	 * fast timeout locally (audit_count_records(), the expected_domain_id
507 	 * == 0 probe in matches_log_domain_deallocated()).
508 	 */
509 	err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
510 			 sizeof(audit_tv_default));
511 	if (err) {
512 		err = -errno;
513 		goto err_close;
514 	}
515 
516 	return fd;
517 
518 err_close:
519 	close(fd);
520 	return err;
521 }
522 
523 static int audit_init_filter_exe(struct audit_filter *filter, const char *path)
524 {
525 	char *absolute_path = NULL;
526 
527 	/* It is assume that there is not already filtering rules. */
528 	filter->record_type = AUDIT_EXE;
529 	if (!path) {
530 		int ret = readlink("/proc/self/exe", filter->exe,
531 				   sizeof(filter->exe) - 1);
532 		if (ret < 0)
533 			return -errno;
534 
535 		filter->exe_len = ret;
536 		return 0;
537 	}
538 
539 	absolute_path = realpath(path, NULL);
540 	if (!absolute_path)
541 		return -errno;
542 
543 	/* No need for the terminating NULL byte. */
544 	filter->exe_len = strlen(absolute_path);
545 	if (filter->exe_len > sizeof(filter->exe))
546 		return -E2BIG;
547 
548 	memcpy(filter->exe, absolute_path, filter->exe_len);
549 	free(absolute_path);
550 	return 0;
551 }
552 
553 static int audit_cleanup(int audit_fd, struct audit_filter *filter)
554 {
555 	struct audit_filter new_filter;
556 	int err = 0;
557 
558 	if (audit_fd < 0 || !filter) {
559 		/*
560 		 * Simulates audit_init_with_exe_filter() when called from
561 		 * FIXTURE_TEARDOWN_PARENT().
562 		 */
563 		audit_fd = audit_init();
564 		if (audit_fd < 0)
565 			return audit_fd;
566 
567 		filter = &new_filter;
568 		err = audit_init_filter_exe(filter, NULL);
569 		if (err)
570 			goto err_close;
571 	}
572 
573 	/* Filters might not be in place. */
574 	audit_filter_exe(audit_fd, filter, AUDIT_DEL_RULE);
575 	audit_filter_drop(audit_fd, AUDIT_DEL_RULE);
576 
577 	err = audit_set_status(audit_fd, AUDIT_STATUS_ENABLED, 0);
578 
579 err_close:
580 	close(audit_fd);
581 	return err;
582 }
583 
584 static int audit_init_with_exe_filter(struct audit_filter *filter)
585 {
586 	int fd, err;
587 
588 	fd = audit_init();
589 	if (fd < 0)
590 		return fd;
591 
592 	err = audit_init_filter_exe(filter, NULL);
593 	if (err)
594 		goto err_close;
595 
596 	err = audit_filter_exe(fd, filter, AUDIT_ADD_RULE);
597 	if (err)
598 		goto err_close;
599 
600 	return fd;
601 
602 err_close:
603 	close(fd);
604 	return err;
605 }
606