1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Landlock tests - Common user space base
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6  * Copyright © 2019-2020 ANSSI
7  */
8 
9 #define _GNU_SOURCE
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <linux/keyctl.h>
13 #include <linux/landlock.h>
14 #include <string.h>
15 #include <sys/prctl.h>
16 #include <sys/socket.h>
17 #include <sys/types.h>
18 
19 #include "common.h"
20 
21 #ifndef O_PATH
22 #define O_PATH 010000000
23 #endif
24 
TEST(inconsistent_attr)25 TEST(inconsistent_attr)
26 {
27 	const long page_size = sysconf(_SC_PAGESIZE);
28 	char *const buf = malloc(page_size + 1);
29 	struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
30 
31 	ASSERT_NE(NULL, buf);
32 
33 	/* Checks copy_from_user(). */
34 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0));
35 	/* The size if less than sizeof(struct landlock_attr_enforce). */
36 	ASSERT_EQ(EINVAL, errno);
37 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0));
38 	ASSERT_EQ(EINVAL, errno);
39 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0));
40 	ASSERT_EQ(EINVAL, errno);
41 
42 	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0));
43 	/* The size if less than sizeof(struct landlock_attr_enforce). */
44 	ASSERT_EQ(EFAULT, errno);
45 
46 	ASSERT_EQ(-1, landlock_create_ruleset(
47 			      NULL, sizeof(struct landlock_ruleset_attr), 0));
48 	ASSERT_EQ(EFAULT, errno);
49 
50 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
51 	ASSERT_EQ(E2BIG, errno);
52 
53 	/* Checks minimal valid attribute size. */
54 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0));
55 	ASSERT_EQ(ENOMSG, errno);
56 	ASSERT_EQ(-1, landlock_create_ruleset(
57 			      ruleset_attr,
58 			      sizeof(struct landlock_ruleset_attr), 0));
59 	ASSERT_EQ(ENOMSG, errno);
60 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
61 	ASSERT_EQ(ENOMSG, errno);
62 
63 	/* Checks non-zero value. */
64 	buf[page_size - 2] = '.';
65 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
66 	ASSERT_EQ(E2BIG, errno);
67 
68 	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
69 	ASSERT_EQ(E2BIG, errno);
70 
71 	free(buf);
72 }
73 
TEST(abi_version)74 TEST(abi_version)
75 {
76 	const struct landlock_ruleset_attr ruleset_attr = {
77 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
78 	};
79 	ASSERT_EQ(3, landlock_create_ruleset(NULL, 0,
80 					     LANDLOCK_CREATE_RULESET_VERSION));
81 
82 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
83 					      LANDLOCK_CREATE_RULESET_VERSION));
84 	ASSERT_EQ(EINVAL, errno);
85 
86 	ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
87 					      LANDLOCK_CREATE_RULESET_VERSION));
88 	ASSERT_EQ(EINVAL, errno);
89 
90 	ASSERT_EQ(-1,
91 		  landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
92 					  LANDLOCK_CREATE_RULESET_VERSION));
93 	ASSERT_EQ(EINVAL, errno);
94 
95 	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
96 					      LANDLOCK_CREATE_RULESET_VERSION |
97 						      1 << 31));
98 	ASSERT_EQ(EINVAL, errno);
99 }
100 
101 /* Tests ordering of syscall argument checks. */
TEST(create_ruleset_checks_ordering)102 TEST(create_ruleset_checks_ordering)
103 {
104 	const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
105 	const int invalid_flag = last_flag << 1;
106 	int ruleset_fd;
107 	const struct landlock_ruleset_attr ruleset_attr = {
108 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
109 	};
110 
111 	/* Checks priority for invalid flags. */
112 	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag));
113 	ASSERT_EQ(EINVAL, errno);
114 
115 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag));
116 	ASSERT_EQ(EINVAL, errno);
117 
118 	ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
119 					      invalid_flag));
120 	ASSERT_EQ(EINVAL, errno);
121 
122 	ASSERT_EQ(-1,
123 		  landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
124 					  invalid_flag));
125 	ASSERT_EQ(EINVAL, errno);
126 
127 	/* Checks too big ruleset_attr size. */
128 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0));
129 	ASSERT_EQ(E2BIG, errno);
130 
131 	/* Checks too small ruleset_attr size. */
132 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0));
133 	ASSERT_EQ(EINVAL, errno);
134 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0));
135 	ASSERT_EQ(EINVAL, errno);
136 
137 	/* Checks valid call. */
138 	ruleset_fd =
139 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
140 	ASSERT_LE(0, ruleset_fd);
141 	ASSERT_EQ(0, close(ruleset_fd));
142 }
143 
144 /* Tests ordering of syscall argument checks. */
TEST(add_rule_checks_ordering)145 TEST(add_rule_checks_ordering)
146 {
147 	const struct landlock_ruleset_attr ruleset_attr = {
148 		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
149 	};
150 	struct landlock_path_beneath_attr path_beneath_attr = {
151 		.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
152 		.parent_fd = -1,
153 	};
154 	const int ruleset_fd =
155 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
156 
157 	ASSERT_LE(0, ruleset_fd);
158 
159 	/* Checks invalid flags. */
160 	ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
161 	ASSERT_EQ(EINVAL, errno);
162 
163 	/* Checks invalid ruleset FD. */
164 	ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0));
165 	ASSERT_EQ(EBADF, errno);
166 
167 	/* Checks invalid rule type. */
168 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0));
169 	ASSERT_EQ(EINVAL, errno);
170 
171 	/* Checks invalid rule attr. */
172 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
173 					NULL, 0));
174 	ASSERT_EQ(EFAULT, errno);
175 
176 	/* Checks invalid path_beneath.parent_fd. */
177 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
178 					&path_beneath_attr, 0));
179 	ASSERT_EQ(EBADF, errno);
180 
181 	/* Checks valid call. */
182 	path_beneath_attr.parent_fd =
183 		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
184 	ASSERT_LE(0, path_beneath_attr.parent_fd);
185 	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
186 				       &path_beneath_attr, 0));
187 	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
188 	ASSERT_EQ(0, close(ruleset_fd));
189 }
190 
191 /* Tests ordering of syscall argument and permission checks. */
TEST(restrict_self_checks_ordering)192 TEST(restrict_self_checks_ordering)
193 {
194 	const struct landlock_ruleset_attr ruleset_attr = {
195 		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
196 	};
197 	struct landlock_path_beneath_attr path_beneath_attr = {
198 		.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
199 		.parent_fd = -1,
200 	};
201 	const int ruleset_fd =
202 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
203 
204 	ASSERT_LE(0, ruleset_fd);
205 	path_beneath_attr.parent_fd =
206 		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
207 	ASSERT_LE(0, path_beneath_attr.parent_fd);
208 	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
209 				       &path_beneath_attr, 0));
210 	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
211 
212 	/* Checks unprivileged enforcement without no_new_privs. */
213 	drop_caps(_metadata);
214 	ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
215 	ASSERT_EQ(EPERM, errno);
216 	ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
217 	ASSERT_EQ(EPERM, errno);
218 	ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
219 	ASSERT_EQ(EPERM, errno);
220 
221 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
222 
223 	/* Checks invalid flags. */
224 	ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
225 	ASSERT_EQ(EINVAL, errno);
226 
227 	/* Checks invalid ruleset FD. */
228 	ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
229 	ASSERT_EQ(EBADF, errno);
230 
231 	/* Checks valid call. */
232 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
233 	ASSERT_EQ(0, close(ruleset_fd));
234 }
235 
TEST(ruleset_fd_io)236 TEST(ruleset_fd_io)
237 {
238 	struct landlock_ruleset_attr ruleset_attr = {
239 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
240 	};
241 	int ruleset_fd;
242 	char buf;
243 
244 	drop_caps(_metadata);
245 	ruleset_fd =
246 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
247 	ASSERT_LE(0, ruleset_fd);
248 
249 	ASSERT_EQ(-1, write(ruleset_fd, ".", 1));
250 	ASSERT_EQ(EINVAL, errno);
251 	ASSERT_EQ(-1, read(ruleset_fd, &buf, 1));
252 	ASSERT_EQ(EINVAL, errno);
253 
254 	ASSERT_EQ(0, close(ruleset_fd));
255 }
256 
257 /* Tests enforcement of a ruleset FD transferred through a UNIX socket. */
TEST(ruleset_fd_transfer)258 TEST(ruleset_fd_transfer)
259 {
260 	struct landlock_ruleset_attr ruleset_attr = {
261 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
262 	};
263 	struct landlock_path_beneath_attr path_beneath_attr = {
264 		.allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
265 	};
266 	int ruleset_fd_tx, dir_fd;
267 	int socket_fds[2];
268 	pid_t child;
269 	int status;
270 
271 	drop_caps(_metadata);
272 
273 	/* Creates a test ruleset with a simple rule. */
274 	ruleset_fd_tx =
275 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
276 	ASSERT_LE(0, ruleset_fd_tx);
277 	path_beneath_attr.parent_fd =
278 		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
279 	ASSERT_LE(0, path_beneath_attr.parent_fd);
280 	ASSERT_EQ(0,
281 		  landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH,
282 				    &path_beneath_attr, 0));
283 	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
284 
285 	/* Sends the ruleset FD over a socketpair and then close it. */
286 	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
287 				socket_fds));
288 	ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx));
289 	ASSERT_EQ(0, close(socket_fds[0]));
290 	ASSERT_EQ(0, close(ruleset_fd_tx));
291 
292 	child = fork();
293 	ASSERT_LE(0, child);
294 	if (child == 0) {
295 		const int ruleset_fd_rx = recv_fd(socket_fds[1]);
296 
297 		ASSERT_LE(0, ruleset_fd_rx);
298 		ASSERT_EQ(0, close(socket_fds[1]));
299 
300 		/* Enforces the received ruleset on the child. */
301 		ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
302 		ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0));
303 		ASSERT_EQ(0, close(ruleset_fd_rx));
304 
305 		/* Checks that the ruleset enforcement. */
306 		ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
307 		ASSERT_EQ(EACCES, errno);
308 		dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
309 		ASSERT_LE(0, dir_fd);
310 		ASSERT_EQ(0, close(dir_fd));
311 		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
312 		return;
313 	}
314 
315 	ASSERT_EQ(0, close(socket_fds[1]));
316 
317 	/* Checks that the parent is unrestricted. */
318 	dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
319 	ASSERT_LE(0, dir_fd);
320 	ASSERT_EQ(0, close(dir_fd));
321 	dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
322 	ASSERT_LE(0, dir_fd);
323 	ASSERT_EQ(0, close(dir_fd));
324 
325 	ASSERT_EQ(child, waitpid(child, &status, 0));
326 	ASSERT_EQ(1, WIFEXITED(status));
327 	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
328 }
329 
TEST(cred_transfer)330 TEST(cred_transfer)
331 {
332 	struct landlock_ruleset_attr ruleset_attr = {
333 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
334 	};
335 	int ruleset_fd, dir_fd;
336 	pid_t child;
337 	int status;
338 
339 	drop_caps(_metadata);
340 
341 	dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
342 	EXPECT_LE(0, dir_fd);
343 	EXPECT_EQ(0, close(dir_fd));
344 
345 	/* Denies opening directories. */
346 	ruleset_fd =
347 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
348 	ASSERT_LE(0, ruleset_fd);
349 	EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
350 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
351 	EXPECT_EQ(0, close(ruleset_fd));
352 
353 	/* Checks ruleset enforcement. */
354 	EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
355 	EXPECT_EQ(EACCES, errno);
356 
357 	/* Needed for KEYCTL_SESSION_TO_PARENT permission checks */
358 	EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL, 0,
359 			      0, 0))
360 	{
361 		TH_LOG("Failed to join session keyring: %s", strerror(errno));
362 	}
363 
364 	child = fork();
365 	ASSERT_LE(0, child);
366 	if (child == 0) {
367 		/* Checks ruleset enforcement. */
368 		EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
369 		EXPECT_EQ(EACCES, errno);
370 
371 		/*
372 		 * KEYCTL_SESSION_TO_PARENT is a no-op unless we have a
373 		 * different session keyring in the child, so make that happen.
374 		 */
375 		EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING,
376 				      NULL, 0, 0, 0));
377 
378 		/*
379 		 * KEYCTL_SESSION_TO_PARENT installs credentials on the parent
380 		 * that never go through the cred_prepare hook, this path uses
381 		 * cred_transfer instead.
382 		 */
383 		EXPECT_EQ(0, syscall(__NR_keyctl, KEYCTL_SESSION_TO_PARENT, 0,
384 				     0, 0, 0));
385 
386 		/* Re-checks ruleset enforcement. */
387 		EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
388 		EXPECT_EQ(EACCES, errno);
389 
390 		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
391 		return;
392 	}
393 
394 	EXPECT_EQ(child, waitpid(child, &status, 0));
395 	EXPECT_EQ(1, WIFEXITED(status));
396 	EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
397 
398 	/* Re-checks ruleset enforcement. */
399 	EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
400 	EXPECT_EQ(EACCES, errno);
401 }
402 
403 TEST_HARNESS_MAIN
404