xref: /linux/tools/testing/selftests/landlock/audit_test.c (revision 30e268185e59c3d5a1233416a2135cfda5630644)
16a500b22SMickaël Salaün // SPDX-License-Identifier: GPL-2.0
26a500b22SMickaël Salaün /*
36a500b22SMickaël Salaün  * Landlock tests - Audit
46a500b22SMickaël Salaün  *
56a500b22SMickaël Salaün  * Copyright © 2024-2025 Microsoft Corporation
66a500b22SMickaël Salaün  */
76a500b22SMickaël Salaün 
86a500b22SMickaël Salaün #define _GNU_SOURCE
96a500b22SMickaël Salaün #include <errno.h>
10960ed6caSMickaël Salaün #include <limits.h>
116a500b22SMickaël Salaün #include <linux/landlock.h>
12*6b456640SMickaël Salaün #include <pthread.h>
13960ed6caSMickaël Salaün #include <stdlib.h>
146a500b22SMickaël Salaün #include <sys/mount.h>
156a500b22SMickaël Salaün #include <sys/prctl.h>
166a500b22SMickaël Salaün #include <sys/types.h>
176a500b22SMickaël Salaün #include <sys/wait.h>
186a500b22SMickaël Salaün #include <unistd.h>
196a500b22SMickaël Salaün 
206a500b22SMickaël Salaün #include "audit.h"
216a500b22SMickaël Salaün #include "common.h"
226a500b22SMickaël Salaün 
matches_log_signal(struct __test_metadata * const _metadata,int audit_fd,const pid_t opid,__u64 * domain_id)236a500b22SMickaël Salaün static int matches_log_signal(struct __test_metadata *const _metadata,
246a500b22SMickaël Salaün 			      int audit_fd, const pid_t opid, __u64 *domain_id)
256a500b22SMickaël Salaün {
266a500b22SMickaël Salaün 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
276a500b22SMickaël Salaün 		" blockers=scope\\.signal opid=%d ocomm=\"audit_test\"$";
286a500b22SMickaël Salaün 	char log_match[sizeof(log_template) + 10];
296a500b22SMickaël Salaün 	int log_match_len;
306a500b22SMickaël Salaün 
316a500b22SMickaël Salaün 	log_match_len =
326a500b22SMickaël Salaün 		snprintf(log_match, sizeof(log_match), log_template, opid);
336a500b22SMickaël Salaün 	if (log_match_len > sizeof(log_match))
346a500b22SMickaël Salaün 		return -E2BIG;
356a500b22SMickaël Salaün 
366a500b22SMickaël Salaün 	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
376a500b22SMickaël Salaün 				  domain_id);
386a500b22SMickaël Salaün }
396a500b22SMickaël Salaün 
FIXTURE(audit)406a500b22SMickaël Salaün FIXTURE(audit)
416a500b22SMickaël Salaün {
426a500b22SMickaël Salaün 	struct audit_filter audit_filter;
436a500b22SMickaël Salaün 	int audit_fd;
446a500b22SMickaël Salaün };
456a500b22SMickaël Salaün 
FIXTURE_SETUP(audit)466a500b22SMickaël Salaün FIXTURE_SETUP(audit)
476a500b22SMickaël Salaün {
486a500b22SMickaël Salaün 	disable_caps(_metadata);
496a500b22SMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
506a500b22SMickaël Salaün 	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
516a500b22SMickaël Salaün 	EXPECT_LE(0, self->audit_fd)
526a500b22SMickaël Salaün 	{
536a500b22SMickaël Salaün 		const char *error_msg;
546a500b22SMickaël Salaün 
556a500b22SMickaël Salaün 		/* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
566a500b22SMickaël Salaün 		if (self->audit_fd == -EEXIST)
576a500b22SMickaël Salaün 			error_msg = "socket already in use (e.g. auditd)";
586a500b22SMickaël Salaün 		else
596a500b22SMickaël Salaün 			error_msg = strerror(-self->audit_fd);
606a500b22SMickaël Salaün 		TH_LOG("Failed to initialize audit: %s", error_msg);
616a500b22SMickaël Salaün 	}
626a500b22SMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
636a500b22SMickaël Salaün }
646a500b22SMickaël Salaün 
FIXTURE_TEARDOWN(audit)656a500b22SMickaël Salaün FIXTURE_TEARDOWN(audit)
666a500b22SMickaël Salaün {
676a500b22SMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
686a500b22SMickaël Salaün 	EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
696a500b22SMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
706a500b22SMickaël Salaün }
716a500b22SMickaël Salaün 
TEST_F(audit,layers)726a500b22SMickaël Salaün TEST_F(audit, layers)
736a500b22SMickaël Salaün {
746a500b22SMickaël Salaün 	const struct landlock_ruleset_attr ruleset_attr = {
756a500b22SMickaël Salaün 		.scoped = LANDLOCK_SCOPE_SIGNAL,
766a500b22SMickaël Salaün 	};
776a500b22SMickaël Salaün 	int status, ruleset_fd, i;
78e4a0f9e0SMickaël Salaün 	__u64(*domain_stack)[16];
796a500b22SMickaël Salaün 	__u64 prev_dom = 3;
806a500b22SMickaël Salaün 	pid_t child;
816a500b22SMickaël Salaün 
82e4a0f9e0SMickaël Salaün 	domain_stack = mmap(NULL, sizeof(*domain_stack), PROT_READ | PROT_WRITE,
83e4a0f9e0SMickaël Salaün 			    MAP_SHARED | MAP_ANONYMOUS, -1, 0);
84e4a0f9e0SMickaël Salaün 	ASSERT_NE(MAP_FAILED, domain_stack);
85e4a0f9e0SMickaël Salaün 	memset(domain_stack, 0, sizeof(*domain_stack));
86e4a0f9e0SMickaël Salaün 
876a500b22SMickaël Salaün 	ruleset_fd =
886a500b22SMickaël Salaün 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
896a500b22SMickaël Salaün 	ASSERT_LE(0, ruleset_fd);
906a500b22SMickaël Salaün 	EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
916a500b22SMickaël Salaün 
926a500b22SMickaël Salaün 	child = fork();
936a500b22SMickaël Salaün 	ASSERT_LE(0, child);
946a500b22SMickaël Salaün 	if (child == 0) {
95e4a0f9e0SMickaël Salaün 		for (i = 0; i < ARRAY_SIZE(*domain_stack); i++) {
966a500b22SMickaël Salaün 			__u64 denial_dom = 1;
976a500b22SMickaël Salaün 			__u64 allocated_dom = 2;
986a500b22SMickaël Salaün 
996a500b22SMickaël Salaün 			EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
1006a500b22SMickaël Salaün 
1016a500b22SMickaël Salaün 			/* Creates a denial to get the domain ID. */
1026a500b22SMickaël Salaün 			EXPECT_EQ(-1, kill(getppid(), 0));
1036a500b22SMickaël Salaün 			EXPECT_EQ(EPERM, errno);
1046a500b22SMickaël Salaün 			EXPECT_EQ(0,
1056a500b22SMickaël Salaün 				  matches_log_signal(_metadata, self->audit_fd,
1066a500b22SMickaël Salaün 						     getppid(), &denial_dom));
1076a500b22SMickaël Salaün 			EXPECT_EQ(0, matches_log_domain_allocated(
108*6b456640SMickaël Salaün 					     self->audit_fd, getpid(),
109*6b456640SMickaël Salaün 					     &allocated_dom));
1106a500b22SMickaël Salaün 			EXPECT_NE(denial_dom, 1);
1116a500b22SMickaël Salaün 			EXPECT_NE(denial_dom, 0);
1126a500b22SMickaël Salaün 			EXPECT_EQ(denial_dom, allocated_dom);
1136a500b22SMickaël Salaün 
1146a500b22SMickaël Salaün 			/* Checks that the new domain is younger than the previous one. */
1156a500b22SMickaël Salaün 			EXPECT_GT(allocated_dom, prev_dom);
1166a500b22SMickaël Salaün 			prev_dom = allocated_dom;
117e4a0f9e0SMickaël Salaün 			(*domain_stack)[i] = allocated_dom;
1186a500b22SMickaël Salaün 		}
1196a500b22SMickaël Salaün 
1206a500b22SMickaël Salaün 		/* Checks that we reached the maximum number of layers. */
1216a500b22SMickaël Salaün 		EXPECT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
1226a500b22SMickaël Salaün 		EXPECT_EQ(E2BIG, errno);
1236a500b22SMickaël Salaün 
1246a500b22SMickaël Salaün 		/* Updates filter rules to match the drop record. */
1256a500b22SMickaël Salaün 		set_cap(_metadata, CAP_AUDIT_CONTROL);
1266a500b22SMickaël Salaün 		EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
1276a500b22SMickaël Salaün 		EXPECT_EQ(0,
1286a500b22SMickaël Salaün 			  audit_filter_exe(self->audit_fd, &self->audit_filter,
1296a500b22SMickaël Salaün 					   AUDIT_DEL_RULE));
1306a500b22SMickaël Salaün 		clear_cap(_metadata, CAP_AUDIT_CONTROL);
1316a500b22SMickaël Salaün 
1326a500b22SMickaël Salaün 		_exit(_metadata->exit_code);
1336a500b22SMickaël Salaün 		return;
1346a500b22SMickaël Salaün 	}
1356a500b22SMickaël Salaün 
1366a500b22SMickaël Salaün 	ASSERT_EQ(child, waitpid(child, &status, 0));
1376a500b22SMickaël Salaün 	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
1386a500b22SMickaël Salaün 	    WEXITSTATUS(status) != EXIT_SUCCESS)
1396a500b22SMickaël Salaün 		_metadata->exit_code = KSFT_FAIL;
1406a500b22SMickaël Salaün 
1416a500b22SMickaël Salaün 	/* Purges log from deallocated domains. */
1426a500b22SMickaël Salaün 	EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
1436a500b22SMickaël Salaün 				&audit_tv_dom_drop, sizeof(audit_tv_dom_drop)));
144e4a0f9e0SMickaël Salaün 	for (i = ARRAY_SIZE(*domain_stack) - 1; i >= 0; i--) {
1456a500b22SMickaël Salaün 		__u64 deallocated_dom = 2;
1466a500b22SMickaël Salaün 
1476a500b22SMickaël Salaün 		EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1,
1486a500b22SMickaël Salaün 							    &deallocated_dom));
149e4a0f9e0SMickaël Salaün 		EXPECT_EQ((*domain_stack)[i], deallocated_dom)
1506a500b22SMickaël Salaün 		{
1516a500b22SMickaël Salaün 			TH_LOG("Failed to match domain %llx (#%d)",
152e4a0f9e0SMickaël Salaün 			       (*domain_stack)[i], i);
1536a500b22SMickaël Salaün 		}
1546a500b22SMickaël Salaün 	}
155e4a0f9e0SMickaël Salaün 	EXPECT_EQ(0, munmap(domain_stack, sizeof(*domain_stack)));
1566a500b22SMickaël Salaün 	EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
1576a500b22SMickaël Salaün 				&audit_tv_default, sizeof(audit_tv_default)));
1586a500b22SMickaël Salaün 	EXPECT_EQ(0, close(ruleset_fd));
1596a500b22SMickaël Salaün }
1606a500b22SMickaël Salaün 
161*6b456640SMickaël Salaün struct thread_data {
162*6b456640SMickaël Salaün 	pid_t parent_pid;
163*6b456640SMickaël Salaün 	int ruleset_fd, pipe_child, pipe_parent;
164*6b456640SMickaël Salaün };
165*6b456640SMickaël Salaün 
thread_audit_test(void * arg)166*6b456640SMickaël Salaün static void *thread_audit_test(void *arg)
167*6b456640SMickaël Salaün {
168*6b456640SMickaël Salaün 	const struct thread_data *data = (struct thread_data *)arg;
169*6b456640SMickaël Salaün 	uintptr_t err = 0;
170*6b456640SMickaël Salaün 	char buffer;
171*6b456640SMickaël Salaün 
172*6b456640SMickaël Salaün 	/* TGID and TID are different for a second thread. */
173*6b456640SMickaël Salaün 	if (getpid() == gettid()) {
174*6b456640SMickaël Salaün 		err = 1;
175*6b456640SMickaël Salaün 		goto out;
176*6b456640SMickaël Salaün 	}
177*6b456640SMickaël Salaün 
178*6b456640SMickaël Salaün 	if (landlock_restrict_self(data->ruleset_fd, 0)) {
179*6b456640SMickaël Salaün 		err = 2;
180*6b456640SMickaël Salaün 		goto out;
181*6b456640SMickaël Salaün 	}
182*6b456640SMickaël Salaün 
183*6b456640SMickaël Salaün 	if (close(data->ruleset_fd)) {
184*6b456640SMickaël Salaün 		err = 3;
185*6b456640SMickaël Salaün 		goto out;
186*6b456640SMickaël Salaün 	}
187*6b456640SMickaël Salaün 
188*6b456640SMickaël Salaün 	/* Creates a denial to get the domain ID. */
189*6b456640SMickaël Salaün 	if (kill(data->parent_pid, 0) != -1) {
190*6b456640SMickaël Salaün 		err = 4;
191*6b456640SMickaël Salaün 		goto out;
192*6b456640SMickaël Salaün 	}
193*6b456640SMickaël Salaün 
194*6b456640SMickaël Salaün 	if (EPERM != errno) {
195*6b456640SMickaël Salaün 		err = 5;
196*6b456640SMickaël Salaün 		goto out;
197*6b456640SMickaël Salaün 	}
198*6b456640SMickaël Salaün 
199*6b456640SMickaël Salaün 	/* Signals the parent to read denial logs. */
200*6b456640SMickaël Salaün 	if (write(data->pipe_child, ".", 1) != 1) {
201*6b456640SMickaël Salaün 		err = 6;
202*6b456640SMickaël Salaün 		goto out;
203*6b456640SMickaël Salaün 	}
204*6b456640SMickaël Salaün 
205*6b456640SMickaël Salaün 	/* Waits for the parent to update audit filters. */
206*6b456640SMickaël Salaün 	if (read(data->pipe_parent, &buffer, 1) != 1) {
207*6b456640SMickaël Salaün 		err = 7;
208*6b456640SMickaël Salaün 		goto out;
209*6b456640SMickaël Salaün 	}
210*6b456640SMickaël Salaün 
211*6b456640SMickaël Salaün out:
212*6b456640SMickaël Salaün 	close(data->pipe_child);
213*6b456640SMickaël Salaün 	close(data->pipe_parent);
214*6b456640SMickaël Salaün 	return (void *)err;
215*6b456640SMickaël Salaün }
216*6b456640SMickaël Salaün 
217*6b456640SMickaël Salaün /* Checks that the PID tied to a domain is not a TID but the TGID. */
TEST_F(audit,thread)218*6b456640SMickaël Salaün TEST_F(audit, thread)
219*6b456640SMickaël Salaün {
220*6b456640SMickaël Salaün 	const struct landlock_ruleset_attr ruleset_attr = {
221*6b456640SMickaël Salaün 		.scoped = LANDLOCK_SCOPE_SIGNAL,
222*6b456640SMickaël Salaün 	};
223*6b456640SMickaël Salaün 	__u64 denial_dom = 1;
224*6b456640SMickaël Salaün 	__u64 allocated_dom = 2;
225*6b456640SMickaël Salaün 	__u64 deallocated_dom = 3;
226*6b456640SMickaël Salaün 	pthread_t thread;
227*6b456640SMickaël Salaün 	int pipe_child[2], pipe_parent[2];
228*6b456640SMickaël Salaün 	char buffer;
229*6b456640SMickaël Salaün 	struct thread_data child_data;
230*6b456640SMickaël Salaün 
231*6b456640SMickaël Salaün 	child_data.parent_pid = getppid();
232*6b456640SMickaël Salaün 	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
233*6b456640SMickaël Salaün 	child_data.pipe_child = pipe_child[1];
234*6b456640SMickaël Salaün 	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
235*6b456640SMickaël Salaün 	child_data.pipe_parent = pipe_parent[0];
236*6b456640SMickaël Salaün 	child_data.ruleset_fd =
237*6b456640SMickaël Salaün 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
238*6b456640SMickaël Salaün 	ASSERT_LE(0, child_data.ruleset_fd);
239*6b456640SMickaël Salaün 
240*6b456640SMickaël Salaün 	/* TGID and TID are the same for the initial thread . */
241*6b456640SMickaël Salaün 	EXPECT_EQ(getpid(), gettid());
242*6b456640SMickaël Salaün 	EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
243*6b456640SMickaël Salaün 	ASSERT_EQ(0, pthread_create(&thread, NULL, thread_audit_test,
244*6b456640SMickaël Salaün 				    &child_data));
245*6b456640SMickaël Salaün 
246*6b456640SMickaël Salaün 	/* Waits for the child to generate a denial. */
247*6b456640SMickaël Salaün 	ASSERT_EQ(1, read(pipe_child[0], &buffer, 1));
248*6b456640SMickaël Salaün 	EXPECT_EQ(0, close(pipe_child[0]));
249*6b456640SMickaël Salaün 
250*6b456640SMickaël Salaün 	/* Matches the signal log to get the domain ID. */
251*6b456640SMickaël Salaün 	EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
252*6b456640SMickaël Salaün 					child_data.parent_pid, &denial_dom));
253*6b456640SMickaël Salaün 	EXPECT_NE(denial_dom, 1);
254*6b456640SMickaël Salaün 	EXPECT_NE(denial_dom, 0);
255*6b456640SMickaël Salaün 
256*6b456640SMickaël Salaün 	EXPECT_EQ(0, matches_log_domain_allocated(self->audit_fd, getpid(),
257*6b456640SMickaël Salaün 						  &allocated_dom));
258*6b456640SMickaël Salaün 	EXPECT_EQ(denial_dom, allocated_dom);
259*6b456640SMickaël Salaün 
260*6b456640SMickaël Salaün 	/* Updates filter rules to match the drop record. */
261*6b456640SMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
262*6b456640SMickaël Salaün 	EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
263*6b456640SMickaël Salaün 	EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
264*6b456640SMickaël Salaün 				      AUDIT_DEL_RULE));
265*6b456640SMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
266*6b456640SMickaël Salaün 
267*6b456640SMickaël Salaün 	/* Signals the thread to exit, which will generate a domain deallocation. */
268*6b456640SMickaël Salaün 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
269*6b456640SMickaël Salaün 	EXPECT_EQ(0, close(pipe_parent[1]));
270*6b456640SMickaël Salaün 	ASSERT_EQ(0, pthread_join(thread, NULL));
271*6b456640SMickaël Salaün 
272*6b456640SMickaël Salaün 	EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
273*6b456640SMickaël Salaün 				&audit_tv_dom_drop, sizeof(audit_tv_dom_drop)));
274*6b456640SMickaël Salaün 	EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1,
275*6b456640SMickaël Salaün 						    &deallocated_dom));
276*6b456640SMickaël Salaün 	EXPECT_EQ(denial_dom, deallocated_dom);
277*6b456640SMickaël Salaün 	EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
278*6b456640SMickaël Salaün 				&audit_tv_default, sizeof(audit_tv_default)));
279*6b456640SMickaël Salaün }
280*6b456640SMickaël Salaün 
FIXTURE(audit_flags)2816a500b22SMickaël Salaün FIXTURE(audit_flags)
2826a500b22SMickaël Salaün {
2836a500b22SMickaël Salaün 	struct audit_filter audit_filter;
2846a500b22SMickaël Salaün 	int audit_fd;
2856a500b22SMickaël Salaün 	__u64 *domain_id;
2866a500b22SMickaël Salaün };
2876a500b22SMickaël Salaün 
FIXTURE_VARIANT(audit_flags)2886a500b22SMickaël Salaün FIXTURE_VARIANT(audit_flags)
2896a500b22SMickaël Salaün {
2906a500b22SMickaël Salaün 	const int restrict_flags;
2916a500b22SMickaël Salaün };
2926a500b22SMickaël Salaün 
2936a500b22SMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,default)2946a500b22SMickaël Salaün FIXTURE_VARIANT_ADD(audit_flags, default) {
2956a500b22SMickaël Salaün 	/* clang-format on */
2966a500b22SMickaël Salaün 	.restrict_flags = 0,
2976a500b22SMickaël Salaün };
2986a500b22SMickaël Salaün 
2996a500b22SMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,same_exec_off)3006a500b22SMickaël Salaün FIXTURE_VARIANT_ADD(audit_flags, same_exec_off) {
3016a500b22SMickaël Salaün 	/* clang-format on */
3026a500b22SMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF,
3036a500b22SMickaël Salaün };
3046a500b22SMickaël Salaün 
3056a500b22SMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,subdomains_off)3066a500b22SMickaël Salaün FIXTURE_VARIANT_ADD(audit_flags, subdomains_off) {
3076a500b22SMickaël Salaün 	/* clang-format on */
3086a500b22SMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF,
3096a500b22SMickaël Salaün };
3106a500b22SMickaël Salaün 
3116a500b22SMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,cross_exec_on)3126a500b22SMickaël Salaün FIXTURE_VARIANT_ADD(audit_flags, cross_exec_on) {
3136a500b22SMickaël Salaün 	/* clang-format on */
3146a500b22SMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
3156a500b22SMickaël Salaün };
3166a500b22SMickaël Salaün 
FIXTURE_SETUP(audit_flags)3176a500b22SMickaël Salaün FIXTURE_SETUP(audit_flags)
3186a500b22SMickaël Salaün {
3196a500b22SMickaël Salaün 	disable_caps(_metadata);
3206a500b22SMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
3216a500b22SMickaël Salaün 	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
3226a500b22SMickaël Salaün 	EXPECT_LE(0, self->audit_fd)
3236a500b22SMickaël Salaün 	{
3246a500b22SMickaël Salaün 		const char *error_msg;
3256a500b22SMickaël Salaün 
3266a500b22SMickaël Salaün 		/* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
3276a500b22SMickaël Salaün 		if (self->audit_fd == -EEXIST)
3286a500b22SMickaël Salaün 			error_msg = "socket already in use (e.g. auditd)";
3296a500b22SMickaël Salaün 		else
3306a500b22SMickaël Salaün 			error_msg = strerror(-self->audit_fd);
3316a500b22SMickaël Salaün 		TH_LOG("Failed to initialize audit: %s", error_msg);
3326a500b22SMickaël Salaün 	}
3336a500b22SMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
3346a500b22SMickaël Salaün 
3356a500b22SMickaël Salaün 	self->domain_id = mmap(NULL, sizeof(*self->domain_id),
3366a500b22SMickaël Salaün 			       PROT_READ | PROT_WRITE,
3376a500b22SMickaël Salaün 			       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
3386a500b22SMickaël Salaün 	ASSERT_NE(MAP_FAILED, self->domain_id);
3396a500b22SMickaël Salaün 	/* Domain IDs are greater or equal to 2^32. */
3406a500b22SMickaël Salaün 	*self->domain_id = 1;
3416a500b22SMickaël Salaün }
3426a500b22SMickaël Salaün 
FIXTURE_TEARDOWN(audit_flags)3436a500b22SMickaël Salaün FIXTURE_TEARDOWN(audit_flags)
3446a500b22SMickaël Salaün {
3456a500b22SMickaël Salaün 	EXPECT_EQ(0, munmap(self->domain_id, sizeof(*self->domain_id)));
3466a500b22SMickaël Salaün 
3476a500b22SMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
3486a500b22SMickaël Salaün 	EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
3496a500b22SMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
3506a500b22SMickaël Salaün }
3516a500b22SMickaël Salaün 
TEST_F(audit_flags,signal)3526a500b22SMickaël Salaün TEST_F(audit_flags, signal)
3536a500b22SMickaël Salaün {
3546a500b22SMickaël Salaün 	int status;
3556a500b22SMickaël Salaün 	pid_t child;
3566a500b22SMickaël Salaün 	struct audit_records records;
3576a500b22SMickaël Salaün 	__u64 deallocated_dom = 2;
3586a500b22SMickaël Salaün 
3596a500b22SMickaël Salaün 	child = fork();
3606a500b22SMickaël Salaün 	ASSERT_LE(0, child);
3616a500b22SMickaël Salaün 	if (child == 0) {
3626a500b22SMickaël Salaün 		const struct landlock_ruleset_attr ruleset_attr = {
3636a500b22SMickaël Salaün 			.scoped = LANDLOCK_SCOPE_SIGNAL,
3646a500b22SMickaël Salaün 		};
3656a500b22SMickaël Salaün 		int ruleset_fd;
3666a500b22SMickaël Salaün 
3676a500b22SMickaël Salaün 		/* Add filesystem restrictions. */
3686a500b22SMickaël Salaün 		ruleset_fd = landlock_create_ruleset(&ruleset_attr,
3696a500b22SMickaël Salaün 						     sizeof(ruleset_attr), 0);
3706a500b22SMickaël Salaün 		ASSERT_LE(0, ruleset_fd);
3716a500b22SMickaël Salaün 		EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
3726a500b22SMickaël Salaün 		ASSERT_EQ(0, landlock_restrict_self(ruleset_fd,
3736a500b22SMickaël Salaün 						    variant->restrict_flags));
3746a500b22SMickaël Salaün 		EXPECT_EQ(0, close(ruleset_fd));
3756a500b22SMickaël Salaün 
3766a500b22SMickaël Salaün 		/* First signal checks to test log entries. */
3776a500b22SMickaël Salaün 		EXPECT_EQ(-1, kill(getppid(), 0));
3786a500b22SMickaël Salaün 		EXPECT_EQ(EPERM, errno);
3796a500b22SMickaël Salaün 
3806a500b22SMickaël Salaün 		if (variant->restrict_flags &
3816a500b22SMickaël Salaün 		    LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
3826a500b22SMickaël Salaün 			EXPECT_EQ(-EAGAIN, matches_log_signal(
3836a500b22SMickaël Salaün 						   _metadata, self->audit_fd,
3846a500b22SMickaël Salaün 						   getppid(), self->domain_id));
3856a500b22SMickaël Salaün 			EXPECT_EQ(*self->domain_id, 1);
3866a500b22SMickaël Salaün 		} else {
3876a500b22SMickaël Salaün 			__u64 allocated_dom = 3;
3886a500b22SMickaël Salaün 
3896a500b22SMickaël Salaün 			EXPECT_EQ(0, matches_log_signal(
3906a500b22SMickaël Salaün 					     _metadata, self->audit_fd,
3916a500b22SMickaël Salaün 					     getppid(), self->domain_id));
3926a500b22SMickaël Salaün 
3936a500b22SMickaël Salaün 			/* Checks domain information records. */
3946a500b22SMickaël Salaün 			EXPECT_EQ(0, matches_log_domain_allocated(
395*6b456640SMickaël Salaün 					     self->audit_fd, getpid(),
396*6b456640SMickaël Salaün 					     &allocated_dom));
3976a500b22SMickaël Salaün 			EXPECT_NE(*self->domain_id, 1);
3986a500b22SMickaël Salaün 			EXPECT_NE(*self->domain_id, 0);
3996a500b22SMickaël Salaün 			EXPECT_EQ(*self->domain_id, allocated_dom);
4006a500b22SMickaël Salaün 		}
4016a500b22SMickaël Salaün 
4026a500b22SMickaël Salaün 		/* Second signal checks to test audit_count_records(). */
4036a500b22SMickaël Salaün 		EXPECT_EQ(-1, kill(getppid(), 0));
4046a500b22SMickaël Salaün 		EXPECT_EQ(EPERM, errno);
4056a500b22SMickaël Salaün 
4066a500b22SMickaël Salaün 		/* Makes sure there is no superfluous logged records. */
4076a500b22SMickaël Salaün 		EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
4086a500b22SMickaël Salaün 		if (variant->restrict_flags &
4096a500b22SMickaël Salaün 		    LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
4106a500b22SMickaël Salaün 			EXPECT_EQ(0, records.access);
4116a500b22SMickaël Salaün 		} else {
4126a500b22SMickaël Salaün 			EXPECT_EQ(1, records.access);
4136a500b22SMickaël Salaün 		}
4146a500b22SMickaël Salaün 		EXPECT_EQ(0, records.domain);
4156a500b22SMickaël Salaün 
4166a500b22SMickaël Salaün 		/* Updates filter rules to match the drop record. */
4176a500b22SMickaël Salaün 		set_cap(_metadata, CAP_AUDIT_CONTROL);
4186a500b22SMickaël Salaün 		EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
4196a500b22SMickaël Salaün 		EXPECT_EQ(0,
4206a500b22SMickaël Salaün 			  audit_filter_exe(self->audit_fd, &self->audit_filter,
4216a500b22SMickaël Salaün 					   AUDIT_DEL_RULE));
4226a500b22SMickaël Salaün 		clear_cap(_metadata, CAP_AUDIT_CONTROL);
4236a500b22SMickaël Salaün 
4246a500b22SMickaël Salaün 		_exit(_metadata->exit_code);
4256a500b22SMickaël Salaün 		return;
4266a500b22SMickaël Salaün 	}
4276a500b22SMickaël Salaün 
4286a500b22SMickaël Salaün 	ASSERT_EQ(child, waitpid(child, &status, 0));
4296a500b22SMickaël Salaün 	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
4306a500b22SMickaël Salaün 	    WEXITSTATUS(status) != EXIT_SUCCESS)
4316a500b22SMickaël Salaün 		_metadata->exit_code = KSFT_FAIL;
4326a500b22SMickaël Salaün 
4336a500b22SMickaël Salaün 	if (variant->restrict_flags &
4346a500b22SMickaël Salaün 	    LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
4356a500b22SMickaël Salaün 		EXPECT_EQ(-EAGAIN,
4366a500b22SMickaël Salaün 			  matches_log_domain_deallocated(self->audit_fd, 0,
4376a500b22SMickaël Salaün 							 &deallocated_dom));
4386a500b22SMickaël Salaün 		EXPECT_EQ(deallocated_dom, 2);
4396a500b22SMickaël Salaün 	} else {
4406a500b22SMickaël Salaün 		EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
4416a500b22SMickaël Salaün 					&audit_tv_dom_drop,
4426a500b22SMickaël Salaün 					sizeof(audit_tv_dom_drop)));
4436a500b22SMickaël Salaün 		EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 2,
4446a500b22SMickaël Salaün 							    &deallocated_dom));
4456a500b22SMickaël Salaün 		EXPECT_NE(deallocated_dom, 2);
4466a500b22SMickaël Salaün 		EXPECT_NE(deallocated_dom, 0);
4476a500b22SMickaël Salaün 		EXPECT_EQ(deallocated_dom, *self->domain_id);
4486a500b22SMickaël Salaün 		EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
4496a500b22SMickaël Salaün 					&audit_tv_default,
4506a500b22SMickaël Salaün 					sizeof(audit_tv_default)));
4516a500b22SMickaël Salaün 	}
4526a500b22SMickaël Salaün }
4536a500b22SMickaël Salaün 
matches_log_fs_read_root(int audit_fd)454960ed6caSMickaël Salaün static int matches_log_fs_read_root(int audit_fd)
455960ed6caSMickaël Salaün {
456960ed6caSMickaël Salaün 	return audit_match_record(
457960ed6caSMickaël Salaün 		audit_fd, AUDIT_LANDLOCK_ACCESS,
458960ed6caSMickaël Salaün 		REGEX_LANDLOCK_PREFIX
459960ed6caSMickaël Salaün 		" blockers=fs\\.read_dir path=\"/\" dev=\"[^\"]\\+\" ino=[0-9]\\+$",
460960ed6caSMickaël Salaün 		NULL);
461960ed6caSMickaël Salaün }
462960ed6caSMickaël Salaün 
FIXTURE(audit_exec)463960ed6caSMickaël Salaün FIXTURE(audit_exec)
464960ed6caSMickaël Salaün {
465960ed6caSMickaël Salaün 	struct audit_filter audit_filter;
466960ed6caSMickaël Salaün 	int audit_fd;
467960ed6caSMickaël Salaün };
468960ed6caSMickaël Salaün 
FIXTURE_VARIANT(audit_exec)469960ed6caSMickaël Salaün FIXTURE_VARIANT(audit_exec)
470960ed6caSMickaël Salaün {
471960ed6caSMickaël Salaün 	const int restrict_flags;
472960ed6caSMickaël Salaün };
473960ed6caSMickaël Salaün 
474960ed6caSMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,default)475960ed6caSMickaël Salaün FIXTURE_VARIANT_ADD(audit_exec, default) {
476960ed6caSMickaël Salaün 	/* clang-format on */
477960ed6caSMickaël Salaün 	.restrict_flags = 0,
478960ed6caSMickaël Salaün };
479960ed6caSMickaël Salaün 
480960ed6caSMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,same_exec_off)481960ed6caSMickaël Salaün FIXTURE_VARIANT_ADD(audit_exec, same_exec_off) {
482960ed6caSMickaël Salaün 	/* clang-format on */
483960ed6caSMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF,
484960ed6caSMickaël Salaün };
485960ed6caSMickaël Salaün 
486960ed6caSMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,subdomains_off)487960ed6caSMickaël Salaün FIXTURE_VARIANT_ADD(audit_exec, subdomains_off) {
488960ed6caSMickaël Salaün 	/* clang-format on */
489960ed6caSMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF,
490960ed6caSMickaël Salaün };
491960ed6caSMickaël Salaün 
492960ed6caSMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,cross_exec_on)493960ed6caSMickaël Salaün FIXTURE_VARIANT_ADD(audit_exec, cross_exec_on) {
494960ed6caSMickaël Salaün 	/* clang-format on */
495960ed6caSMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
496960ed6caSMickaël Salaün };
497960ed6caSMickaël Salaün 
498960ed6caSMickaël Salaün /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,subdomains_off_and_cross_exec_on)499960ed6caSMickaël Salaün FIXTURE_VARIANT_ADD(audit_exec, subdomains_off_and_cross_exec_on) {
500960ed6caSMickaël Salaün 	/* clang-format on */
501960ed6caSMickaël Salaün 	.restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF |
502960ed6caSMickaël Salaün 			  LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
503960ed6caSMickaël Salaün };
504960ed6caSMickaël Salaün 
FIXTURE_SETUP(audit_exec)505960ed6caSMickaël Salaün FIXTURE_SETUP(audit_exec)
506960ed6caSMickaël Salaün {
507960ed6caSMickaël Salaün 	disable_caps(_metadata);
508960ed6caSMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
509960ed6caSMickaël Salaün 
510960ed6caSMickaël Salaün 	self->audit_fd = audit_init();
511960ed6caSMickaël Salaün 	EXPECT_LE(0, self->audit_fd)
512960ed6caSMickaël Salaün 	{
513960ed6caSMickaël Salaün 		const char *error_msg;
514960ed6caSMickaël Salaün 
515960ed6caSMickaël Salaün 		/* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
516960ed6caSMickaël Salaün 		if (self->audit_fd == -EEXIST)
517960ed6caSMickaël Salaün 			error_msg = "socket already in use (e.g. auditd)";
518960ed6caSMickaël Salaün 		else
519960ed6caSMickaël Salaün 			error_msg = strerror(-self->audit_fd);
520960ed6caSMickaël Salaün 		TH_LOG("Failed to initialize audit: %s", error_msg);
521960ed6caSMickaël Salaün 	}
522960ed6caSMickaël Salaün 
523960ed6caSMickaël Salaün 	/* Applies test filter for the bin_wait_pipe_sandbox program. */
524960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_init_filter_exe(&self->audit_filter,
525960ed6caSMickaël Salaün 					   bin_wait_pipe_sandbox));
526960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
527960ed6caSMickaël Salaün 				      AUDIT_ADD_RULE));
528960ed6caSMickaël Salaün 
529960ed6caSMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
530960ed6caSMickaël Salaün }
531960ed6caSMickaël Salaün 
FIXTURE_TEARDOWN(audit_exec)532960ed6caSMickaël Salaün FIXTURE_TEARDOWN(audit_exec)
533960ed6caSMickaël Salaün {
534960ed6caSMickaël Salaün 	set_cap(_metadata, CAP_AUDIT_CONTROL);
535960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
536960ed6caSMickaël Salaün 				      AUDIT_DEL_RULE));
537960ed6caSMickaël Salaün 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
538960ed6caSMickaël Salaün 	EXPECT_EQ(0, close(self->audit_fd));
539960ed6caSMickaël Salaün }
540960ed6caSMickaël Salaün 
TEST_F(audit_exec,signal_and_open)541960ed6caSMickaël Salaün TEST_F(audit_exec, signal_and_open)
542960ed6caSMickaël Salaün {
543960ed6caSMickaël Salaün 	struct audit_records records;
544960ed6caSMickaël Salaün 	int pipe_child[2], pipe_parent[2];
545960ed6caSMickaël Salaün 	char buf_parent;
546960ed6caSMickaël Salaün 	pid_t child;
547960ed6caSMickaël Salaün 	int status;
548960ed6caSMickaël Salaün 
549960ed6caSMickaël Salaün 	ASSERT_EQ(0, pipe2(pipe_child, 0));
550960ed6caSMickaël Salaün 	ASSERT_EQ(0, pipe2(pipe_parent, 0));
551960ed6caSMickaël Salaün 
552960ed6caSMickaël Salaün 	child = fork();
553960ed6caSMickaël Salaün 	ASSERT_LE(0, child);
554960ed6caSMickaël Salaün 	if (child == 0) {
555960ed6caSMickaël Salaün 		const struct landlock_ruleset_attr layer1 = {
556960ed6caSMickaël Salaün 			.scoped = LANDLOCK_SCOPE_SIGNAL,
557960ed6caSMickaël Salaün 		};
558960ed6caSMickaël Salaün 		char pipe_child_str[12], pipe_parent_str[12];
559960ed6caSMickaël Salaün 		char *const argv[] = { (char *)bin_wait_pipe_sandbox,
560960ed6caSMickaël Salaün 				       pipe_child_str, pipe_parent_str, NULL };
561960ed6caSMickaël Salaün 		int ruleset_fd;
562960ed6caSMickaël Salaün 
563960ed6caSMickaël Salaün 		/* Passes the pipe FDs to the executed binary. */
564960ed6caSMickaël Salaün 		EXPECT_EQ(0, close(pipe_child[0]));
565960ed6caSMickaël Salaün 		EXPECT_EQ(0, close(pipe_parent[1]));
566960ed6caSMickaël Salaün 		snprintf(pipe_child_str, sizeof(pipe_child_str), "%d",
567960ed6caSMickaël Salaün 			 pipe_child[1]);
568960ed6caSMickaël Salaün 		snprintf(pipe_parent_str, sizeof(pipe_parent_str), "%d",
569960ed6caSMickaël Salaün 			 pipe_parent[0]);
570960ed6caSMickaël Salaün 
571960ed6caSMickaël Salaün 		ruleset_fd =
572960ed6caSMickaël Salaün 			landlock_create_ruleset(&layer1, sizeof(layer1), 0);
573960ed6caSMickaël Salaün 		if (ruleset_fd < 0) {
574960ed6caSMickaël Salaün 			perror("Failed to create a ruleset");
575960ed6caSMickaël Salaün 			_exit(1);
576960ed6caSMickaël Salaün 		}
577960ed6caSMickaël Salaün 		prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
578960ed6caSMickaël Salaün 		if (landlock_restrict_self(ruleset_fd,
579960ed6caSMickaël Salaün 					   variant->restrict_flags)) {
580960ed6caSMickaël Salaün 			perror("Failed to restrict self");
581960ed6caSMickaël Salaün 			_exit(1);
582960ed6caSMickaël Salaün 		}
583960ed6caSMickaël Salaün 		close(ruleset_fd);
584960ed6caSMickaël Salaün 
585960ed6caSMickaël Salaün 		ASSERT_EQ(0, execve(argv[0], argv, NULL))
586960ed6caSMickaël Salaün 		{
587960ed6caSMickaël Salaün 			TH_LOG("Failed to execute \"%s\": %s", argv[0],
588960ed6caSMickaël Salaün 			       strerror(errno));
589960ed6caSMickaël Salaün 		};
590960ed6caSMickaël Salaün 		_exit(1);
591960ed6caSMickaël Salaün 		return;
592960ed6caSMickaël Salaün 	}
593960ed6caSMickaël Salaün 
594960ed6caSMickaël Salaün 	EXPECT_EQ(0, close(pipe_child[1]));
595960ed6caSMickaël Salaün 	EXPECT_EQ(0, close(pipe_parent[0]));
596960ed6caSMickaël Salaün 
597960ed6caSMickaël Salaün 	/* Waits for the child. */
598960ed6caSMickaël Salaün 	EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
599960ed6caSMickaël Salaün 
600960ed6caSMickaël Salaün 	/* Tests that there was no denial until now. */
601960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
602960ed6caSMickaël Salaün 	EXPECT_EQ(0, records.access);
603960ed6caSMickaël Salaün 	EXPECT_EQ(0, records.domain);
604960ed6caSMickaël Salaün 
605960ed6caSMickaël Salaün 	/*
606960ed6caSMickaël Salaün 	 * Wait for the child to do a first denied action by layer1 and
607960ed6caSMickaël Salaün 	 * sandbox itself with layer2.
608960ed6caSMickaël Salaün 	 */
609960ed6caSMickaël Salaün 	EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
610960ed6caSMickaël Salaün 	EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
611960ed6caSMickaël Salaün 
612960ed6caSMickaël Salaün 	/* Tests that the audit record only matches the child. */
613960ed6caSMickaël Salaün 	if (variant->restrict_flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON) {
614960ed6caSMickaël Salaün 		/* Matches the current domain. */
615960ed6caSMickaël Salaün 		EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
616960ed6caSMickaël Salaün 						getpid(), NULL));
617960ed6caSMickaël Salaün 	}
618960ed6caSMickaël Salaün 
619960ed6caSMickaël Salaün 	/* Checks that we didn't miss anything. */
620960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
621960ed6caSMickaël Salaün 	EXPECT_EQ(0, records.access);
622960ed6caSMickaël Salaün 
623960ed6caSMickaël Salaün 	/*
624960ed6caSMickaël Salaün 	 * Wait for the child to do a second denied action by layer1 and
625960ed6caSMickaël Salaün 	 * layer2, and sandbox itself with layer3.
626960ed6caSMickaël Salaün 	 */
627960ed6caSMickaël Salaün 	EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
628960ed6caSMickaël Salaün 	EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
629960ed6caSMickaël Salaün 
630960ed6caSMickaël Salaün 	/* Tests that the audit record only matches the child. */
631960ed6caSMickaël Salaün 	if (variant->restrict_flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON) {
632960ed6caSMickaël Salaün 		/* Matches the current domain. */
633960ed6caSMickaël Salaün 		EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
634960ed6caSMickaël Salaün 						getpid(), NULL));
635960ed6caSMickaël Salaün 	}
636960ed6caSMickaël Salaün 
637960ed6caSMickaël Salaün 	if (!(variant->restrict_flags &
638960ed6caSMickaël Salaün 	      LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) {
639960ed6caSMickaël Salaün 		/* Matches the child domain. */
640960ed6caSMickaël Salaün 		EXPECT_EQ(0, matches_log_fs_read_root(self->audit_fd));
641960ed6caSMickaël Salaün 	}
642960ed6caSMickaël Salaün 
643960ed6caSMickaël Salaün 	/* Checks that we didn't miss anything. */
644960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
645960ed6caSMickaël Salaün 	EXPECT_EQ(0, records.access);
646960ed6caSMickaël Salaün 
647960ed6caSMickaël Salaün 	/* Waits for the child to terminate. */
648960ed6caSMickaël Salaün 	EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
649960ed6caSMickaël Salaün 	ASSERT_EQ(child, waitpid(child, &status, 0));
650960ed6caSMickaël Salaün 	ASSERT_EQ(1, WIFEXITED(status));
651960ed6caSMickaël Salaün 	ASSERT_EQ(0, WEXITSTATUS(status));
652960ed6caSMickaël Salaün 
653960ed6caSMickaël Salaün 	/* Tests that the audit record only matches the child. */
654960ed6caSMickaël Salaün 	if (!(variant->restrict_flags &
655960ed6caSMickaël Salaün 	      LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) {
656960ed6caSMickaël Salaün 		/*
657960ed6caSMickaël Salaün 		 * Matches the child domains, which tests that the
658960ed6caSMickaël Salaün 		 * llcred->domain_exec bitmask is correctly updated with a new
659960ed6caSMickaël Salaün 		 * domain.
660960ed6caSMickaël Salaün 		 */
661960ed6caSMickaël Salaün 		EXPECT_EQ(0, matches_log_fs_read_root(self->audit_fd));
662960ed6caSMickaël Salaün 		EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
663960ed6caSMickaël Salaün 						getpid(), NULL));
664960ed6caSMickaël Salaün 	}
665960ed6caSMickaël Salaün 
666960ed6caSMickaël Salaün 	/* Checks that we didn't miss anything. */
667960ed6caSMickaël Salaün 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
668960ed6caSMickaël Salaün 	EXPECT_EQ(0, records.access);
669960ed6caSMickaël Salaün }
670960ed6caSMickaël Salaün 
6716a500b22SMickaël Salaün TEST_HARNESS_MAIN
672