xref: /linux/tools/testing/selftests/landlock/wait-pipe-sandbox.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Write in a pipe, wait, sandbox itself, test sandboxing, and wait again.
4  *
5  * Used by audit_exec.flags from audit_test.c
6  *
7  * Copyright © 2024-2025 Microsoft Corporation
8  */
9 
10 #define _GNU_SOURCE
11 #include <fcntl.h>
12 #include <linux/landlock.h>
13 #include <linux/prctl.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/prctl.h>
18 #include <unistd.h>
19 
20 #include "wrappers.h"
21 
22 static int sync_with(int pipe_child, int pipe_parent)
23 {
24 	char buf;
25 
26 	/* Signals that we are waiting. */
27 	if (write(pipe_child, ".", 1) != 1) {
28 		perror("Failed to write to first argument");
29 		return 1;
30 	}
31 
32 	/* Waits for the parent do its test. */
33 	if (read(pipe_parent, &buf, 1) != 1) {
34 		perror("Failed to write to the second argument");
35 		return 1;
36 	}
37 
38 	return 0;
39 }
40 
41 int main(int argc, char *argv[])
42 {
43 	const struct landlock_ruleset_attr layer2 = {
44 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
45 	};
46 	const struct landlock_ruleset_attr layer3 = {
47 		.scoped = LANDLOCK_SCOPE_SIGNAL,
48 	};
49 	int err, pipe_child, pipe_parent, ruleset_fd;
50 
51 	/* The first argument must be the file descriptor number of a pipe. */
52 	if (argc != 3) {
53 		fprintf(stderr, "Wrong number of arguments (not two)\n");
54 		return 1;
55 	}
56 
57 	pipe_child = atoi(argv[1]);
58 	pipe_parent = atoi(argv[2]);
59 	/* PR_SET_NO_NEW_PRIVS already set by parent. */
60 
61 	/* First step to test parent's layer1. */
62 	err = sync_with(pipe_child, pipe_parent);
63 	if (err)
64 		return err;
65 
66 	/* Tries to send a signal, denied by layer1. */
67 	if (!kill(getppid(), 0)) {
68 		fprintf(stderr, "Successfully sent a signal to the parent");
69 		return 1;
70 	}
71 
72 	/* Second step to test parent's layer1 and our layer2. */
73 	err = sync_with(pipe_child, pipe_parent);
74 	if (err)
75 		return err;
76 
77 	ruleset_fd = landlock_create_ruleset(&layer2, sizeof(layer2), 0);
78 	if (ruleset_fd < 0) {
79 		perror("Failed to create the layer2 ruleset");
80 		return 1;
81 	}
82 
83 	if (landlock_restrict_self(ruleset_fd, 0)) {
84 		perror("Failed to restrict self");
85 		return 1;
86 	}
87 	close(ruleset_fd);
88 
89 	/* Tries to send a signal, denied by layer1. */
90 	if (!kill(getppid(), 0)) {
91 		fprintf(stderr, "Successfully sent a signal to the parent");
92 		return 1;
93 	}
94 
95 	/* Tries to open ., denied by layer2. */
96 	if (open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC) >= 0) {
97 		fprintf(stderr, "Successfully opened /");
98 		return 1;
99 	}
100 
101 	/* Third step to test our layer2 and layer3. */
102 	err = sync_with(pipe_child, pipe_parent);
103 	if (err)
104 		return err;
105 
106 	ruleset_fd = landlock_create_ruleset(&layer3, sizeof(layer3), 0);
107 	if (ruleset_fd < 0) {
108 		perror("Failed to create the layer3 ruleset");
109 		return 1;
110 	}
111 
112 	if (landlock_restrict_self(ruleset_fd, 0)) {
113 		perror("Failed to restrict self");
114 		return 1;
115 	}
116 	close(ruleset_fd);
117 
118 	/* Tries to open ., denied by layer2. */
119 	if (open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC) >= 0) {
120 		fprintf(stderr, "Successfully opened /");
121 		return 1;
122 	}
123 
124 	/* Tries to send a signal, denied by layer3. */
125 	if (!kill(getppid(), 0)) {
126 		fprintf(stderr, "Successfully sent a signal to the parent");
127 		return 1;
128 	}
129 
130 	return 0;
131 }
132