1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Landlock tests - Audit
4 *
5 * Copyright © 2024-2025 Microsoft Corporation
6 */
7
8 #define _GNU_SOURCE
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <linux/landlock.h>
13 #include <pthread.h>
14 #include <stdlib.h>
15 #include <sys/mount.h>
16 #include <sys/prctl.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20
21 #include "audit.h"
22 #include "common.h"
23
matches_log_signal(struct __test_metadata * const _metadata,int audit_fd,const pid_t opid,__u64 * domain_id)24 static int matches_log_signal(struct __test_metadata *const _metadata,
25 int audit_fd, const pid_t opid, __u64 *domain_id)
26 {
27 static const char log_template[] = REGEX_LANDLOCK_PREFIX
28 " blockers=scope\\.signal opid=%d ocomm=\"audit_test\"$";
29 char log_match[sizeof(log_template) + 10];
30 int log_match_len;
31
32 log_match_len =
33 snprintf(log_match, sizeof(log_match), log_template, opid);
34 if (log_match_len > sizeof(log_match))
35 return -E2BIG;
36
37 return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
38 domain_id);
39 }
40
FIXTURE(audit)41 FIXTURE(audit)
42 {
43 struct audit_filter audit_filter;
44 int audit_fd;
45 };
46
FIXTURE_SETUP(audit)47 FIXTURE_SETUP(audit)
48 {
49 disable_caps(_metadata);
50 set_cap(_metadata, CAP_AUDIT_CONTROL);
51 self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
52 EXPECT_LE(0, self->audit_fd)
53 {
54 const char *error_msg;
55
56 /* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
57 if (self->audit_fd == -EEXIST)
58 error_msg = "socket already in use (e.g. auditd)";
59 else
60 error_msg = strerror(-self->audit_fd);
61 TH_LOG("Failed to initialize audit: %s", error_msg);
62 }
63 clear_cap(_metadata, CAP_AUDIT_CONTROL);
64 }
65
FIXTURE_TEARDOWN(audit)66 FIXTURE_TEARDOWN(audit)
67 {
68 set_cap(_metadata, CAP_AUDIT_CONTROL);
69 EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
70 clear_cap(_metadata, CAP_AUDIT_CONTROL);
71 }
72
TEST_F(audit,layers)73 TEST_F(audit, layers)
74 {
75 const struct landlock_ruleset_attr ruleset_attr = {
76 .scoped = LANDLOCK_SCOPE_SIGNAL,
77 };
78 int status, ruleset_fd, i;
79 __u64(*domain_stack)[16];
80 __u64 prev_dom = 3;
81 pid_t child;
82
83 domain_stack = mmap(NULL, sizeof(*domain_stack), PROT_READ | PROT_WRITE,
84 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
85 ASSERT_NE(MAP_FAILED, domain_stack);
86 memset(domain_stack, 0, sizeof(*domain_stack));
87
88 ruleset_fd =
89 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
90 ASSERT_LE(0, ruleset_fd);
91 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
92
93 child = fork();
94 ASSERT_LE(0, child);
95 if (child == 0) {
96 for (i = 0; i < ARRAY_SIZE(*domain_stack); i++) {
97 __u64 denial_dom = 1;
98 __u64 allocated_dom = 2;
99
100 EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
101
102 /* Creates a denial to get the domain ID. */
103 EXPECT_EQ(-1, kill(getppid(), 0));
104 EXPECT_EQ(EPERM, errno);
105 EXPECT_EQ(0,
106 matches_log_signal(_metadata, self->audit_fd,
107 getppid(), &denial_dom));
108 EXPECT_EQ(0, matches_log_domain_allocated(
109 self->audit_fd, getpid(),
110 &allocated_dom));
111 EXPECT_NE(denial_dom, 1);
112 EXPECT_NE(denial_dom, 0);
113 EXPECT_EQ(denial_dom, allocated_dom);
114
115 /* Checks that the new domain is younger than the previous one. */
116 EXPECT_GT(allocated_dom, prev_dom);
117 prev_dom = allocated_dom;
118 (*domain_stack)[i] = allocated_dom;
119 }
120
121 /* Checks that we reached the maximum number of layers. */
122 EXPECT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
123 EXPECT_EQ(E2BIG, errno);
124
125 /* Updates filter rules to match the drop record. */
126 set_cap(_metadata, CAP_AUDIT_CONTROL);
127 EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
128 EXPECT_EQ(0,
129 audit_filter_exe(self->audit_fd, &self->audit_filter,
130 AUDIT_DEL_RULE));
131 clear_cap(_metadata, CAP_AUDIT_CONTROL);
132
133 _exit(_metadata->exit_code);
134 return;
135 }
136
137 ASSERT_EQ(child, waitpid(child, &status, 0));
138 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
139 WEXITSTATUS(status) != EXIT_SUCCESS)
140 _metadata->exit_code = KSFT_FAIL;
141
142 /* Purges log from deallocated domains. */
143 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
144 &audit_tv_dom_drop, sizeof(audit_tv_dom_drop)));
145 for (i = ARRAY_SIZE(*domain_stack) - 1; i >= 0; i--) {
146 __u64 deallocated_dom = 2;
147
148 EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1,
149 &deallocated_dom));
150 EXPECT_EQ((*domain_stack)[i], deallocated_dom)
151 {
152 TH_LOG("Failed to match domain %llx (#%d)",
153 (*domain_stack)[i], i);
154 }
155 }
156 EXPECT_EQ(0, munmap(domain_stack, sizeof(*domain_stack)));
157 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
158 &audit_tv_default, sizeof(audit_tv_default)));
159 EXPECT_EQ(0, close(ruleset_fd));
160 }
161
162 struct thread_data {
163 pid_t parent_pid;
164 int ruleset_fd, pipe_child, pipe_parent;
165 };
166
thread_audit_test(void * arg)167 static void *thread_audit_test(void *arg)
168 {
169 const struct thread_data *data = (struct thread_data *)arg;
170 uintptr_t err = 0;
171 char buffer;
172
173 /* TGID and TID are different for a second thread. */
174 if (getpid() == gettid()) {
175 err = 1;
176 goto out;
177 }
178
179 if (landlock_restrict_self(data->ruleset_fd, 0)) {
180 err = 2;
181 goto out;
182 }
183
184 if (close(data->ruleset_fd)) {
185 err = 3;
186 goto out;
187 }
188
189 /* Creates a denial to get the domain ID. */
190 if (kill(data->parent_pid, 0) != -1) {
191 err = 4;
192 goto out;
193 }
194
195 if (EPERM != errno) {
196 err = 5;
197 goto out;
198 }
199
200 /* Signals the parent to read denial logs. */
201 if (write(data->pipe_child, ".", 1) != 1) {
202 err = 6;
203 goto out;
204 }
205
206 /* Waits for the parent to update audit filters. */
207 if (read(data->pipe_parent, &buffer, 1) != 1) {
208 err = 7;
209 goto out;
210 }
211
212 out:
213 close(data->pipe_child);
214 close(data->pipe_parent);
215 return (void *)err;
216 }
217
218 /* Checks that the PID tied to a domain is not a TID but the TGID. */
TEST_F(audit,thread)219 TEST_F(audit, thread)
220 {
221 const struct landlock_ruleset_attr ruleset_attr = {
222 .scoped = LANDLOCK_SCOPE_SIGNAL,
223 };
224 __u64 denial_dom = 1;
225 __u64 allocated_dom = 2;
226 __u64 deallocated_dom = 3;
227 pthread_t thread;
228 int pipe_child[2], pipe_parent[2];
229 char buffer;
230 struct thread_data child_data;
231
232 child_data.parent_pid = getppid();
233 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
234 child_data.pipe_child = pipe_child[1];
235 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
236 child_data.pipe_parent = pipe_parent[0];
237 child_data.ruleset_fd =
238 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
239 ASSERT_LE(0, child_data.ruleset_fd);
240
241 /* TGID and TID are the same for the initial thread . */
242 EXPECT_EQ(getpid(), gettid());
243 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
244 ASSERT_EQ(0, pthread_create(&thread, NULL, thread_audit_test,
245 &child_data));
246
247 /* Waits for the child to generate a denial. */
248 ASSERT_EQ(1, read(pipe_child[0], &buffer, 1));
249 EXPECT_EQ(0, close(pipe_child[0]));
250
251 /* Matches the signal log to get the domain ID. */
252 EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
253 child_data.parent_pid, &denial_dom));
254 EXPECT_NE(denial_dom, 1);
255 EXPECT_NE(denial_dom, 0);
256
257 EXPECT_EQ(0, matches_log_domain_allocated(self->audit_fd, getpid(),
258 &allocated_dom));
259 EXPECT_EQ(denial_dom, allocated_dom);
260
261 /* Updates filter rules to match the drop record. */
262 set_cap(_metadata, CAP_AUDIT_CONTROL);
263 EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
264 EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
265 AUDIT_DEL_RULE));
266 clear_cap(_metadata, CAP_AUDIT_CONTROL);
267
268 /* Signals the thread to exit, which will generate a domain deallocation. */
269 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
270 EXPECT_EQ(0, close(pipe_parent[1]));
271 ASSERT_EQ(0, pthread_join(thread, NULL));
272
273 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
274 &audit_tv_dom_drop, sizeof(audit_tv_dom_drop)));
275 EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1,
276 &deallocated_dom));
277 EXPECT_EQ(denial_dom, deallocated_dom);
278 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
279 &audit_tv_default, sizeof(audit_tv_default)));
280 }
281
FIXTURE(audit_flags)282 FIXTURE(audit_flags)
283 {
284 struct audit_filter audit_filter;
285 int audit_fd;
286 __u64 *domain_id;
287 };
288
FIXTURE_VARIANT(audit_flags)289 FIXTURE_VARIANT(audit_flags)
290 {
291 const int restrict_flags;
292 };
293
294 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,default)295 FIXTURE_VARIANT_ADD(audit_flags, default) {
296 /* clang-format on */
297 .restrict_flags = 0,
298 };
299
300 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,same_exec_off)301 FIXTURE_VARIANT_ADD(audit_flags, same_exec_off) {
302 /* clang-format on */
303 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF,
304 };
305
306 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,subdomains_off)307 FIXTURE_VARIANT_ADD(audit_flags, subdomains_off) {
308 /* clang-format on */
309 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF,
310 };
311
312 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_flags,cross_exec_on)313 FIXTURE_VARIANT_ADD(audit_flags, cross_exec_on) {
314 /* clang-format on */
315 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
316 };
317
FIXTURE_SETUP(audit_flags)318 FIXTURE_SETUP(audit_flags)
319 {
320 disable_caps(_metadata);
321 set_cap(_metadata, CAP_AUDIT_CONTROL);
322 self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
323 EXPECT_LE(0, self->audit_fd)
324 {
325 const char *error_msg;
326
327 /* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
328 if (self->audit_fd == -EEXIST)
329 error_msg = "socket already in use (e.g. auditd)";
330 else
331 error_msg = strerror(-self->audit_fd);
332 TH_LOG("Failed to initialize audit: %s", error_msg);
333 }
334 clear_cap(_metadata, CAP_AUDIT_CONTROL);
335
336 self->domain_id = mmap(NULL, sizeof(*self->domain_id),
337 PROT_READ | PROT_WRITE,
338 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
339 ASSERT_NE(MAP_FAILED, self->domain_id);
340 /* Domain IDs are greater or equal to 2^32. */
341 *self->domain_id = 1;
342 }
343
FIXTURE_TEARDOWN(audit_flags)344 FIXTURE_TEARDOWN(audit_flags)
345 {
346 EXPECT_EQ(0, munmap(self->domain_id, sizeof(*self->domain_id)));
347
348 set_cap(_metadata, CAP_AUDIT_CONTROL);
349 EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
350 clear_cap(_metadata, CAP_AUDIT_CONTROL);
351 }
352
TEST_F(audit_flags,signal)353 TEST_F(audit_flags, signal)
354 {
355 int status;
356 pid_t child;
357 struct audit_records records;
358 __u64 deallocated_dom = 2;
359
360 child = fork();
361 ASSERT_LE(0, child);
362 if (child == 0) {
363 const struct landlock_ruleset_attr ruleset_attr = {
364 .scoped = LANDLOCK_SCOPE_SIGNAL,
365 };
366 int ruleset_fd;
367
368 /* Add filesystem restrictions. */
369 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
370 sizeof(ruleset_attr), 0);
371 ASSERT_LE(0, ruleset_fd);
372 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
373 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd,
374 variant->restrict_flags));
375 EXPECT_EQ(0, close(ruleset_fd));
376
377 /* First signal checks to test log entries. */
378 EXPECT_EQ(-1, kill(getppid(), 0));
379 EXPECT_EQ(EPERM, errno);
380
381 if (variant->restrict_flags &
382 LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
383 EXPECT_EQ(-EAGAIN, matches_log_signal(
384 _metadata, self->audit_fd,
385 getppid(), self->domain_id));
386 EXPECT_EQ(*self->domain_id, 1);
387 } else {
388 __u64 allocated_dom = 3;
389
390 EXPECT_EQ(0, matches_log_signal(
391 _metadata, self->audit_fd,
392 getppid(), self->domain_id));
393
394 /* Checks domain information records. */
395 EXPECT_EQ(0, matches_log_domain_allocated(
396 self->audit_fd, getpid(),
397 &allocated_dom));
398 EXPECT_NE(*self->domain_id, 1);
399 EXPECT_NE(*self->domain_id, 0);
400 EXPECT_EQ(*self->domain_id, allocated_dom);
401 }
402
403 /* Second signal checks to test audit_count_records(). */
404 EXPECT_EQ(-1, kill(getppid(), 0));
405 EXPECT_EQ(EPERM, errno);
406
407 /* Makes sure there is no superfluous logged records. */
408 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
409 if (variant->restrict_flags &
410 LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
411 EXPECT_EQ(0, records.access);
412 } else {
413 EXPECT_EQ(1, records.access);
414 }
415 EXPECT_EQ(0, records.domain);
416
417 /* Updates filter rules to match the drop record. */
418 set_cap(_metadata, CAP_AUDIT_CONTROL);
419 EXPECT_EQ(0, audit_filter_drop(self->audit_fd, AUDIT_ADD_RULE));
420 EXPECT_EQ(0,
421 audit_filter_exe(self->audit_fd, &self->audit_filter,
422 AUDIT_DEL_RULE));
423 clear_cap(_metadata, CAP_AUDIT_CONTROL);
424
425 _exit(_metadata->exit_code);
426 return;
427 }
428
429 ASSERT_EQ(child, waitpid(child, &status, 0));
430 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
431 WEXITSTATUS(status) != EXIT_SUCCESS)
432 _metadata->exit_code = KSFT_FAIL;
433
434 if (variant->restrict_flags &
435 LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) {
436 EXPECT_EQ(-EAGAIN,
437 matches_log_domain_deallocated(self->audit_fd, 0,
438 &deallocated_dom));
439 EXPECT_EQ(deallocated_dom, 2);
440 } else {
441 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
442 &audit_tv_dom_drop,
443 sizeof(audit_tv_dom_drop)));
444 EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 2,
445 &deallocated_dom));
446 EXPECT_NE(deallocated_dom, 2);
447 EXPECT_NE(deallocated_dom, 0);
448 EXPECT_EQ(deallocated_dom, *self->domain_id);
449 EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO,
450 &audit_tv_default,
451 sizeof(audit_tv_default)));
452 }
453 }
454
matches_log_fs_read_root(int audit_fd)455 static int matches_log_fs_read_root(int audit_fd)
456 {
457 return audit_match_record(
458 audit_fd, AUDIT_LANDLOCK_ACCESS,
459 REGEX_LANDLOCK_PREFIX
460 " blockers=fs\\.read_dir path=\"/\" dev=\"[^\"]\\+\" ino=[0-9]\\+$",
461 NULL);
462 }
463
FIXTURE(audit_exec)464 FIXTURE(audit_exec)
465 {
466 struct audit_filter audit_filter;
467 int audit_fd;
468 };
469
FIXTURE_VARIANT(audit_exec)470 FIXTURE_VARIANT(audit_exec)
471 {
472 const int restrict_flags;
473 };
474
475 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,default)476 FIXTURE_VARIANT_ADD(audit_exec, default) {
477 /* clang-format on */
478 .restrict_flags = 0,
479 };
480
481 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,same_exec_off)482 FIXTURE_VARIANT_ADD(audit_exec, same_exec_off) {
483 /* clang-format on */
484 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF,
485 };
486
487 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,subdomains_off)488 FIXTURE_VARIANT_ADD(audit_exec, subdomains_off) {
489 /* clang-format on */
490 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF,
491 };
492
493 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,cross_exec_on)494 FIXTURE_VARIANT_ADD(audit_exec, cross_exec_on) {
495 /* clang-format on */
496 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
497 };
498
499 /* clang-format off */
FIXTURE_VARIANT_ADD(audit_exec,subdomains_off_and_cross_exec_on)500 FIXTURE_VARIANT_ADD(audit_exec, subdomains_off_and_cross_exec_on) {
501 /* clang-format on */
502 .restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF |
503 LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON,
504 };
505
FIXTURE_SETUP(audit_exec)506 FIXTURE_SETUP(audit_exec)
507 {
508 disable_caps(_metadata);
509 set_cap(_metadata, CAP_AUDIT_CONTROL);
510
511 self->audit_fd = audit_init();
512 EXPECT_LE(0, self->audit_fd)
513 {
514 const char *error_msg;
515
516 /* kill "$(auditctl -s | sed -ne 's/^pid \([0-9]\+\)$/\1/p')" */
517 if (self->audit_fd == -EEXIST)
518 error_msg = "socket already in use (e.g. auditd)";
519 else
520 error_msg = strerror(-self->audit_fd);
521 TH_LOG("Failed to initialize audit: %s", error_msg);
522 }
523
524 /* Applies test filter for the bin_wait_pipe_sandbox program. */
525 EXPECT_EQ(0, audit_init_filter_exe(&self->audit_filter,
526 bin_wait_pipe_sandbox));
527 EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
528 AUDIT_ADD_RULE));
529
530 clear_cap(_metadata, CAP_AUDIT_CONTROL);
531 }
532
FIXTURE_TEARDOWN(audit_exec)533 FIXTURE_TEARDOWN(audit_exec)
534 {
535 set_cap(_metadata, CAP_AUDIT_CONTROL);
536 EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
537 AUDIT_DEL_RULE));
538 clear_cap(_metadata, CAP_AUDIT_CONTROL);
539 EXPECT_EQ(0, close(self->audit_fd));
540 }
541
TEST_F(audit_exec,signal_and_open)542 TEST_F(audit_exec, signal_and_open)
543 {
544 struct audit_records records;
545 int pipe_child[2], pipe_parent[2];
546 char buf_parent;
547 pid_t child;
548 int status;
549
550 ASSERT_EQ(0, pipe2(pipe_child, 0));
551 ASSERT_EQ(0, pipe2(pipe_parent, 0));
552
553 child = fork();
554 ASSERT_LE(0, child);
555 if (child == 0) {
556 const struct landlock_ruleset_attr layer1 = {
557 .scoped = LANDLOCK_SCOPE_SIGNAL,
558 };
559 char pipe_child_str[12], pipe_parent_str[12];
560 char *const argv[] = { (char *)bin_wait_pipe_sandbox,
561 pipe_child_str, pipe_parent_str, NULL };
562 int ruleset_fd;
563
564 /* Passes the pipe FDs to the executed binary. */
565 EXPECT_EQ(0, close(pipe_child[0]));
566 EXPECT_EQ(0, close(pipe_parent[1]));
567 snprintf(pipe_child_str, sizeof(pipe_child_str), "%d",
568 pipe_child[1]);
569 snprintf(pipe_parent_str, sizeof(pipe_parent_str), "%d",
570 pipe_parent[0]);
571
572 ruleset_fd =
573 landlock_create_ruleset(&layer1, sizeof(layer1), 0);
574 if (ruleset_fd < 0) {
575 perror("Failed to create a ruleset");
576 _exit(1);
577 }
578 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
579 if (landlock_restrict_self(ruleset_fd,
580 variant->restrict_flags)) {
581 perror("Failed to restrict self");
582 _exit(1);
583 }
584 close(ruleset_fd);
585
586 ASSERT_EQ(0, execve(argv[0], argv, NULL))
587 {
588 TH_LOG("Failed to execute \"%s\": %s", argv[0],
589 strerror(errno));
590 };
591 _exit(1);
592 return;
593 }
594
595 EXPECT_EQ(0, close(pipe_child[1]));
596 EXPECT_EQ(0, close(pipe_parent[0]));
597
598 /* Waits for the child. */
599 EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
600
601 /* Tests that there was no denial until now. */
602 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
603 EXPECT_EQ(0, records.access);
604 EXPECT_EQ(0, records.domain);
605
606 /*
607 * Wait for the child to do a first denied action by layer1 and
608 * sandbox itself with layer2.
609 */
610 EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
611 EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
612
613 /* Tests that the audit record only matches the child. */
614 if (variant->restrict_flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON) {
615 /* Matches the current domain. */
616 EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
617 getpid(), NULL));
618 }
619
620 /* Checks that we didn't miss anything. */
621 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
622 EXPECT_EQ(0, records.access);
623
624 /*
625 * Wait for the child to do a second denied action by layer1 and
626 * layer2, and sandbox itself with layer3.
627 */
628 EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
629 EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
630
631 /* Tests that the audit record only matches the child. */
632 if (variant->restrict_flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON) {
633 /* Matches the current domain. */
634 EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
635 getpid(), NULL));
636 }
637
638 if (!(variant->restrict_flags &
639 LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) {
640 /* Matches the child domain. */
641 EXPECT_EQ(0, matches_log_fs_read_root(self->audit_fd));
642 }
643
644 /* Checks that we didn't miss anything. */
645 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
646 EXPECT_EQ(0, records.access);
647
648 /* Waits for the child to terminate. */
649 EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
650 ASSERT_EQ(child, waitpid(child, &status, 0));
651 ASSERT_EQ(1, WIFEXITED(status));
652 ASSERT_EQ(0, WEXITSTATUS(status));
653
654 /* Tests that the audit record only matches the child. */
655 if (!(variant->restrict_flags &
656 LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) {
657 /*
658 * Matches the child domains, which tests that the
659 * llcred->domain_exec bitmask is correctly updated with a new
660 * domain.
661 */
662 EXPECT_EQ(0, matches_log_fs_read_root(self->audit_fd));
663 EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd,
664 getpid(), NULL));
665 }
666
667 /* Checks that we didn't miss anything. */
668 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
669 EXPECT_EQ(0, records.access);
670 }
671
672 TEST_HARNESS_MAIN
673