xref: /linux/tools/testing/selftests/landlock/fs_test.c (revision ae388edd4a8f0226f3ef7b102c34f78220756c3d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Landlock tests - Filesystem
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6  * Copyright © 2020 ANSSI
7  * Copyright © 2020-2022 Microsoft Corporation
8  */
9 
10 #define _GNU_SOURCE
11 #include <asm/termbits.h>
12 #include <fcntl.h>
13 #include <libgen.h>
14 #include <linux/fiemap.h>
15 #include <linux/landlock.h>
16 #include <linux/magic.h>
17 #include <sched.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/capability.h>
22 #include <sys/ioctl.h>
23 #include <sys/mount.h>
24 #include <sys/prctl.h>
25 #include <sys/sendfile.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/sysmacros.h>
29 #include <sys/un.h>
30 #include <sys/vfs.h>
31 #include <unistd.h>
32 
33 /*
34  * Intentionally included last to work around header conflict.
35  * See https://sourceware.org/glibc/wiki/Synchronizing_Headers.
36  */
37 #include <linux/fs.h>
38 #include <linux/mount.h>
39 
40 /* Defines AT_EXECVE_CHECK without type conflicts. */
41 #define _ASM_GENERIC_FCNTL_H
42 #include <linux/fcntl.h>
43 
44 #include "audit.h"
45 #include "common.h"
46 
47 #ifndef renameat2
renameat2(int olddirfd,const char * oldpath,int newdirfd,const char * newpath,unsigned int flags)48 int renameat2(int olddirfd, const char *oldpath, int newdirfd,
49 	      const char *newpath, unsigned int flags)
50 {
51 	return syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath,
52 		       flags);
53 }
54 #endif
55 
56 #ifndef open_tree
open_tree(int dfd,const char * filename,unsigned int flags)57 int open_tree(int dfd, const char *filename, unsigned int flags)
58 {
59 	return syscall(__NR_open_tree, dfd, filename, flags);
60 }
61 #endif
62 
sys_execveat(int dirfd,const char * pathname,char * const argv[],char * const envp[],int flags)63 static int sys_execveat(int dirfd, const char *pathname, char *const argv[],
64 			char *const envp[], int flags)
65 {
66 	return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
67 }
68 
69 #ifndef RENAME_EXCHANGE
70 #define RENAME_EXCHANGE (1 << 1)
71 #endif
72 
73 static const char bin_true[] = "./true";
74 
75 /* Paths (sibling number and depth) */
76 static const char dir_s1d1[] = TMP_DIR "/s1d1";
77 static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
78 static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
79 static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
80 static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
81 static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
82 static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
83 static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
84 static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
85 
86 static const char dir_s2d1[] = TMP_DIR "/s2d1";
87 static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
88 static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
89 static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
90 static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
91 static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
92 static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
93 
94 static const char dir_s3d1[] = TMP_DIR "/s3d1";
95 static const char file1_s3d1[] = TMP_DIR "/s3d1/f1";
96 /* dir_s3d2 is a mount point. */
97 static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
98 static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
99 static const char file1_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3/f1";
100 static const char dir_s3d4[] = TMP_DIR "/s3d1/s3d2/s3d4";
101 static const char file1_s3d4[] = TMP_DIR "/s3d1/s3d2/s3d4/f1";
102 
103 /*
104  * layout1 hierarchy:
105  *
106  * tmp
107  * ├── s1d1
108  * │   ├── f1
109  * │   ├── f2
110  * │   └── s1d2
111  * │       ├── f1
112  * │       ├── f2
113  * │       └── s1d3
114  * │           ├── f1
115  * │           └── f2
116  * ├── s2d1
117  * │   ├── f1
118  * │   └── s2d2
119  * │       ├── f1
120  * │       └── s2d3
121  * │           ├── f1
122  * │           └── f2
123  * └── s3d1
124  *     ├── f1
125  *     └── s3d2 [mount point]
126  *         ├── s3d3
127  *         │   └── f1
128  *         └── s3d4
129  *             └── f1
130  */
131 
fgrep(FILE * const inf,const char * const str)132 static bool fgrep(FILE *const inf, const char *const str)
133 {
134 	char line[32];
135 	const int slen = strlen(str);
136 
137 	while (!feof(inf)) {
138 		if (!fgets(line, sizeof(line), inf))
139 			break;
140 		if (strncmp(line, str, slen))
141 			continue;
142 
143 		return true;
144 	}
145 
146 	return false;
147 }
148 
supports_filesystem(const char * const filesystem)149 static bool supports_filesystem(const char *const filesystem)
150 {
151 	char str[32];
152 	int len;
153 	bool res = true;
154 	FILE *const inf = fopen("/proc/filesystems", "r");
155 
156 	/*
157 	 * Consider that the filesystem is supported if we cannot get the
158 	 * supported ones.
159 	 */
160 	if (!inf)
161 		return true;
162 
163 	/* filesystem can be null for bind mounts. */
164 	if (!filesystem)
165 		goto out;
166 
167 	len = snprintf(str, sizeof(str), "nodev\t%s\n", filesystem);
168 	if (len >= sizeof(str))
169 		/* Ignores too-long filesystem names. */
170 		goto out;
171 
172 	res = fgrep(inf, str);
173 
174 out:
175 	fclose(inf);
176 	return res;
177 }
178 
cwd_matches_fs(unsigned int fs_magic)179 static bool cwd_matches_fs(unsigned int fs_magic)
180 {
181 	struct statfs statfs_buf;
182 
183 	if (!fs_magic)
184 		return true;
185 
186 	if (statfs(".", &statfs_buf))
187 		return true;
188 
189 	return statfs_buf.f_type == fs_magic;
190 }
191 
mkdir_parents(struct __test_metadata * const _metadata,const char * const path)192 static void mkdir_parents(struct __test_metadata *const _metadata,
193 			  const char *const path)
194 {
195 	char *walker;
196 	const char *parent;
197 	int i, err;
198 
199 	ASSERT_NE(path[0], '\0');
200 	walker = strdup(path);
201 	ASSERT_NE(NULL, walker);
202 	parent = walker;
203 	for (i = 1; walker[i]; i++) {
204 		if (walker[i] != '/')
205 			continue;
206 		walker[i] = '\0';
207 		err = mkdir(parent, 0700);
208 		ASSERT_FALSE(err && errno != EEXIST)
209 		{
210 			TH_LOG("Failed to create directory \"%s\": %s", parent,
211 			       strerror(errno));
212 		}
213 		walker[i] = '/';
214 	}
215 	free(walker);
216 }
217 
create_directory(struct __test_metadata * const _metadata,const char * const path)218 static void create_directory(struct __test_metadata *const _metadata,
219 			     const char *const path)
220 {
221 	mkdir_parents(_metadata, path);
222 	ASSERT_EQ(0, mkdir(path, 0700))
223 	{
224 		TH_LOG("Failed to create directory \"%s\": %s", path,
225 		       strerror(errno));
226 	}
227 }
228 
create_file(struct __test_metadata * const _metadata,const char * const path)229 static void create_file(struct __test_metadata *const _metadata,
230 			const char *const path)
231 {
232 	mkdir_parents(_metadata, path);
233 	ASSERT_EQ(0, mknod(path, S_IFREG | 0700, 0))
234 	{
235 		TH_LOG("Failed to create file \"%s\": %s", path,
236 		       strerror(errno));
237 	}
238 }
239 
remove_path(const char * const path)240 static int remove_path(const char *const path)
241 {
242 	char *walker;
243 	int i, ret, err = 0;
244 
245 	walker = strdup(path);
246 	if (!walker) {
247 		err = ENOMEM;
248 		goto out;
249 	}
250 	if (unlink(path) && rmdir(path)) {
251 		if (errno != ENOENT && errno != ENOTDIR)
252 			err = errno;
253 		goto out;
254 	}
255 	for (i = strlen(walker); i > 0; i--) {
256 		if (walker[i] != '/')
257 			continue;
258 		walker[i] = '\0';
259 		ret = rmdir(walker);
260 		if (ret) {
261 			if (errno != ENOTEMPTY && errno != EBUSY)
262 				err = errno;
263 			goto out;
264 		}
265 		if (strcmp(walker, TMP_DIR) == 0)
266 			goto out;
267 	}
268 
269 out:
270 	free(walker);
271 	return err;
272 }
273 
274 struct mnt_opt {
275 	const char *const source;
276 	const char *const type;
277 	const unsigned long flags;
278 	const char *const data;
279 };
280 
281 #define MNT_TMP_DATA "size=4m,mode=700"
282 
283 static const struct mnt_opt mnt_tmp = {
284 	.type = "tmpfs",
285 	.data = MNT_TMP_DATA,
286 };
287 
mount_opt(const struct mnt_opt * const mnt,const char * const target)288 static int mount_opt(const struct mnt_opt *const mnt, const char *const target)
289 {
290 	return mount(mnt->source ?: mnt->type, target, mnt->type, mnt->flags,
291 		     mnt->data);
292 }
293 
prepare_layout_opt(struct __test_metadata * const _metadata,const struct mnt_opt * const mnt)294 static void prepare_layout_opt(struct __test_metadata *const _metadata,
295 			       const struct mnt_opt *const mnt)
296 {
297 	disable_caps(_metadata);
298 	umask(0077);
299 	create_directory(_metadata, TMP_DIR);
300 
301 	/*
302 	 * Do not pollute the rest of the system: creates a private mount point
303 	 * for tests relying on pivot_root(2) and move_mount(2).
304 	 */
305 	set_cap(_metadata, CAP_SYS_ADMIN);
306 	ASSERT_EQ(0, unshare(CLONE_NEWNS | CLONE_NEWCGROUP));
307 	ASSERT_EQ(0, mount_opt(mnt, TMP_DIR))
308 	{
309 		TH_LOG("Failed to mount the %s filesystem: %s", mnt->type,
310 		       strerror(errno));
311 		/*
312 		 * FIXTURE_TEARDOWN() is not called when FIXTURE_SETUP()
313 		 * failed, so we need to explicitly do a minimal cleanup to
314 		 * avoid cascading errors with other tests that don't depend on
315 		 * the same filesystem.
316 		 */
317 		remove_path(TMP_DIR);
318 	}
319 	ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL));
320 	clear_cap(_metadata, CAP_SYS_ADMIN);
321 }
322 
prepare_layout(struct __test_metadata * const _metadata)323 static void prepare_layout(struct __test_metadata *const _metadata)
324 {
325 	prepare_layout_opt(_metadata, &mnt_tmp);
326 }
327 
cleanup_layout(struct __test_metadata * const _metadata)328 static void cleanup_layout(struct __test_metadata *const _metadata)
329 {
330 	set_cap(_metadata, CAP_SYS_ADMIN);
331 	if (umount(TMP_DIR)) {
332 		/*
333 		 * According to the test environment, the mount point of the
334 		 * current directory may be shared or not, which changes the
335 		 * visibility of the nested TMP_DIR mount point for the test's
336 		 * parent process doing this cleanup.
337 		 */
338 		ASSERT_EQ(EINVAL, errno);
339 	}
340 	clear_cap(_metadata, CAP_SYS_ADMIN);
341 	EXPECT_EQ(0, remove_path(TMP_DIR));
342 }
343 
344 /* clang-format off */
FIXTURE(layout0)345 FIXTURE(layout0) {};
346 /* clang-format on */
347 
FIXTURE_SETUP(layout0)348 FIXTURE_SETUP(layout0)
349 {
350 	prepare_layout(_metadata);
351 }
352 
FIXTURE_TEARDOWN_PARENT(layout0)353 FIXTURE_TEARDOWN_PARENT(layout0)
354 {
355 	cleanup_layout(_metadata);
356 }
357 
create_layout1(struct __test_metadata * const _metadata)358 static void create_layout1(struct __test_metadata *const _metadata)
359 {
360 	create_file(_metadata, file1_s1d1);
361 	create_file(_metadata, file1_s1d2);
362 	create_file(_metadata, file1_s1d3);
363 	create_file(_metadata, file2_s1d1);
364 	create_file(_metadata, file2_s1d2);
365 	create_file(_metadata, file2_s1d3);
366 
367 	create_file(_metadata, file1_s2d1);
368 	create_file(_metadata, file1_s2d2);
369 	create_file(_metadata, file1_s2d3);
370 	create_file(_metadata, file2_s2d3);
371 
372 	create_file(_metadata, file1_s3d1);
373 	create_directory(_metadata, dir_s3d2);
374 	set_cap(_metadata, CAP_SYS_ADMIN);
375 	ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s3d2));
376 	clear_cap(_metadata, CAP_SYS_ADMIN);
377 
378 	create_file(_metadata, file1_s3d3);
379 	create_file(_metadata, file1_s3d4);
380 }
381 
remove_layout1(struct __test_metadata * const _metadata)382 static void remove_layout1(struct __test_metadata *const _metadata)
383 {
384 	EXPECT_EQ(0, remove_path(file2_s1d3));
385 	EXPECT_EQ(0, remove_path(file2_s1d2));
386 	EXPECT_EQ(0, remove_path(file2_s1d1));
387 	EXPECT_EQ(0, remove_path(file1_s1d3));
388 	EXPECT_EQ(0, remove_path(file1_s1d2));
389 	EXPECT_EQ(0, remove_path(file1_s1d1));
390 	EXPECT_EQ(0, remove_path(dir_s1d3));
391 
392 	EXPECT_EQ(0, remove_path(file2_s2d3));
393 	EXPECT_EQ(0, remove_path(file1_s2d3));
394 	EXPECT_EQ(0, remove_path(file1_s2d2));
395 	EXPECT_EQ(0, remove_path(file1_s2d1));
396 	EXPECT_EQ(0, remove_path(dir_s2d2));
397 
398 	EXPECT_EQ(0, remove_path(file1_s3d1));
399 	EXPECT_EQ(0, remove_path(file1_s3d3));
400 	EXPECT_EQ(0, remove_path(file1_s3d4));
401 	set_cap(_metadata, CAP_SYS_ADMIN);
402 	umount(dir_s3d2);
403 	clear_cap(_metadata, CAP_SYS_ADMIN);
404 	EXPECT_EQ(0, remove_path(dir_s3d2));
405 }
406 
407 /* clang-format off */
FIXTURE(layout1)408 FIXTURE(layout1) {};
409 /* clang-format on */
410 
FIXTURE_SETUP(layout1)411 FIXTURE_SETUP(layout1)
412 {
413 	prepare_layout(_metadata);
414 
415 	create_layout1(_metadata);
416 }
417 
FIXTURE_TEARDOWN_PARENT(layout1)418 FIXTURE_TEARDOWN_PARENT(layout1)
419 {
420 	remove_layout1(_metadata);
421 
422 	cleanup_layout(_metadata);
423 }
424 
425 /*
426  * This helper enables to use the ASSERT_* macros and print the line number
427  * pointing to the test caller.
428  */
test_open_rel(const int dirfd,const char * const path,const int flags)429 static int test_open_rel(const int dirfd, const char *const path,
430 			 const int flags)
431 {
432 	int fd;
433 
434 	/* Works with file and directories. */
435 	fd = openat(dirfd, path, flags | O_CLOEXEC);
436 	if (fd < 0)
437 		return errno;
438 	/*
439 	 * Mixing error codes from close(2) and open(2) should not lead to any
440 	 * (access type) confusion for this test.
441 	 */
442 	if (close(fd) != 0)
443 		return errno;
444 	return 0;
445 }
446 
test_open(const char * const path,const int flags)447 static int test_open(const char *const path, const int flags)
448 {
449 	return test_open_rel(AT_FDCWD, path, flags);
450 }
451 
TEST_F_FORK(layout1,no_restriction)452 TEST_F_FORK(layout1, no_restriction)
453 {
454 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
455 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
456 	ASSERT_EQ(0, test_open(file2_s1d1, O_RDONLY));
457 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
458 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
459 	ASSERT_EQ(0, test_open(file2_s1d2, O_RDONLY));
460 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
461 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
462 
463 	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
464 	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
465 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
466 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
467 	ASSERT_EQ(0, test_open(dir_s2d3, O_RDONLY));
468 	ASSERT_EQ(0, test_open(file1_s2d3, O_RDONLY));
469 
470 	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
471 	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
472 	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
473 }
474 
TEST_F_FORK(layout1,inval)475 TEST_F_FORK(layout1, inval)
476 {
477 	struct landlock_path_beneath_attr path_beneath = {
478 		.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
479 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
480 		.parent_fd = -1,
481 	};
482 	struct landlock_ruleset_attr ruleset_attr = {
483 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
484 				     LANDLOCK_ACCESS_FS_WRITE_FILE,
485 	};
486 	int ruleset_fd;
487 
488 	path_beneath.parent_fd =
489 		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
490 	ASSERT_LE(0, path_beneath.parent_fd);
491 
492 	ruleset_fd = open(dir_s1d1, O_PATH | O_DIRECTORY | O_CLOEXEC);
493 	ASSERT_LE(0, ruleset_fd);
494 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
495 					&path_beneath, 0));
496 	/* Returns EBADF because ruleset_fd is not a landlock-ruleset FD. */
497 	ASSERT_EQ(EBADF, errno);
498 	ASSERT_EQ(0, close(ruleset_fd));
499 
500 	ruleset_fd = open(dir_s1d1, O_DIRECTORY | O_CLOEXEC);
501 	ASSERT_LE(0, ruleset_fd);
502 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
503 					&path_beneath, 0));
504 	/* Returns EBADFD because ruleset_fd is not a valid ruleset. */
505 	ASSERT_EQ(EBADFD, errno);
506 	ASSERT_EQ(0, close(ruleset_fd));
507 
508 	/* Gets a real ruleset. */
509 	ruleset_fd =
510 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
511 	ASSERT_LE(0, ruleset_fd);
512 	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
513 				       &path_beneath, 0));
514 	ASSERT_EQ(0, close(path_beneath.parent_fd));
515 
516 	/* Tests without O_PATH. */
517 	path_beneath.parent_fd = open(dir_s1d2, O_DIRECTORY | O_CLOEXEC);
518 	ASSERT_LE(0, path_beneath.parent_fd);
519 	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
520 				       &path_beneath, 0));
521 	ASSERT_EQ(0, close(path_beneath.parent_fd));
522 
523 	/* Tests with a ruleset FD. */
524 	path_beneath.parent_fd = ruleset_fd;
525 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
526 					&path_beneath, 0));
527 	ASSERT_EQ(EBADFD, errno);
528 
529 	/* Checks unhandled allowed_access. */
530 	path_beneath.parent_fd =
531 		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
532 	ASSERT_LE(0, path_beneath.parent_fd);
533 
534 	/* Test with legitimate values. */
535 	path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_EXECUTE;
536 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
537 					&path_beneath, 0));
538 	ASSERT_EQ(EINVAL, errno);
539 	path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE;
540 
541 	/* Tests with denied-by-default access right. */
542 	path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_REFER;
543 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
544 					&path_beneath, 0));
545 	ASSERT_EQ(EINVAL, errno);
546 	path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_REFER;
547 
548 	/* Test with unknown (64-bits) value. */
549 	path_beneath.allowed_access |= (1ULL << 60);
550 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
551 					&path_beneath, 0));
552 	ASSERT_EQ(EINVAL, errno);
553 	path_beneath.allowed_access &= ~(1ULL << 60);
554 
555 	/* Test with no access. */
556 	path_beneath.allowed_access = 0;
557 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
558 					&path_beneath, 0));
559 	ASSERT_EQ(ENOMSG, errno);
560 	path_beneath.allowed_access &= ~(1ULL << 60);
561 
562 	ASSERT_EQ(0, close(path_beneath.parent_fd));
563 
564 	/* Enforces the ruleset. */
565 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
566 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
567 
568 	ASSERT_EQ(0, close(ruleset_fd));
569 }
570 
571 /* clang-format off */
572 
573 #define ACCESS_FILE ( \
574 	LANDLOCK_ACCESS_FS_EXECUTE | \
575 	LANDLOCK_ACCESS_FS_WRITE_FILE | \
576 	LANDLOCK_ACCESS_FS_READ_FILE | \
577 	LANDLOCK_ACCESS_FS_TRUNCATE | \
578 	LANDLOCK_ACCESS_FS_IOCTL_DEV)
579 
580 #define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
581 
582 #define ACCESS_ALL ( \
583 	ACCESS_FILE | \
584 	LANDLOCK_ACCESS_FS_READ_DIR | \
585 	LANDLOCK_ACCESS_FS_REMOVE_DIR | \
586 	LANDLOCK_ACCESS_FS_REMOVE_FILE | \
587 	LANDLOCK_ACCESS_FS_MAKE_CHAR | \
588 	LANDLOCK_ACCESS_FS_MAKE_DIR | \
589 	LANDLOCK_ACCESS_FS_MAKE_REG | \
590 	LANDLOCK_ACCESS_FS_MAKE_SOCK | \
591 	LANDLOCK_ACCESS_FS_MAKE_FIFO | \
592 	LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
593 	LANDLOCK_ACCESS_FS_MAKE_SYM | \
594 	LANDLOCK_ACCESS_FS_REFER)
595 
596 /* clang-format on */
597 
TEST_F_FORK(layout1,file_and_dir_access_rights)598 TEST_F_FORK(layout1, file_and_dir_access_rights)
599 {
600 	__u64 access;
601 	int err;
602 	struct landlock_path_beneath_attr path_beneath_file = {},
603 					  path_beneath_dir = {};
604 	struct landlock_ruleset_attr ruleset_attr = {
605 		.handled_access_fs = ACCESS_ALL,
606 	};
607 	const int ruleset_fd =
608 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
609 
610 	ASSERT_LE(0, ruleset_fd);
611 
612 	/* Tests access rights for files. */
613 	path_beneath_file.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC);
614 	ASSERT_LE(0, path_beneath_file.parent_fd);
615 
616 	/* Tests access rights for directories. */
617 	path_beneath_dir.parent_fd =
618 		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
619 	ASSERT_LE(0, path_beneath_dir.parent_fd);
620 
621 	for (access = 1; access <= ACCESS_LAST; access <<= 1) {
622 		path_beneath_dir.allowed_access = access;
623 		ASSERT_EQ(0, landlock_add_rule(ruleset_fd,
624 					       LANDLOCK_RULE_PATH_BENEATH,
625 					       &path_beneath_dir, 0));
626 
627 		path_beneath_file.allowed_access = access;
628 		err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
629 					&path_beneath_file, 0);
630 		if (access & ACCESS_FILE) {
631 			ASSERT_EQ(0, err);
632 		} else {
633 			ASSERT_EQ(-1, err);
634 			ASSERT_EQ(EINVAL, errno);
635 		}
636 	}
637 	ASSERT_EQ(0, close(path_beneath_file.parent_fd));
638 	ASSERT_EQ(0, close(path_beneath_dir.parent_fd));
639 	ASSERT_EQ(0, close(ruleset_fd));
640 }
641 
TEST_F_FORK(layout0,ruleset_with_unknown_access)642 TEST_F_FORK(layout0, ruleset_with_unknown_access)
643 {
644 	__u64 access_mask;
645 
646 	for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST;
647 	     access_mask >>= 1) {
648 		struct landlock_ruleset_attr ruleset_attr = {
649 			.handled_access_fs = access_mask,
650 		};
651 
652 		ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr,
653 						      sizeof(ruleset_attr), 0));
654 		ASSERT_EQ(EINVAL, errno);
655 	}
656 }
657 
TEST_F_FORK(layout0,rule_with_unknown_access)658 TEST_F_FORK(layout0, rule_with_unknown_access)
659 {
660 	__u64 access;
661 	struct landlock_path_beneath_attr path_beneath = {};
662 	const struct landlock_ruleset_attr ruleset_attr = {
663 		.handled_access_fs = ACCESS_ALL,
664 	};
665 	const int ruleset_fd =
666 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
667 
668 	ASSERT_LE(0, ruleset_fd);
669 
670 	path_beneath.parent_fd =
671 		open(TMP_DIR, O_PATH | O_DIRECTORY | O_CLOEXEC);
672 	ASSERT_LE(0, path_beneath.parent_fd);
673 
674 	for (access = 1ULL << 63; access != ACCESS_LAST; access >>= 1) {
675 		path_beneath.allowed_access = access;
676 		EXPECT_EQ(-1, landlock_add_rule(ruleset_fd,
677 						LANDLOCK_RULE_PATH_BENEATH,
678 						&path_beneath, 0));
679 		EXPECT_EQ(EINVAL, errno);
680 	}
681 	ASSERT_EQ(0, close(path_beneath.parent_fd));
682 	ASSERT_EQ(0, close(ruleset_fd));
683 }
684 
TEST_F_FORK(layout1,rule_with_unhandled_access)685 TEST_F_FORK(layout1, rule_with_unhandled_access)
686 {
687 	struct landlock_ruleset_attr ruleset_attr = {
688 		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
689 	};
690 	struct landlock_path_beneath_attr path_beneath = {};
691 	int ruleset_fd;
692 	__u64 access;
693 
694 	ruleset_fd =
695 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
696 	ASSERT_LE(0, ruleset_fd);
697 
698 	path_beneath.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC);
699 	ASSERT_LE(0, path_beneath.parent_fd);
700 
701 	for (access = 1; access > 0; access <<= 1) {
702 		int err;
703 
704 		path_beneath.allowed_access = access;
705 		err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
706 					&path_beneath, 0);
707 		if (access == ruleset_attr.handled_access_fs) {
708 			EXPECT_EQ(0, err);
709 		} else {
710 			EXPECT_EQ(-1, err);
711 			EXPECT_EQ(EINVAL, errno);
712 		}
713 	}
714 
715 	EXPECT_EQ(0, close(path_beneath.parent_fd));
716 	EXPECT_EQ(0, close(ruleset_fd));
717 }
718 
add_path_beneath(struct __test_metadata * const _metadata,const int ruleset_fd,const __u64 allowed_access,const char * const path)719 static void add_path_beneath(struct __test_metadata *const _metadata,
720 			     const int ruleset_fd, const __u64 allowed_access,
721 			     const char *const path)
722 {
723 	struct landlock_path_beneath_attr path_beneath = {
724 		.allowed_access = allowed_access,
725 	};
726 
727 	path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC);
728 	ASSERT_LE(0, path_beneath.parent_fd)
729 	{
730 		TH_LOG("Failed to open directory \"%s\": %s", path,
731 		       strerror(errno));
732 	}
733 	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
734 				       &path_beneath, 0))
735 	{
736 		TH_LOG("Failed to update the ruleset with \"%s\": %s", path,
737 		       strerror(errno));
738 	}
739 	ASSERT_EQ(0, close(path_beneath.parent_fd));
740 }
741 
742 struct rule {
743 	const char *path;
744 	__u64 access;
745 };
746 
747 /* clang-format off */
748 
749 #define ACCESS_RO ( \
750 	LANDLOCK_ACCESS_FS_READ_FILE | \
751 	LANDLOCK_ACCESS_FS_READ_DIR)
752 
753 #define ACCESS_RW ( \
754 	ACCESS_RO | \
755 	LANDLOCK_ACCESS_FS_WRITE_FILE)
756 
757 /* clang-format on */
758 
create_ruleset(struct __test_metadata * const _metadata,const __u64 handled_access_fs,const struct rule rules[])759 static int create_ruleset(struct __test_metadata *const _metadata,
760 			  const __u64 handled_access_fs,
761 			  const struct rule rules[])
762 {
763 	int ruleset_fd, i;
764 	struct landlock_ruleset_attr ruleset_attr = {
765 		.handled_access_fs = handled_access_fs,
766 	};
767 
768 	ASSERT_NE(NULL, rules)
769 	{
770 		TH_LOG("No rule list");
771 	}
772 	ASSERT_NE(NULL, rules[0].path)
773 	{
774 		TH_LOG("Empty rule list");
775 	}
776 
777 	ruleset_fd =
778 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
779 	ASSERT_LE(0, ruleset_fd)
780 	{
781 		TH_LOG("Failed to create a ruleset: %s", strerror(errno));
782 	}
783 
784 	for (i = 0; rules[i].path; i++) {
785 		if (!rules[i].access)
786 			continue;
787 
788 		add_path_beneath(_metadata, ruleset_fd, rules[i].access,
789 				 rules[i].path);
790 	}
791 	return ruleset_fd;
792 }
793 
TEST_F_FORK(layout0,proc_nsfs)794 TEST_F_FORK(layout0, proc_nsfs)
795 {
796 	const struct rule rules[] = {
797 		{
798 			.path = "/dev/null",
799 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
800 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
801 		},
802 		{},
803 	};
804 	struct landlock_path_beneath_attr path_beneath;
805 	const int ruleset_fd = create_ruleset(
806 		_metadata, rules[0].access | LANDLOCK_ACCESS_FS_READ_DIR,
807 		rules);
808 
809 	ASSERT_LE(0, ruleset_fd);
810 	ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
811 
812 	enforce_ruleset(_metadata, ruleset_fd);
813 
814 	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
815 	ASSERT_EQ(EACCES, test_open("/dev", O_RDONLY));
816 	ASSERT_EQ(0, test_open("/dev/null", O_RDONLY));
817 	ASSERT_EQ(EACCES, test_open("/dev/full", O_RDONLY));
818 
819 	ASSERT_EQ(EACCES, test_open("/proc", O_RDONLY));
820 	ASSERT_EQ(EACCES, test_open("/proc/self", O_RDONLY));
821 	ASSERT_EQ(EACCES, test_open("/proc/self/ns", O_RDONLY));
822 	/*
823 	 * Because nsfs is an internal filesystem, /proc/self/ns/mnt is a
824 	 * disconnected path.  Such path cannot be identified and must then be
825 	 * allowed.
826 	 */
827 	ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
828 
829 	/*
830 	 * Checks that it is not possible to add nsfs-like filesystem
831 	 * references to a ruleset.
832 	 */
833 	path_beneath.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
834 				      LANDLOCK_ACCESS_FS_WRITE_FILE,
835 	path_beneath.parent_fd = open("/proc/self/ns/mnt", O_PATH | O_CLOEXEC);
836 	ASSERT_LE(0, path_beneath.parent_fd);
837 	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
838 					&path_beneath, 0));
839 	ASSERT_EQ(EBADFD, errno);
840 	ASSERT_EQ(0, close(path_beneath.parent_fd));
841 }
842 
TEST_F_FORK(layout0,unpriv)843 TEST_F_FORK(layout0, unpriv)
844 {
845 	const struct rule rules[] = {
846 		{
847 			.path = TMP_DIR,
848 			.access = ACCESS_RO,
849 		},
850 		{},
851 	};
852 	int ruleset_fd;
853 
854 	drop_caps(_metadata);
855 
856 	ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
857 	ASSERT_LE(0, ruleset_fd);
858 	ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
859 	ASSERT_EQ(EPERM, errno);
860 
861 	/* enforce_ruleset() calls prctl(no_new_privs). */
862 	enforce_ruleset(_metadata, ruleset_fd);
863 	ASSERT_EQ(0, close(ruleset_fd));
864 }
865 
TEST_F_FORK(layout1,effective_access)866 TEST_F_FORK(layout1, effective_access)
867 {
868 	const struct rule rules[] = {
869 		{
870 			.path = dir_s1d2,
871 			.access = ACCESS_RO,
872 		},
873 		{
874 			.path = file1_s2d2,
875 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
876 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
877 		},
878 		{},
879 	};
880 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
881 	char buf;
882 	int reg_fd;
883 
884 	ASSERT_LE(0, ruleset_fd);
885 	enforce_ruleset(_metadata, ruleset_fd);
886 	ASSERT_EQ(0, close(ruleset_fd));
887 
888 	/* Tests on a directory (with or without O_PATH). */
889 	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
890 	ASSERT_EQ(0, test_open("/", O_RDONLY | O_PATH));
891 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
892 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_PATH));
893 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
894 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY | O_PATH));
895 
896 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
897 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
898 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
899 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
900 
901 	/* Tests on a file (with or without O_PATH). */
902 	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY));
903 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_PATH));
904 
905 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
906 
907 	/* Checks effective read and write actions. */
908 	reg_fd = open(file1_s2d2, O_RDWR | O_CLOEXEC);
909 	ASSERT_LE(0, reg_fd);
910 	ASSERT_EQ(1, write(reg_fd, ".", 1));
911 	ASSERT_LE(0, lseek(reg_fd, 0, SEEK_SET));
912 	ASSERT_EQ(1, read(reg_fd, &buf, 1));
913 	ASSERT_EQ('.', buf);
914 	ASSERT_EQ(0, close(reg_fd));
915 
916 	/* Just in case, double-checks effective actions. */
917 	reg_fd = open(file1_s2d2, O_RDONLY | O_CLOEXEC);
918 	ASSERT_LE(0, reg_fd);
919 	ASSERT_EQ(-1, write(reg_fd, &buf, 1));
920 	ASSERT_EQ(EBADF, errno);
921 	ASSERT_EQ(0, close(reg_fd));
922 }
923 
TEST_F_FORK(layout1,unhandled_access)924 TEST_F_FORK(layout1, unhandled_access)
925 {
926 	const struct rule rules[] = {
927 		{
928 			.path = dir_s1d2,
929 			.access = ACCESS_RO,
930 		},
931 		{},
932 	};
933 	/* Here, we only handle read accesses, not write accesses. */
934 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
935 
936 	ASSERT_LE(0, ruleset_fd);
937 	enforce_ruleset(_metadata, ruleset_fd);
938 	ASSERT_EQ(0, close(ruleset_fd));
939 
940 	/*
941 	 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE,
942 	 * opening for write-only should be allowed, but not read-write.
943 	 */
944 	ASSERT_EQ(0, test_open(file1_s1d1, O_WRONLY));
945 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
946 
947 	ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
948 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
949 }
950 
TEST_F_FORK(layout1,ruleset_overlap)951 TEST_F_FORK(layout1, ruleset_overlap)
952 {
953 	const struct rule rules[] = {
954 		/* These rules should be ORed among them. */
955 		{
956 			.path = dir_s1d2,
957 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
958 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
959 		},
960 		{
961 			.path = dir_s1d2,
962 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
963 				  LANDLOCK_ACCESS_FS_READ_DIR,
964 		},
965 		{},
966 	};
967 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
968 
969 	ASSERT_LE(0, ruleset_fd);
970 	enforce_ruleset(_metadata, ruleset_fd);
971 	ASSERT_EQ(0, close(ruleset_fd));
972 
973 	/* Checks s1d1 hierarchy. */
974 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
975 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
976 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
977 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
978 
979 	/* Checks s1d2 hierarchy. */
980 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
981 	ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
982 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
983 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
984 
985 	/* Checks s1d3 hierarchy. */
986 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
987 	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
988 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
989 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
990 }
991 
TEST_F_FORK(layout1,layer_rule_unions)992 TEST_F_FORK(layout1, layer_rule_unions)
993 {
994 	const struct rule layer1[] = {
995 		{
996 			.path = dir_s1d2,
997 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
998 		},
999 		/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
1000 		{
1001 			.path = dir_s1d3,
1002 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1003 		},
1004 		{},
1005 	};
1006 	const struct rule layer2[] = {
1007 		/* Doesn't change anything from layer1. */
1008 		{
1009 			.path = dir_s1d2,
1010 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
1011 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
1012 		},
1013 		{},
1014 	};
1015 	const struct rule layer3[] = {
1016 		/* Only allows write (but not read) to dir_s1d3. */
1017 		{
1018 			.path = dir_s1d2,
1019 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1020 		},
1021 		{},
1022 	};
1023 	int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1);
1024 
1025 	ASSERT_LE(0, ruleset_fd);
1026 	enforce_ruleset(_metadata, ruleset_fd);
1027 	ASSERT_EQ(0, close(ruleset_fd));
1028 
1029 	/* Checks s1d1 hierarchy with layer1. */
1030 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1031 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1032 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
1033 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1034 
1035 	/* Checks s1d2 hierarchy with layer1. */
1036 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
1037 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1038 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1039 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1040 
1041 	/* Checks s1d3 hierarchy with layer1. */
1042 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1043 	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
1044 	/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
1045 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1046 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1047 
1048 	/* Doesn't change anything from layer1. */
1049 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2);
1050 	ASSERT_LE(0, ruleset_fd);
1051 	enforce_ruleset(_metadata, ruleset_fd);
1052 	ASSERT_EQ(0, close(ruleset_fd));
1053 
1054 	/* Checks s1d1 hierarchy with layer2. */
1055 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1056 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1057 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
1058 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1059 
1060 	/* Checks s1d2 hierarchy with layer2. */
1061 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
1062 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1063 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1064 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1065 
1066 	/* Checks s1d3 hierarchy with layer2. */
1067 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1068 	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
1069 	/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
1070 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1071 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1072 
1073 	/* Only allows write (but not read) to dir_s1d3. */
1074 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3);
1075 	ASSERT_LE(0, ruleset_fd);
1076 	enforce_ruleset(_metadata, ruleset_fd);
1077 	ASSERT_EQ(0, close(ruleset_fd));
1078 
1079 	/* Checks s1d1 hierarchy with layer3. */
1080 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1081 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1082 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
1083 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1084 
1085 	/* Checks s1d2 hierarchy with layer3. */
1086 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
1087 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1088 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1089 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1090 
1091 	/* Checks s1d3 hierarchy with layer3. */
1092 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
1093 	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
1094 	/* dir_s1d3 should now deny READ_FILE and WRITE_FILE (O_RDWR). */
1095 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDWR));
1096 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1097 }
1098 
TEST_F_FORK(layout1,non_overlapping_accesses)1099 TEST_F_FORK(layout1, non_overlapping_accesses)
1100 {
1101 	const struct rule layer1[] = {
1102 		{
1103 			.path = dir_s1d2,
1104 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
1105 		},
1106 		{},
1107 	};
1108 	const struct rule layer2[] = {
1109 		{
1110 			.path = dir_s1d3,
1111 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
1112 		},
1113 		{},
1114 	};
1115 	int ruleset_fd;
1116 
1117 	ASSERT_EQ(0, unlink(file1_s1d1));
1118 	ASSERT_EQ(0, unlink(file1_s1d2));
1119 
1120 	ruleset_fd =
1121 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, layer1);
1122 	ASSERT_LE(0, ruleset_fd);
1123 	enforce_ruleset(_metadata, ruleset_fd);
1124 	ASSERT_EQ(0, close(ruleset_fd));
1125 
1126 	ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
1127 	ASSERT_EQ(EACCES, errno);
1128 	ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
1129 	ASSERT_EQ(0, unlink(file1_s1d2));
1130 
1131 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE,
1132 				    layer2);
1133 	ASSERT_LE(0, ruleset_fd);
1134 	enforce_ruleset(_metadata, ruleset_fd);
1135 	ASSERT_EQ(0, close(ruleset_fd));
1136 
1137 	/* Unchanged accesses for file creation. */
1138 	ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
1139 	ASSERT_EQ(EACCES, errno);
1140 	ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
1141 
1142 	/* Checks file removing. */
1143 	ASSERT_EQ(-1, unlink(file1_s1d2));
1144 	ASSERT_EQ(EACCES, errno);
1145 	ASSERT_EQ(0, unlink(file1_s1d3));
1146 }
1147 
TEST_F_FORK(layout1,interleaved_masked_accesses)1148 TEST_F_FORK(layout1, interleaved_masked_accesses)
1149 {
1150 	/*
1151 	 * Checks overly restrictive rules:
1152 	 * layer 1: allows R   s1d1/s1d2/s1d3/file1
1153 	 * layer 2: allows RW  s1d1/s1d2/s1d3
1154 	 *          allows  W  s1d1/s1d2
1155 	 *          denies R   s1d1/s1d2
1156 	 * layer 3: allows R   s1d1
1157 	 * layer 4: allows R   s1d1/s1d2
1158 	 *          denies  W  s1d1/s1d2
1159 	 * layer 5: allows R   s1d1/s1d2
1160 	 * layer 6: allows   X ----
1161 	 * layer 7: allows  W  s1d1/s1d2
1162 	 *          denies R   s1d1/s1d2
1163 	 */
1164 	const struct rule layer1_read[] = {
1165 		/* Allows read access to file1_s1d3 with the first layer. */
1166 		{
1167 			.path = file1_s1d3,
1168 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1169 		},
1170 		{},
1171 	};
1172 	/* First rule with write restrictions. */
1173 	const struct rule layer2_read_write[] = {
1174 		/* Start by granting read-write access via its parent directory... */
1175 		{
1176 			.path = dir_s1d3,
1177 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
1178 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
1179 		},
1180 		/* ...but also denies read access via its grandparent directory. */
1181 		{
1182 			.path = dir_s1d2,
1183 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1184 		},
1185 		{},
1186 	};
1187 	const struct rule layer3_read[] = {
1188 		/* Allows read access via its great-grandparent directory. */
1189 		{
1190 			.path = dir_s1d1,
1191 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1192 		},
1193 		{},
1194 	};
1195 	const struct rule layer4_read_write[] = {
1196 		/*
1197 		 * Try to confuse the deny access by denying write (but not
1198 		 * read) access via its grandparent directory.
1199 		 */
1200 		{
1201 			.path = dir_s1d2,
1202 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1203 		},
1204 		{},
1205 	};
1206 	const struct rule layer5_read[] = {
1207 		/*
1208 		 * Try to override layer2's deny read access by explicitly
1209 		 * allowing read access via file1_s1d3's grandparent.
1210 		 */
1211 		{
1212 			.path = dir_s1d2,
1213 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1214 		},
1215 		{},
1216 	};
1217 	const struct rule layer6_execute[] = {
1218 		/*
1219 		 * Restricts an unrelated file hierarchy with a new access
1220 		 * (non-overlapping) type.
1221 		 */
1222 		{
1223 			.path = dir_s2d1,
1224 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
1225 		},
1226 		{},
1227 	};
1228 	const struct rule layer7_read_write[] = {
1229 		/*
1230 		 * Finally, denies read access to file1_s1d3 via its
1231 		 * grandparent.
1232 		 */
1233 		{
1234 			.path = dir_s1d2,
1235 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1236 		},
1237 		{},
1238 	};
1239 	int ruleset_fd;
1240 
1241 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1242 				    layer1_read);
1243 	ASSERT_LE(0, ruleset_fd);
1244 	enforce_ruleset(_metadata, ruleset_fd);
1245 	ASSERT_EQ(0, close(ruleset_fd));
1246 
1247 	/* Checks that read access is granted for file1_s1d3 with layer 1. */
1248 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1249 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1250 	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1251 
1252 	ruleset_fd = create_ruleset(_metadata,
1253 				    LANDLOCK_ACCESS_FS_READ_FILE |
1254 					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1255 				    layer2_read_write);
1256 	ASSERT_LE(0, ruleset_fd);
1257 	enforce_ruleset(_metadata, ruleset_fd);
1258 	ASSERT_EQ(0, close(ruleset_fd));
1259 
1260 	/* Checks that previous access rights are unchanged with layer 2. */
1261 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1262 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1263 	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1264 
1265 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1266 				    layer3_read);
1267 	ASSERT_LE(0, ruleset_fd);
1268 	enforce_ruleset(_metadata, ruleset_fd);
1269 	ASSERT_EQ(0, close(ruleset_fd));
1270 
1271 	/* Checks that previous access rights are unchanged with layer 3. */
1272 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1273 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1274 	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1275 
1276 	/* This time, denies write access for the file hierarchy. */
1277 	ruleset_fd = create_ruleset(_metadata,
1278 				    LANDLOCK_ACCESS_FS_READ_FILE |
1279 					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1280 				    layer4_read_write);
1281 	ASSERT_LE(0, ruleset_fd);
1282 	enforce_ruleset(_metadata, ruleset_fd);
1283 	ASSERT_EQ(0, close(ruleset_fd));
1284 
1285 	/*
1286 	 * Checks that the only change with layer 4 is that write access is
1287 	 * denied.
1288 	 */
1289 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1290 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1291 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1292 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1293 
1294 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1295 				    layer5_read);
1296 	ASSERT_LE(0, ruleset_fd);
1297 	enforce_ruleset(_metadata, ruleset_fd);
1298 	ASSERT_EQ(0, close(ruleset_fd));
1299 
1300 	/* Checks that previous access rights are unchanged with layer 5. */
1301 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1302 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1303 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1304 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1305 
1306 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE,
1307 				    layer6_execute);
1308 	ASSERT_LE(0, ruleset_fd);
1309 	enforce_ruleset(_metadata, ruleset_fd);
1310 	ASSERT_EQ(0, close(ruleset_fd));
1311 
1312 	/* Checks that previous access rights are unchanged with layer 6. */
1313 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1314 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1315 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1316 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1317 
1318 	ruleset_fd = create_ruleset(_metadata,
1319 				    LANDLOCK_ACCESS_FS_READ_FILE |
1320 					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1321 				    layer7_read_write);
1322 	ASSERT_LE(0, ruleset_fd);
1323 	enforce_ruleset(_metadata, ruleset_fd);
1324 	ASSERT_EQ(0, close(ruleset_fd));
1325 
1326 	/* Checks read access is now denied with layer 7. */
1327 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
1328 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1329 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1330 	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1331 }
1332 
TEST_F_FORK(layout1,inherit_subset)1333 TEST_F_FORK(layout1, inherit_subset)
1334 {
1335 	const struct rule rules[] = {
1336 		{
1337 			.path = dir_s1d2,
1338 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
1339 				  LANDLOCK_ACCESS_FS_READ_DIR,
1340 		},
1341 		{},
1342 	};
1343 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1344 
1345 	ASSERT_LE(0, ruleset_fd);
1346 	enforce_ruleset(_metadata, ruleset_fd);
1347 
1348 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1349 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1350 
1351 	/* Write access is forbidden. */
1352 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1353 	/* Readdir access is allowed. */
1354 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1355 
1356 	/* Write access is forbidden. */
1357 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1358 	/* Readdir access is allowed. */
1359 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1360 
1361 	/*
1362 	 * Tests shared rule extension: the following rules should not grant
1363 	 * any new access, only remove some.  Once enforced, these rules are
1364 	 * ANDed with the previous ones.
1365 	 */
1366 	add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
1367 			 dir_s1d2);
1368 	/*
1369 	 * According to ruleset_fd, dir_s1d2 should now have the
1370 	 * LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE
1371 	 * access rights (even if this directory is opened a second time).
1372 	 * However, when enforcing this updated ruleset, the ruleset tied to
1373 	 * the current process (i.e. its domain) will still only have the
1374 	 * dir_s1d2 with LANDLOCK_ACCESS_FS_READ_FILE and
1375 	 * LANDLOCK_ACCESS_FS_READ_DIR accesses, but
1376 	 * LANDLOCK_ACCESS_FS_WRITE_FILE must not be allowed because it would
1377 	 * be a privilege escalation.
1378 	 */
1379 	enforce_ruleset(_metadata, ruleset_fd);
1380 
1381 	/* Same tests and results as above. */
1382 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1383 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1384 
1385 	/* It is still forbidden to write in file1_s1d2. */
1386 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1387 	/* Readdir access is still allowed. */
1388 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1389 
1390 	/* It is still forbidden to write in file1_s1d3. */
1391 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1392 	/* Readdir access is still allowed. */
1393 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1394 
1395 	/*
1396 	 * Try to get more privileges by adding new access rights to the parent
1397 	 * directory: dir_s1d1.
1398 	 */
1399 	add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1);
1400 	enforce_ruleset(_metadata, ruleset_fd);
1401 
1402 	/* Same tests and results as above. */
1403 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1404 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1405 
1406 	/* It is still forbidden to write in file1_s1d2. */
1407 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1408 	/* Readdir access is still allowed. */
1409 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1410 
1411 	/* It is still forbidden to write in file1_s1d3. */
1412 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1413 	/* Readdir access is still allowed. */
1414 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1415 
1416 	/*
1417 	 * Now, dir_s1d3 get a new rule tied to it, only allowing
1418 	 * LANDLOCK_ACCESS_FS_WRITE_FILE.  The (kernel internal) difference is
1419 	 * that there was no rule tied to it before.
1420 	 */
1421 	add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
1422 			 dir_s1d3);
1423 	enforce_ruleset(_metadata, ruleset_fd);
1424 	ASSERT_EQ(0, close(ruleset_fd));
1425 
1426 	/*
1427 	 * Same tests and results as above, except for open(dir_s1d3) which is
1428 	 * now denied because the new rule mask the rule previously inherited
1429 	 * from dir_s1d2.
1430 	 */
1431 
1432 	/* Same tests and results as above. */
1433 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1434 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1435 
1436 	/* It is still forbidden to write in file1_s1d2. */
1437 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1438 	/* Readdir access is still allowed. */
1439 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1440 
1441 	/* It is still forbidden to write in file1_s1d3. */
1442 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1443 	/*
1444 	 * Readdir of dir_s1d3 is still allowed because of the OR policy inside
1445 	 * the same layer.
1446 	 */
1447 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1448 }
1449 
TEST_F_FORK(layout1,inherit_superset)1450 TEST_F_FORK(layout1, inherit_superset)
1451 {
1452 	const struct rule rules[] = {
1453 		{
1454 			.path = dir_s1d3,
1455 			.access = ACCESS_RO,
1456 		},
1457 		{},
1458 	};
1459 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1460 
1461 	ASSERT_LE(0, ruleset_fd);
1462 	enforce_ruleset(_metadata, ruleset_fd);
1463 
1464 	/* Readdir access is denied for dir_s1d2. */
1465 	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1466 	/* Readdir access is allowed for dir_s1d3. */
1467 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1468 	/* File access is allowed for file1_s1d3. */
1469 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1470 
1471 	/* Now dir_s1d2, parent of dir_s1d3, gets a new rule tied to it. */
1472 	add_path_beneath(_metadata, ruleset_fd,
1473 			 LANDLOCK_ACCESS_FS_READ_FILE |
1474 				 LANDLOCK_ACCESS_FS_READ_DIR,
1475 			 dir_s1d2);
1476 	enforce_ruleset(_metadata, ruleset_fd);
1477 	ASSERT_EQ(0, close(ruleset_fd));
1478 
1479 	/* Readdir access is still denied for dir_s1d2. */
1480 	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1481 	/* Readdir access is still allowed for dir_s1d3. */
1482 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1483 	/* File access is still allowed for file1_s1d3. */
1484 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1485 }
1486 
TEST_F_FORK(layout0,max_layers)1487 TEST_F_FORK(layout0, max_layers)
1488 {
1489 	int i, err;
1490 	const struct rule rules[] = {
1491 		{
1492 			.path = TMP_DIR,
1493 			.access = ACCESS_RO,
1494 		},
1495 		{},
1496 	};
1497 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1498 
1499 	ASSERT_LE(0, ruleset_fd);
1500 	for (i = 0; i < 16; i++)
1501 		enforce_ruleset(_metadata, ruleset_fd);
1502 
1503 	for (i = 0; i < 2; i++) {
1504 		err = landlock_restrict_self(ruleset_fd, 0);
1505 		ASSERT_EQ(-1, err);
1506 		ASSERT_EQ(E2BIG, errno);
1507 	}
1508 	ASSERT_EQ(0, close(ruleset_fd));
1509 }
1510 
TEST_F_FORK(layout1,empty_or_same_ruleset)1511 TEST_F_FORK(layout1, empty_or_same_ruleset)
1512 {
1513 	struct landlock_ruleset_attr ruleset_attr = {};
1514 	int ruleset_fd;
1515 
1516 	/* Tests empty handled_access_fs. */
1517 	ruleset_fd =
1518 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1519 	ASSERT_LE(-1, ruleset_fd);
1520 	ASSERT_EQ(ENOMSG, errno);
1521 
1522 	/* Enforces policy which deny read access to all files. */
1523 	ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE;
1524 	ruleset_fd =
1525 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1526 	ASSERT_LE(0, ruleset_fd);
1527 	enforce_ruleset(_metadata, ruleset_fd);
1528 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1529 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1530 
1531 	/* Nests a policy which deny read access to all directories. */
1532 	ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR;
1533 	ruleset_fd =
1534 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1535 	ASSERT_LE(0, ruleset_fd);
1536 	enforce_ruleset(_metadata, ruleset_fd);
1537 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1538 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1539 
1540 	/* Enforces a second time with the same ruleset. */
1541 	enforce_ruleset(_metadata, ruleset_fd);
1542 	ASSERT_EQ(0, close(ruleset_fd));
1543 }
1544 
TEST_F_FORK(layout1,rule_on_mountpoint)1545 TEST_F_FORK(layout1, rule_on_mountpoint)
1546 {
1547 	const struct rule rules[] = {
1548 		{
1549 			.path = dir_s1d1,
1550 			.access = ACCESS_RO,
1551 		},
1552 		{
1553 			/* dir_s3d2 is a mount point. */
1554 			.path = dir_s3d2,
1555 			.access = ACCESS_RO,
1556 		},
1557 		{},
1558 	};
1559 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1560 
1561 	ASSERT_LE(0, ruleset_fd);
1562 	enforce_ruleset(_metadata, ruleset_fd);
1563 	ASSERT_EQ(0, close(ruleset_fd));
1564 
1565 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1566 
1567 	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1568 
1569 	ASSERT_EQ(EACCES, test_open(dir_s3d1, O_RDONLY));
1570 	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1571 	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1572 }
1573 
TEST_F_FORK(layout1,rule_over_mountpoint)1574 TEST_F_FORK(layout1, rule_over_mountpoint)
1575 {
1576 	const struct rule rules[] = {
1577 		{
1578 			.path = dir_s1d1,
1579 			.access = ACCESS_RO,
1580 		},
1581 		{
1582 			/* dir_s3d2 is a mount point. */
1583 			.path = dir_s3d1,
1584 			.access = ACCESS_RO,
1585 		},
1586 		{},
1587 	};
1588 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1589 
1590 	ASSERT_LE(0, ruleset_fd);
1591 	enforce_ruleset(_metadata, ruleset_fd);
1592 	ASSERT_EQ(0, close(ruleset_fd));
1593 
1594 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1595 
1596 	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1597 
1598 	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
1599 	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1600 	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1601 }
1602 
1603 /*
1604  * This test verifies that we can apply a landlock rule on the root directory
1605  * (which might require special handling).
1606  */
TEST_F_FORK(layout1,rule_over_root_allow_then_deny)1607 TEST_F_FORK(layout1, rule_over_root_allow_then_deny)
1608 {
1609 	struct rule rules[] = {
1610 		{
1611 			.path = "/",
1612 			.access = ACCESS_RO,
1613 		},
1614 		{},
1615 	};
1616 	int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1617 
1618 	ASSERT_LE(0, ruleset_fd);
1619 	enforce_ruleset(_metadata, ruleset_fd);
1620 	ASSERT_EQ(0, close(ruleset_fd));
1621 
1622 	/* Checks allowed access. */
1623 	ASSERT_EQ(0, test_open("/", O_RDONLY));
1624 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1625 
1626 	rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE;
1627 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1628 	ASSERT_LE(0, ruleset_fd);
1629 	enforce_ruleset(_metadata, ruleset_fd);
1630 	ASSERT_EQ(0, close(ruleset_fd));
1631 
1632 	/* Checks denied access (on a directory). */
1633 	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1634 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1635 }
1636 
TEST_F_FORK(layout1,rule_over_root_deny)1637 TEST_F_FORK(layout1, rule_over_root_deny)
1638 {
1639 	const struct rule rules[] = {
1640 		{
1641 			.path = "/",
1642 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1643 		},
1644 		{},
1645 	};
1646 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1647 
1648 	ASSERT_LE(0, ruleset_fd);
1649 	enforce_ruleset(_metadata, ruleset_fd);
1650 	ASSERT_EQ(0, close(ruleset_fd));
1651 
1652 	/* Checks denied access (on a directory). */
1653 	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1654 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1655 }
1656 
TEST_F_FORK(layout1,rule_inside_mount_ns)1657 TEST_F_FORK(layout1, rule_inside_mount_ns)
1658 {
1659 	const struct rule rules[] = {
1660 		{
1661 			.path = "s3d3",
1662 			.access = ACCESS_RO,
1663 		},
1664 		{},
1665 	};
1666 	int ruleset_fd;
1667 
1668 	set_cap(_metadata, CAP_SYS_ADMIN);
1669 	ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3))
1670 	{
1671 		TH_LOG("Failed to pivot root: %s", strerror(errno));
1672 	};
1673 	ASSERT_EQ(0, chdir("/"));
1674 	clear_cap(_metadata, CAP_SYS_ADMIN);
1675 
1676 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1677 	ASSERT_LE(0, ruleset_fd);
1678 	enforce_ruleset(_metadata, ruleset_fd);
1679 	ASSERT_EQ(0, close(ruleset_fd));
1680 
1681 	ASSERT_EQ(0, test_open("s3d3", O_RDONLY));
1682 	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1683 }
1684 
TEST_F_FORK(layout1,mount_and_pivot)1685 TEST_F_FORK(layout1, mount_and_pivot)
1686 {
1687 	const struct rule rules[] = {
1688 		{
1689 			.path = dir_s3d2,
1690 			.access = ACCESS_RO,
1691 		},
1692 		{},
1693 	};
1694 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1695 
1696 	ASSERT_LE(0, ruleset_fd);
1697 	enforce_ruleset(_metadata, ruleset_fd);
1698 	ASSERT_EQ(0, close(ruleset_fd));
1699 
1700 	set_cap(_metadata, CAP_SYS_ADMIN);
1701 	ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
1702 	ASSERT_EQ(EPERM, errno);
1703 	ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1704 	ASSERT_EQ(EPERM, errno);
1705 	clear_cap(_metadata, CAP_SYS_ADMIN);
1706 }
1707 
TEST_F_FORK(layout1,move_mount)1708 TEST_F_FORK(layout1, move_mount)
1709 {
1710 	const struct rule rules[] = {
1711 		{
1712 			.path = dir_s3d2,
1713 			.access = ACCESS_RO,
1714 		},
1715 		{},
1716 	};
1717 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1718 
1719 	ASSERT_LE(0, ruleset_fd);
1720 
1721 	set_cap(_metadata, CAP_SYS_ADMIN);
1722 	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1723 			     dir_s1d2, 0))
1724 	{
1725 		TH_LOG("Failed to move mount: %s", strerror(errno));
1726 	}
1727 
1728 	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD,
1729 			     dir_s3d2, 0));
1730 	clear_cap(_metadata, CAP_SYS_ADMIN);
1731 
1732 	enforce_ruleset(_metadata, ruleset_fd);
1733 	ASSERT_EQ(0, close(ruleset_fd));
1734 
1735 	set_cap(_metadata, CAP_SYS_ADMIN);
1736 	ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1737 			      dir_s1d2, 0));
1738 	ASSERT_EQ(EPERM, errno);
1739 	clear_cap(_metadata, CAP_SYS_ADMIN);
1740 }
1741 
TEST_F_FORK(layout1,topology_changes_with_net_only)1742 TEST_F_FORK(layout1, topology_changes_with_net_only)
1743 {
1744 	const struct landlock_ruleset_attr ruleset_net = {
1745 		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1746 				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
1747 	};
1748 	int ruleset_fd;
1749 
1750 	/* Add network restrictions. */
1751 	ruleset_fd =
1752 		landlock_create_ruleset(&ruleset_net, sizeof(ruleset_net), 0);
1753 	ASSERT_LE(0, ruleset_fd);
1754 	enforce_ruleset(_metadata, ruleset_fd);
1755 	ASSERT_EQ(0, close(ruleset_fd));
1756 
1757 	/* Mount, remount, move_mount, umount, and pivot_root checks. */
1758 	set_cap(_metadata, CAP_SYS_ADMIN);
1759 	ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s1d2));
1760 	ASSERT_EQ(0, mount(NULL, dir_s1d2, NULL, MS_PRIVATE | MS_REC, NULL));
1761 	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD,
1762 			     dir_s2d2, 0));
1763 	ASSERT_EQ(0, umount(dir_s2d2));
1764 	ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1765 	ASSERT_EQ(0, chdir("/"));
1766 	clear_cap(_metadata, CAP_SYS_ADMIN);
1767 }
1768 
TEST_F_FORK(layout1,topology_changes_with_net_and_fs)1769 TEST_F_FORK(layout1, topology_changes_with_net_and_fs)
1770 {
1771 	const struct landlock_ruleset_attr ruleset_net_fs = {
1772 		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1773 				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
1774 		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
1775 	};
1776 	int ruleset_fd;
1777 
1778 	/* Add network and filesystem restrictions. */
1779 	ruleset_fd = landlock_create_ruleset(&ruleset_net_fs,
1780 					     sizeof(ruleset_net_fs), 0);
1781 	ASSERT_LE(0, ruleset_fd);
1782 	enforce_ruleset(_metadata, ruleset_fd);
1783 	ASSERT_EQ(0, close(ruleset_fd));
1784 
1785 	/* Mount, remount, move_mount, umount, and pivot_root checks. */
1786 	set_cap(_metadata, CAP_SYS_ADMIN);
1787 	ASSERT_EQ(-1, mount_opt(&mnt_tmp, dir_s1d2));
1788 	ASSERT_EQ(EPERM, errno);
1789 	ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_PRIVATE | MS_REC, NULL));
1790 	ASSERT_EQ(EPERM, errno);
1791 	ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1792 			      dir_s2d2, 0));
1793 	ASSERT_EQ(EPERM, errno);
1794 	ASSERT_EQ(-1, umount(dir_s3d2));
1795 	ASSERT_EQ(EPERM, errno);
1796 	ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1797 	ASSERT_EQ(EPERM, errno);
1798 	clear_cap(_metadata, CAP_SYS_ADMIN);
1799 }
1800 
TEST_F_FORK(layout1,release_inodes)1801 TEST_F_FORK(layout1, release_inodes)
1802 {
1803 	const struct rule rules[] = {
1804 		{
1805 			.path = dir_s1d1,
1806 			.access = ACCESS_RO,
1807 		},
1808 		{
1809 			.path = dir_s3d2,
1810 			.access = ACCESS_RO,
1811 		},
1812 		{
1813 			.path = dir_s3d3,
1814 			.access = ACCESS_RO,
1815 		},
1816 		{},
1817 	};
1818 	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1819 
1820 	ASSERT_LE(0, ruleset_fd);
1821 	/* Unmount a file hierarchy while it is being used by a ruleset. */
1822 	set_cap(_metadata, CAP_SYS_ADMIN);
1823 	ASSERT_EQ(0, umount(dir_s3d2));
1824 	clear_cap(_metadata, CAP_SYS_ADMIN);
1825 
1826 	enforce_ruleset(_metadata, ruleset_fd);
1827 	ASSERT_EQ(0, close(ruleset_fd));
1828 
1829 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
1830 	ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY));
1831 	/* This dir_s3d3 would not be allowed and does not exist anyway. */
1832 	ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY));
1833 }
1834 
1835 /*
1836  * This test checks that a rule on a directory used as a mount point does not
1837  * grant access to the mount covering it.  It is a generalization of the bind
1838  * mount case in layout3_fs.hostfs.release_inodes that tests hidden mount points.
1839  */
TEST_F_FORK(layout1,covered_rule)1840 TEST_F_FORK(layout1, covered_rule)
1841 {
1842 	const struct rule layer1[] = {
1843 		{
1844 			.path = dir_s3d2,
1845 			.access = LANDLOCK_ACCESS_FS_READ_DIR,
1846 		},
1847 		{},
1848 	};
1849 	int ruleset_fd;
1850 
1851 	/* Unmount to simplify FIXTURE_TEARDOWN. */
1852 	set_cap(_metadata, CAP_SYS_ADMIN);
1853 	ASSERT_EQ(0, umount(dir_s3d2));
1854 	clear_cap(_metadata, CAP_SYS_ADMIN);
1855 
1856 	/* Creates a ruleset with the future hidden directory. */
1857 	ruleset_fd =
1858 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
1859 	ASSERT_LE(0, ruleset_fd);
1860 
1861 	/* Covers with a new mount point. */
1862 	set_cap(_metadata, CAP_SYS_ADMIN);
1863 	ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s3d2));
1864 	clear_cap(_metadata, CAP_SYS_ADMIN);
1865 
1866 	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1867 
1868 	enforce_ruleset(_metadata, ruleset_fd);
1869 	ASSERT_EQ(0, close(ruleset_fd));
1870 
1871 	/* Checks that access to the new mount point is denied. */
1872 	ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY));
1873 }
1874 
1875 enum relative_access {
1876 	REL_OPEN,
1877 	REL_CHDIR,
1878 	REL_CHROOT_ONLY,
1879 	REL_CHROOT_CHDIR,
1880 };
1881 
test_relative_path(struct __test_metadata * const _metadata,const enum relative_access rel)1882 static void test_relative_path(struct __test_metadata *const _metadata,
1883 			       const enum relative_access rel)
1884 {
1885 	/*
1886 	 * Common layer to check that chroot doesn't ignore it (i.e. a chroot
1887 	 * is not a disconnected root directory).
1888 	 */
1889 	const struct rule layer1_base[] = {
1890 		{
1891 			.path = TMP_DIR,
1892 			.access = ACCESS_RO,
1893 		},
1894 		{},
1895 	};
1896 	const struct rule layer2_subs[] = {
1897 		{
1898 			.path = dir_s1d2,
1899 			.access = ACCESS_RO,
1900 		},
1901 		{
1902 			.path = dir_s2d2,
1903 			.access = ACCESS_RO,
1904 		},
1905 		{},
1906 	};
1907 	int dirfd, ruleset_fd;
1908 
1909 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
1910 	ASSERT_LE(0, ruleset_fd);
1911 	enforce_ruleset(_metadata, ruleset_fd);
1912 	ASSERT_EQ(0, close(ruleset_fd));
1913 
1914 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs);
1915 
1916 	ASSERT_LE(0, ruleset_fd);
1917 	switch (rel) {
1918 	case REL_OPEN:
1919 	case REL_CHDIR:
1920 		break;
1921 	case REL_CHROOT_ONLY:
1922 		ASSERT_EQ(0, chdir(dir_s2d2));
1923 		break;
1924 	case REL_CHROOT_CHDIR:
1925 		ASSERT_EQ(0, chdir(dir_s1d2));
1926 		break;
1927 	default:
1928 		ASSERT_TRUE(false);
1929 		return;
1930 	}
1931 
1932 	set_cap(_metadata, CAP_SYS_CHROOT);
1933 	enforce_ruleset(_metadata, ruleset_fd);
1934 
1935 	switch (rel) {
1936 	case REL_OPEN:
1937 		dirfd = open(dir_s1d2, O_DIRECTORY);
1938 		ASSERT_LE(0, dirfd);
1939 		break;
1940 	case REL_CHDIR:
1941 		ASSERT_EQ(0, chdir(dir_s1d2));
1942 		dirfd = AT_FDCWD;
1943 		break;
1944 	case REL_CHROOT_ONLY:
1945 		/* Do chroot into dir_s1d2 (relative to dir_s2d2). */
1946 		ASSERT_EQ(0, chroot("../../s1d1/s1d2"))
1947 		{
1948 			TH_LOG("Failed to chroot: %s", strerror(errno));
1949 		}
1950 		dirfd = AT_FDCWD;
1951 		break;
1952 	case REL_CHROOT_CHDIR:
1953 		/* Do chroot into dir_s1d2. */
1954 		ASSERT_EQ(0, chroot("."))
1955 		{
1956 			TH_LOG("Failed to chroot: %s", strerror(errno));
1957 		}
1958 		dirfd = AT_FDCWD;
1959 		break;
1960 	}
1961 
1962 	ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES,
1963 		  test_open_rel(dirfd, "..", O_RDONLY));
1964 	ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY));
1965 
1966 	if (rel == REL_CHROOT_ONLY) {
1967 		/* The current directory is dir_s2d2. */
1968 		ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY));
1969 	} else {
1970 		/* The current directory is dir_s1d2. */
1971 		ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY));
1972 	}
1973 
1974 	if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) {
1975 		/* Checks the root dir_s1d2. */
1976 		ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY));
1977 		ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY));
1978 		ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY));
1979 		ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY));
1980 	}
1981 
1982 	if (rel != REL_CHROOT_CHDIR) {
1983 		ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY));
1984 		ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY));
1985 		ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3",
1986 					   O_RDONLY));
1987 
1988 		ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY));
1989 		ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY));
1990 		ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3",
1991 					   O_RDONLY));
1992 	}
1993 
1994 	if (rel == REL_OPEN)
1995 		ASSERT_EQ(0, close(dirfd));
1996 	ASSERT_EQ(0, close(ruleset_fd));
1997 }
1998 
TEST_F_FORK(layout1,relative_open)1999 TEST_F_FORK(layout1, relative_open)
2000 {
2001 	test_relative_path(_metadata, REL_OPEN);
2002 }
2003 
TEST_F_FORK(layout1,relative_chdir)2004 TEST_F_FORK(layout1, relative_chdir)
2005 {
2006 	test_relative_path(_metadata, REL_CHDIR);
2007 }
2008 
TEST_F_FORK(layout1,relative_chroot_only)2009 TEST_F_FORK(layout1, relative_chroot_only)
2010 {
2011 	test_relative_path(_metadata, REL_CHROOT_ONLY);
2012 }
2013 
TEST_F_FORK(layout1,relative_chroot_chdir)2014 TEST_F_FORK(layout1, relative_chroot_chdir)
2015 {
2016 	test_relative_path(_metadata, REL_CHROOT_CHDIR);
2017 }
2018 
copy_file(struct __test_metadata * const _metadata,const char * const src_path,const char * const dst_path)2019 static void copy_file(struct __test_metadata *const _metadata,
2020 		      const char *const src_path, const char *const dst_path)
2021 {
2022 	int dst_fd, src_fd;
2023 	struct stat statbuf;
2024 
2025 	dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC);
2026 	ASSERT_LE(0, dst_fd)
2027 	{
2028 		TH_LOG("Failed to open \"%s\": %s", dst_path, strerror(errno));
2029 	}
2030 	src_fd = open(src_path, O_RDONLY | O_CLOEXEC);
2031 	ASSERT_LE(0, src_fd)
2032 	{
2033 		TH_LOG("Failed to open \"%s\": %s", src_path, strerror(errno));
2034 	}
2035 	ASSERT_EQ(0, fstat(src_fd, &statbuf));
2036 	ASSERT_EQ(statbuf.st_size,
2037 		  sendfile(dst_fd, src_fd, 0, statbuf.st_size));
2038 	ASSERT_EQ(0, close(src_fd));
2039 	ASSERT_EQ(0, close(dst_fd));
2040 }
2041 
test_execute(struct __test_metadata * const _metadata,const int err,const char * const path)2042 static void test_execute(struct __test_metadata *const _metadata, const int err,
2043 			 const char *const path)
2044 {
2045 	int status;
2046 	char *const argv[] = { (char *)path, NULL };
2047 	const pid_t child = fork();
2048 
2049 	ASSERT_LE(0, child);
2050 	if (child == 0) {
2051 		ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL))
2052 		{
2053 			TH_LOG("Failed to execute \"%s\": %s", path,
2054 			       strerror(errno));
2055 		};
2056 		ASSERT_EQ(err, errno);
2057 		_exit(__test_passed(_metadata) ? 2 : 1);
2058 		return;
2059 	}
2060 	ASSERT_EQ(child, waitpid(child, &status, 0));
2061 	ASSERT_EQ(1, WIFEXITED(status));
2062 	ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status))
2063 	{
2064 		TH_LOG("Unexpected return code for \"%s\"", path);
2065 	};
2066 }
2067 
test_check_exec(struct __test_metadata * const _metadata,const int err,const char * const path)2068 static void test_check_exec(struct __test_metadata *const _metadata,
2069 			    const int err, const char *const path)
2070 {
2071 	int ret;
2072 	char *const argv[] = { (char *)path, NULL };
2073 
2074 	ret = sys_execveat(AT_FDCWD, path, argv, NULL,
2075 			   AT_EMPTY_PATH | AT_EXECVE_CHECK);
2076 	if (err) {
2077 		EXPECT_EQ(-1, ret);
2078 		EXPECT_EQ(errno, err);
2079 	} else {
2080 		EXPECT_EQ(0, ret);
2081 	}
2082 }
2083 
TEST_F_FORK(layout1,execute)2084 TEST_F_FORK(layout1, execute)
2085 {
2086 	const struct rule rules[] = {
2087 		{
2088 			.path = dir_s1d2,
2089 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
2090 		},
2091 		{},
2092 	};
2093 	const int ruleset_fd =
2094 		create_ruleset(_metadata, rules[0].access, rules);
2095 
2096 	ASSERT_LE(0, ruleset_fd);
2097 	copy_file(_metadata, bin_true, file1_s1d1);
2098 	copy_file(_metadata, bin_true, file1_s1d2);
2099 	copy_file(_metadata, bin_true, file1_s1d3);
2100 
2101 	/* Checks before file1_s1d1 being denied. */
2102 	test_execute(_metadata, 0, file1_s1d1);
2103 	test_check_exec(_metadata, 0, file1_s1d1);
2104 
2105 	enforce_ruleset(_metadata, ruleset_fd);
2106 	ASSERT_EQ(0, close(ruleset_fd));
2107 
2108 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
2109 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
2110 	test_execute(_metadata, EACCES, file1_s1d1);
2111 	test_check_exec(_metadata, EACCES, file1_s1d1);
2112 
2113 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
2114 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
2115 	test_execute(_metadata, 0, file1_s1d2);
2116 	test_check_exec(_metadata, 0, file1_s1d2);
2117 
2118 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
2119 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
2120 	test_execute(_metadata, 0, file1_s1d3);
2121 	test_check_exec(_metadata, 0, file1_s1d3);
2122 }
2123 
TEST_F_FORK(layout1,umount_sandboxer)2124 TEST_F_FORK(layout1, umount_sandboxer)
2125 {
2126 	int pipe_child[2], pipe_parent[2];
2127 	char buf_parent;
2128 	pid_t child;
2129 	int status;
2130 
2131 	copy_file(_metadata, bin_sandbox_and_launch, file1_s3d3);
2132 	ASSERT_EQ(0, pipe2(pipe_child, 0));
2133 	ASSERT_EQ(0, pipe2(pipe_parent, 0));
2134 
2135 	child = fork();
2136 	ASSERT_LE(0, child);
2137 	if (child == 0) {
2138 		char pipe_child_str[12], pipe_parent_str[12];
2139 		char *const argv[] = { (char *)file1_s3d3,
2140 				       (char *)bin_wait_pipe, pipe_child_str,
2141 				       pipe_parent_str, NULL };
2142 
2143 		/* Passes the pipe FDs to the executed binary and its child. */
2144 		EXPECT_EQ(0, close(pipe_child[0]));
2145 		EXPECT_EQ(0, close(pipe_parent[1]));
2146 		snprintf(pipe_child_str, sizeof(pipe_child_str), "%d",
2147 			 pipe_child[1]);
2148 		snprintf(pipe_parent_str, sizeof(pipe_parent_str), "%d",
2149 			 pipe_parent[0]);
2150 
2151 		/*
2152 		 * We need bin_sandbox_and_launch (copied inside the mount as
2153 		 * file1_s3d3) to execute bin_wait_pipe (outside the mount) to
2154 		 * make sure the mount point will not be EBUSY because of
2155 		 * file1_s3d3 being in use.  This avoids a potential race
2156 		 * condition between the following read() and umount() calls.
2157 		 */
2158 		ASSERT_EQ(0, execve(argv[0], argv, NULL))
2159 		{
2160 			TH_LOG("Failed to execute \"%s\": %s", argv[0],
2161 			       strerror(errno));
2162 		};
2163 		_exit(1);
2164 		return;
2165 	}
2166 
2167 	EXPECT_EQ(0, close(pipe_child[1]));
2168 	EXPECT_EQ(0, close(pipe_parent[0]));
2169 
2170 	/* Waits for the child to sandbox itself. */
2171 	EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
2172 
2173 	/* Tests that the sandboxer is tied to its mount point. */
2174 	set_cap(_metadata, CAP_SYS_ADMIN);
2175 	EXPECT_EQ(-1, umount(dir_s3d2));
2176 	EXPECT_EQ(EBUSY, errno);
2177 	clear_cap(_metadata, CAP_SYS_ADMIN);
2178 
2179 	/* Signals the child to launch a grandchild. */
2180 	EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
2181 
2182 	/* Waits for the grandchild. */
2183 	EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
2184 
2185 	/* Tests that the domain's sandboxer is not tied to its mount point. */
2186 	set_cap(_metadata, CAP_SYS_ADMIN);
2187 	EXPECT_EQ(0, umount(dir_s3d2))
2188 	{
2189 		TH_LOG("Failed to umount \"%s\": %s", dir_s3d2,
2190 		       strerror(errno));
2191 	};
2192 	clear_cap(_metadata, CAP_SYS_ADMIN);
2193 
2194 	/* Signals the grandchild to terminate. */
2195 	EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
2196 	ASSERT_EQ(child, waitpid(child, &status, 0));
2197 	ASSERT_EQ(1, WIFEXITED(status));
2198 	ASSERT_EQ(0, WEXITSTATUS(status));
2199 }
2200 
TEST_F_FORK(layout1,link)2201 TEST_F_FORK(layout1, link)
2202 {
2203 	const struct rule layer1[] = {
2204 		{
2205 			.path = dir_s1d2,
2206 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2207 		},
2208 		{},
2209 	};
2210 	const struct rule layer2[] = {
2211 		{
2212 			.path = dir_s1d3,
2213 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2214 		},
2215 		{},
2216 	};
2217 	int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
2218 
2219 	ASSERT_LE(0, ruleset_fd);
2220 
2221 	ASSERT_EQ(0, unlink(file1_s1d1));
2222 	ASSERT_EQ(0, unlink(file1_s1d2));
2223 	ASSERT_EQ(0, unlink(file1_s1d3));
2224 
2225 	enforce_ruleset(_metadata, ruleset_fd);
2226 	ASSERT_EQ(0, close(ruleset_fd));
2227 
2228 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
2229 	ASSERT_EQ(EACCES, errno);
2230 
2231 	/* Denies linking because of reparenting. */
2232 	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
2233 	ASSERT_EQ(EXDEV, errno);
2234 	ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
2235 	ASSERT_EQ(EXDEV, errno);
2236 	ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
2237 	ASSERT_EQ(EXDEV, errno);
2238 
2239 	ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
2240 	ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
2241 
2242 	/* Prepares for next unlinks. */
2243 	ASSERT_EQ(0, unlink(file2_s1d2));
2244 	ASSERT_EQ(0, unlink(file2_s1d3));
2245 
2246 	ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
2247 	ASSERT_LE(0, ruleset_fd);
2248 	enforce_ruleset(_metadata, ruleset_fd);
2249 	ASSERT_EQ(0, close(ruleset_fd));
2250 
2251 	/* Checks that linkind doesn't require the ability to delete a file. */
2252 	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
2253 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
2254 }
2255 
test_rename(const char * const oldpath,const char * const newpath)2256 static int test_rename(const char *const oldpath, const char *const newpath)
2257 {
2258 	if (rename(oldpath, newpath))
2259 		return errno;
2260 	return 0;
2261 }
2262 
test_exchange(const char * const oldpath,const char * const newpath)2263 static int test_exchange(const char *const oldpath, const char *const newpath)
2264 {
2265 	if (renameat2(AT_FDCWD, oldpath, AT_FDCWD, newpath, RENAME_EXCHANGE))
2266 		return errno;
2267 	return 0;
2268 }
2269 
TEST_F_FORK(layout1,rename_file)2270 TEST_F_FORK(layout1, rename_file)
2271 {
2272 	const struct rule rules[] = {
2273 		{
2274 			.path = dir_s1d3,
2275 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2276 		},
2277 		{
2278 			.path = dir_s2d2,
2279 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2280 		},
2281 		{},
2282 	};
2283 	const int ruleset_fd =
2284 		create_ruleset(_metadata, rules[0].access, rules);
2285 
2286 	ASSERT_LE(0, ruleset_fd);
2287 
2288 	ASSERT_EQ(0, unlink(file1_s1d2));
2289 
2290 	enforce_ruleset(_metadata, ruleset_fd);
2291 	ASSERT_EQ(0, close(ruleset_fd));
2292 
2293 	/*
2294 	 * Tries to replace a file, from a directory that allows file removal,
2295 	 * but to a different directory (which also allows file removal).
2296 	 */
2297 	ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3));
2298 	ASSERT_EQ(EXDEV, errno);
2299 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3,
2300 				RENAME_EXCHANGE));
2301 	ASSERT_EQ(EXDEV, errno);
2302 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2303 				RENAME_EXCHANGE));
2304 	ASSERT_EQ(EXDEV, errno);
2305 
2306 	/*
2307 	 * Tries to replace a file, from a directory that denies file removal,
2308 	 * to a different directory (which allows file removal).
2309 	 */
2310 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2311 	ASSERT_EQ(EACCES, errno);
2312 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3,
2313 				RENAME_EXCHANGE));
2314 	ASSERT_EQ(EACCES, errno);
2315 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3,
2316 				RENAME_EXCHANGE));
2317 	ASSERT_EQ(EXDEV, errno);
2318 
2319 	/* Exchanges files and directories that partially allow removal. */
2320 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1,
2321 				RENAME_EXCHANGE));
2322 	ASSERT_EQ(EACCES, errno);
2323 	/* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */
2324 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1));
2325 	ASSERT_EQ(EACCES, errno);
2326 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2,
2327 				RENAME_EXCHANGE));
2328 	ASSERT_EQ(EACCES, errno);
2329 	/* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */
2330 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2331 	ASSERT_EQ(EACCES, errno);
2332 
2333 	/* Renames files with different parents. */
2334 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2335 	ASSERT_EQ(EXDEV, errno);
2336 	ASSERT_EQ(0, unlink(file1_s1d3));
2337 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2338 	ASSERT_EQ(EACCES, errno);
2339 
2340 	/* Exchanges and renames files with same parent. */
2341 	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3,
2342 			       RENAME_EXCHANGE));
2343 	ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3));
2344 
2345 	/* Exchanges files and directories with same parent, twice. */
2346 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2347 			       RENAME_EXCHANGE));
2348 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2349 			       RENAME_EXCHANGE));
2350 }
2351 
TEST_F_FORK(layout1,rename_dir)2352 TEST_F_FORK(layout1, rename_dir)
2353 {
2354 	const struct rule rules[] = {
2355 		{
2356 			.path = dir_s1d2,
2357 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2358 		},
2359 		{
2360 			.path = dir_s2d1,
2361 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2362 		},
2363 		{},
2364 	};
2365 	const int ruleset_fd =
2366 		create_ruleset(_metadata, rules[0].access, rules);
2367 
2368 	ASSERT_LE(0, ruleset_fd);
2369 
2370 	/* Empties dir_s1d3 to allow renaming. */
2371 	ASSERT_EQ(0, unlink(file1_s1d3));
2372 	ASSERT_EQ(0, unlink(file2_s1d3));
2373 
2374 	enforce_ruleset(_metadata, ruleset_fd);
2375 	ASSERT_EQ(0, close(ruleset_fd));
2376 
2377 	/* Exchanges and renames directory to a different parent. */
2378 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
2379 				RENAME_EXCHANGE));
2380 	ASSERT_EQ(EXDEV, errno);
2381 	ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3));
2382 	ASSERT_EQ(EXDEV, errno);
2383 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
2384 				RENAME_EXCHANGE));
2385 	ASSERT_EQ(EXDEV, errno);
2386 
2387 	/*
2388 	 * Exchanges directory to the same parent, which doesn't allow
2389 	 * directory removal.
2390 	 */
2391 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1,
2392 				RENAME_EXCHANGE));
2393 	ASSERT_EQ(EACCES, errno);
2394 	/* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */
2395 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1));
2396 	ASSERT_EQ(EACCES, errno);
2397 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2,
2398 				RENAME_EXCHANGE));
2399 	ASSERT_EQ(EACCES, errno);
2400 	/* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */
2401 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2402 	ASSERT_EQ(EACCES, errno);
2403 
2404 	/*
2405 	 * Exchanges and renames directory to the same parent, which allows
2406 	 * directory removal.
2407 	 */
2408 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2,
2409 			       RENAME_EXCHANGE));
2410 	ASSERT_EQ(0, unlink(dir_s1d3));
2411 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
2412 	ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3));
2413 	ASSERT_EQ(0, rmdir(dir_s1d3));
2414 }
2415 
TEST_F_FORK(layout1,reparent_refer)2416 TEST_F_FORK(layout1, reparent_refer)
2417 {
2418 	const struct rule layer1[] = {
2419 		{
2420 			.path = dir_s1d2,
2421 			.access = LANDLOCK_ACCESS_FS_REFER,
2422 		},
2423 		{
2424 			.path = dir_s2d2,
2425 			.access = LANDLOCK_ACCESS_FS_REFER,
2426 		},
2427 		{},
2428 	};
2429 	int ruleset_fd =
2430 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
2431 
2432 	ASSERT_LE(0, ruleset_fd);
2433 	enforce_ruleset(_metadata, ruleset_fd);
2434 	ASSERT_EQ(0, close(ruleset_fd));
2435 
2436 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d1));
2437 	ASSERT_EQ(EXDEV, errno);
2438 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d2));
2439 	ASSERT_EQ(EXDEV, errno);
2440 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
2441 	ASSERT_EQ(EXDEV, errno);
2442 
2443 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d1));
2444 	ASSERT_EQ(EXDEV, errno);
2445 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d2));
2446 	ASSERT_EQ(EXDEV, errno);
2447 	/*
2448 	 * Moving should only be allowed when the source and the destination
2449 	 * parent directory have REFER.
2450 	 */
2451 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d3));
2452 	ASSERT_EQ(ENOTEMPTY, errno);
2453 	ASSERT_EQ(0, unlink(file1_s2d3));
2454 	ASSERT_EQ(0, unlink(file2_s2d3));
2455 	ASSERT_EQ(0, rename(dir_s1d3, dir_s2d3));
2456 }
2457 
2458 /* Checks renames beneath dir_s1d1. */
refer_denied_by_default(struct __test_metadata * const _metadata,const struct rule layer1[],const int layer1_err,const struct rule layer2[])2459 static void refer_denied_by_default(struct __test_metadata *const _metadata,
2460 				    const struct rule layer1[],
2461 				    const int layer1_err,
2462 				    const struct rule layer2[])
2463 {
2464 	int ruleset_fd;
2465 
2466 	ASSERT_EQ(0, unlink(file1_s1d2));
2467 
2468 	ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
2469 	ASSERT_LE(0, ruleset_fd);
2470 	enforce_ruleset(_metadata, ruleset_fd);
2471 	ASSERT_EQ(0, close(ruleset_fd));
2472 
2473 	/*
2474 	 * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to
2475 	 * layer1_err), then it allows some different-parent renames and links.
2476 	 */
2477 	ASSERT_EQ(layer1_err, test_rename(file1_s1d1, file1_s1d2));
2478 	if (layer1_err == 0)
2479 		ASSERT_EQ(layer1_err, test_rename(file1_s1d2, file1_s1d1));
2480 	ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2));
2481 	ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1));
2482 
2483 	ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
2484 	ASSERT_LE(0, ruleset_fd);
2485 	enforce_ruleset(_metadata, ruleset_fd);
2486 	ASSERT_EQ(0, close(ruleset_fd));
2487 
2488 	/*
2489 	 * Now, either the first or the second layer does not handle
2490 	 * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent
2491 	 * renames and links are denied, thus making the layer handling
2492 	 * LANDLOCK_ACCESS_FS_REFER null and void.
2493 	 */
2494 	ASSERT_EQ(EXDEV, test_rename(file1_s1d1, file1_s1d2));
2495 	ASSERT_EQ(EXDEV, test_exchange(file2_s1d1, file2_s1d2));
2496 	ASSERT_EQ(EXDEV, test_exchange(file2_s1d2, file2_s1d1));
2497 }
2498 
2499 const struct rule layer_dir_s1d1_refer[] = {
2500 	{
2501 		.path = dir_s1d1,
2502 		.access = LANDLOCK_ACCESS_FS_REFER,
2503 	},
2504 	{},
2505 };
2506 
2507 const struct rule layer_dir_s1d1_execute[] = {
2508 	{
2509 		/* Matches a parent directory. */
2510 		.path = dir_s1d1,
2511 		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2512 	},
2513 	{},
2514 };
2515 
2516 const struct rule layer_dir_s2d1_execute[] = {
2517 	{
2518 		/* Does not match a parent directory. */
2519 		.path = dir_s2d1,
2520 		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2521 	},
2522 	{},
2523 };
2524 
2525 /*
2526  * Tests precedence over renames: denied by default for different parent
2527  * directories, *with* a rule matching a parent directory, but not directly
2528  * denying access (with MAKE_REG nor REMOVE).
2529  */
TEST_F_FORK(layout1,refer_denied_by_default1)2530 TEST_F_FORK(layout1, refer_denied_by_default1)
2531 {
2532 	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2533 				layer_dir_s1d1_execute);
2534 }
2535 
2536 /*
2537  * Same test but this time turning around the ABI version order: the first
2538  * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2539  */
TEST_F_FORK(layout1,refer_denied_by_default2)2540 TEST_F_FORK(layout1, refer_denied_by_default2)
2541 {
2542 	refer_denied_by_default(_metadata, layer_dir_s1d1_execute, EXDEV,
2543 				layer_dir_s1d1_refer);
2544 }
2545 
2546 /*
2547  * Tests precedence over renames: denied by default for different parent
2548  * directories, *without* a rule matching a parent directory, but not directly
2549  * denying access (with MAKE_REG nor REMOVE).
2550  */
TEST_F_FORK(layout1,refer_denied_by_default3)2551 TEST_F_FORK(layout1, refer_denied_by_default3)
2552 {
2553 	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2554 				layer_dir_s2d1_execute);
2555 }
2556 
2557 /*
2558  * Same test but this time turning around the ABI version order: the first
2559  * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2560  */
TEST_F_FORK(layout1,refer_denied_by_default4)2561 TEST_F_FORK(layout1, refer_denied_by_default4)
2562 {
2563 	refer_denied_by_default(_metadata, layer_dir_s2d1_execute, EXDEV,
2564 				layer_dir_s1d1_refer);
2565 }
2566 
2567 /*
2568  * Tests walking through a denied root mount.
2569  */
TEST_F_FORK(layout1,refer_mount_root_deny)2570 TEST_F_FORK(layout1, refer_mount_root_deny)
2571 {
2572 	const struct landlock_ruleset_attr ruleset_attr = {
2573 		.handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_DIR,
2574 	};
2575 	int root_fd, ruleset_fd;
2576 
2577 	/* Creates a mount object from a non-mount point. */
2578 	set_cap(_metadata, CAP_SYS_ADMIN);
2579 	root_fd =
2580 		open_tree(AT_FDCWD, dir_s1d1,
2581 			  AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
2582 	clear_cap(_metadata, CAP_SYS_ADMIN);
2583 	ASSERT_LE(0, root_fd);
2584 
2585 	ruleset_fd =
2586 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
2587 	ASSERT_LE(0, ruleset_fd);
2588 
2589 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
2590 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
2591 	EXPECT_EQ(0, close(ruleset_fd));
2592 
2593 	/* Link denied by Landlock: EACCES. */
2594 	EXPECT_EQ(-1, linkat(root_fd, ".", root_fd, "does_not_exist", 0));
2595 	EXPECT_EQ(EACCES, errno);
2596 
2597 	/* renameat2() always returns EBUSY. */
2598 	EXPECT_EQ(-1, renameat2(root_fd, ".", root_fd, "does_not_exist", 0));
2599 	EXPECT_EQ(EBUSY, errno);
2600 
2601 	EXPECT_EQ(0, close(root_fd));
2602 }
2603 
TEST_F_FORK(layout1,refer_part_mount_tree_is_allowed)2604 TEST_F_FORK(layout1, refer_part_mount_tree_is_allowed)
2605 {
2606 	const struct rule layer1[] = {
2607 		{
2608 			/* Parent mount point. */
2609 			.path = dir_s3d1,
2610 			.access = LANDLOCK_ACCESS_FS_REFER |
2611 				  LANDLOCK_ACCESS_FS_MAKE_REG,
2612 		},
2613 		{
2614 			/*
2615 			 * Removing the source file is allowed because its
2616 			 * access rights are already a superset of the
2617 			 * destination.
2618 			 */
2619 			.path = dir_s3d4,
2620 			.access = LANDLOCK_ACCESS_FS_REFER |
2621 				  LANDLOCK_ACCESS_FS_MAKE_REG |
2622 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
2623 		},
2624 		{},
2625 	};
2626 	int ruleset_fd;
2627 
2628 	ASSERT_EQ(0, unlink(file1_s3d3));
2629 	ruleset_fd = create_ruleset(_metadata,
2630 				    LANDLOCK_ACCESS_FS_REFER |
2631 					    LANDLOCK_ACCESS_FS_MAKE_REG |
2632 					    LANDLOCK_ACCESS_FS_REMOVE_FILE,
2633 				    layer1);
2634 
2635 	ASSERT_LE(0, ruleset_fd);
2636 	enforce_ruleset(_metadata, ruleset_fd);
2637 	ASSERT_EQ(0, close(ruleset_fd));
2638 
2639 	ASSERT_EQ(0, rename(file1_s3d4, file1_s3d3));
2640 }
2641 
TEST_F_FORK(layout1,reparent_link)2642 TEST_F_FORK(layout1, reparent_link)
2643 {
2644 	const struct rule layer1[] = {
2645 		{
2646 			.path = dir_s1d2,
2647 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2648 		},
2649 		{
2650 			.path = dir_s1d3,
2651 			.access = LANDLOCK_ACCESS_FS_REFER,
2652 		},
2653 		{
2654 			.path = dir_s2d2,
2655 			.access = LANDLOCK_ACCESS_FS_REFER,
2656 		},
2657 		{
2658 			.path = dir_s2d3,
2659 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2660 		},
2661 		{},
2662 	};
2663 	const int ruleset_fd = create_ruleset(
2664 		_metadata,
2665 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2666 
2667 	ASSERT_LE(0, ruleset_fd);
2668 	enforce_ruleset(_metadata, ruleset_fd);
2669 	ASSERT_EQ(0, close(ruleset_fd));
2670 
2671 	ASSERT_EQ(0, unlink(file1_s1d1));
2672 	ASSERT_EQ(0, unlink(file1_s1d2));
2673 	ASSERT_EQ(0, unlink(file1_s1d3));
2674 
2675 	/* Denies linking because of missing MAKE_REG. */
2676 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
2677 	ASSERT_EQ(EACCES, errno);
2678 	/* Denies linking because of missing source and destination REFER. */
2679 	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
2680 	ASSERT_EQ(EXDEV, errno);
2681 	/* Denies linking because of missing source REFER. */
2682 	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d3));
2683 	ASSERT_EQ(EXDEV, errno);
2684 
2685 	/* Denies linking because of missing MAKE_REG. */
2686 	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d1));
2687 	ASSERT_EQ(EACCES, errno);
2688 	/* Denies linking because of missing destination REFER. */
2689 	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d2));
2690 	ASSERT_EQ(EXDEV, errno);
2691 
2692 	/* Allows linking because of REFER and MAKE_REG. */
2693 	ASSERT_EQ(0, link(file1_s2d2, file1_s1d3));
2694 	ASSERT_EQ(0, unlink(file1_s2d2));
2695 	/* Reverse linking denied because of missing MAKE_REG. */
2696 	ASSERT_EQ(-1, link(file1_s1d3, file1_s2d2));
2697 	ASSERT_EQ(EACCES, errno);
2698 	ASSERT_EQ(0, unlink(file1_s2d3));
2699 	/* Checks reverse linking. */
2700 	ASSERT_EQ(0, link(file1_s1d3, file1_s2d3));
2701 	ASSERT_EQ(0, unlink(file1_s1d3));
2702 
2703 	/*
2704 	 * This is OK for a file link, but it should not be allowed for a
2705 	 * directory rename (because of the superset of access rights.
2706 	 */
2707 	ASSERT_EQ(0, link(file1_s2d3, file1_s1d3));
2708 	ASSERT_EQ(0, unlink(file1_s1d3));
2709 
2710 	ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
2711 	ASSERT_EQ(EXDEV, errno);
2712 	ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
2713 	ASSERT_EQ(EXDEV, errno);
2714 
2715 	ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
2716 	ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
2717 }
2718 
TEST_F_FORK(layout1,reparent_rename)2719 TEST_F_FORK(layout1, reparent_rename)
2720 {
2721 	/* Same rules as for reparent_link. */
2722 	const struct rule layer1[] = {
2723 		{
2724 			.path = dir_s1d2,
2725 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2726 		},
2727 		{
2728 			.path = dir_s1d3,
2729 			.access = LANDLOCK_ACCESS_FS_REFER,
2730 		},
2731 		{
2732 			.path = dir_s2d2,
2733 			.access = LANDLOCK_ACCESS_FS_REFER,
2734 		},
2735 		{
2736 			.path = dir_s2d3,
2737 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2738 		},
2739 		{},
2740 	};
2741 	const int ruleset_fd = create_ruleset(
2742 		_metadata,
2743 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2744 
2745 	ASSERT_LE(0, ruleset_fd);
2746 	enforce_ruleset(_metadata, ruleset_fd);
2747 	ASSERT_EQ(0, close(ruleset_fd));
2748 
2749 	ASSERT_EQ(0, unlink(file1_s1d2));
2750 	ASSERT_EQ(0, unlink(file1_s1d3));
2751 
2752 	/* Denies renaming because of missing MAKE_REG. */
2753 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s1d1,
2754 				RENAME_EXCHANGE));
2755 	ASSERT_EQ(EACCES, errno);
2756 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file2_s1d1,
2757 				RENAME_EXCHANGE));
2758 	ASSERT_EQ(EACCES, errno);
2759 	ASSERT_EQ(0, unlink(file1_s1d1));
2760 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
2761 	ASSERT_EQ(EACCES, errno);
2762 	/* Even denies same file exchange. */
2763 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file2_s1d1,
2764 				RENAME_EXCHANGE));
2765 	ASSERT_EQ(EACCES, errno);
2766 
2767 	/* Denies renaming because of missing source and destination REFER. */
2768 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d2));
2769 	ASSERT_EQ(EXDEV, errno);
2770 	/*
2771 	 * Denies renaming because of missing MAKE_REG, source and destination
2772 	 * REFER.
2773 	 */
2774 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d1,
2775 				RENAME_EXCHANGE));
2776 	ASSERT_EQ(EACCES, errno);
2777 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s2d1,
2778 				RENAME_EXCHANGE));
2779 	ASSERT_EQ(EACCES, errno);
2780 
2781 	/* Denies renaming because of missing source REFER. */
2782 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2783 	ASSERT_EQ(EXDEV, errno);
2784 	/* Denies renaming because of missing MAKE_REG. */
2785 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d3,
2786 				RENAME_EXCHANGE));
2787 	ASSERT_EQ(EACCES, errno);
2788 
2789 	/* Denies renaming because of missing MAKE_REG. */
2790 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d1));
2791 	ASSERT_EQ(EACCES, errno);
2792 	/* Denies renaming because of missing destination REFER*/
2793 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2794 	ASSERT_EQ(EXDEV, errno);
2795 
2796 	/* Denies exchange because of one missing MAKE_REG. */
2797 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, file2_s1d3,
2798 				RENAME_EXCHANGE));
2799 	ASSERT_EQ(EACCES, errno);
2800 	/* Allows renaming because of REFER and MAKE_REG. */
2801 	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d3));
2802 
2803 	/* Reverse renaming denied because of missing MAKE_REG. */
2804 	ASSERT_EQ(-1, rename(file1_s1d3, file1_s2d2));
2805 	ASSERT_EQ(EACCES, errno);
2806 	ASSERT_EQ(0, unlink(file1_s2d3));
2807 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2808 
2809 	/* Tests reverse renaming. */
2810 	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2811 	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s1d3,
2812 			       RENAME_EXCHANGE));
2813 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2814 
2815 	/*
2816 	 * This is OK for a file rename, but it should not be allowed for a
2817 	 * directory rename (because of the superset of access rights).
2818 	 */
2819 	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2820 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2821 
2822 	/*
2823 	 * Tests superset restrictions applied to directories.  Not only the
2824 	 * dir_s2d3's parent (dir_s2d2) should be taken into account but also
2825 	 * access rights tied to dir_s2d3. dir_s2d2 is missing one access right
2826 	 * compared to dir_s1d3/file1_s1d3 (MAKE_REG) but it is provided
2827 	 * directly by the moved dir_s2d3.
2828 	 */
2829 	ASSERT_EQ(0, rename(dir_s2d3, file1_s1d3));
2830 	ASSERT_EQ(0, rename(file1_s1d3, dir_s2d3));
2831 	/*
2832 	 * The first rename is allowed but not the exchange because dir_s1d3's
2833 	 * parent (dir_s1d2) doesn't have REFER.
2834 	 */
2835 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2836 				RENAME_EXCHANGE));
2837 	ASSERT_EQ(EXDEV, errno);
2838 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s2d3,
2839 				RENAME_EXCHANGE));
2840 	ASSERT_EQ(EXDEV, errno);
2841 	ASSERT_EQ(-1, rename(file1_s2d3, dir_s1d3));
2842 	ASSERT_EQ(EXDEV, errno);
2843 
2844 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s1d3));
2845 	ASSERT_EQ(EXDEV, errno);
2846 	ASSERT_EQ(-1, rename(file2_s1d3, file1_s1d2));
2847 	ASSERT_EQ(EXDEV, errno);
2848 
2849 	/* Renaming in the same directory is always allowed. */
2850 	ASSERT_EQ(0, rename(file2_s1d2, file1_s1d2));
2851 	ASSERT_EQ(0, rename(file2_s1d3, file1_s1d3));
2852 
2853 	ASSERT_EQ(0, unlink(file1_s1d2));
2854 	/* Denies because of missing source MAKE_REG and destination REFER. */
2855 	ASSERT_EQ(-1, rename(dir_s2d3, file1_s1d2));
2856 	ASSERT_EQ(EXDEV, errno);
2857 
2858 	ASSERT_EQ(0, unlink(file1_s1d3));
2859 	/* Denies because of missing source MAKE_REG and REFER. */
2860 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d3));
2861 	ASSERT_EQ(EXDEV, errno);
2862 }
2863 
2864 static void
reparent_exdev_layers_enforce1(struct __test_metadata * const _metadata)2865 reparent_exdev_layers_enforce1(struct __test_metadata *const _metadata)
2866 {
2867 	const struct rule layer1[] = {
2868 		{
2869 			.path = dir_s1d2,
2870 			.access = LANDLOCK_ACCESS_FS_REFER,
2871 		},
2872 		{
2873 			/* Interesting for the layer2 tests. */
2874 			.path = dir_s1d3,
2875 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2876 		},
2877 		{
2878 			.path = dir_s2d2,
2879 			.access = LANDLOCK_ACCESS_FS_REFER,
2880 		},
2881 		{
2882 			.path = dir_s2d3,
2883 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2884 		},
2885 		{},
2886 	};
2887 	const int ruleset_fd = create_ruleset(
2888 		_metadata,
2889 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2890 
2891 	ASSERT_LE(0, ruleset_fd);
2892 	enforce_ruleset(_metadata, ruleset_fd);
2893 	ASSERT_EQ(0, close(ruleset_fd));
2894 }
2895 
2896 static void
reparent_exdev_layers_enforce2(struct __test_metadata * const _metadata)2897 reparent_exdev_layers_enforce2(struct __test_metadata *const _metadata)
2898 {
2899 	const struct rule layer2[] = {
2900 		{
2901 			.path = dir_s2d3,
2902 			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
2903 		},
2904 		{},
2905 	};
2906 	/*
2907 	 * Same checks as before but with a second layer and a new MAKE_DIR
2908 	 * rule (and no explicit handling of REFER).
2909 	 */
2910 	const int ruleset_fd =
2911 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2);
2912 
2913 	ASSERT_LE(0, ruleset_fd);
2914 	enforce_ruleset(_metadata, ruleset_fd);
2915 	ASSERT_EQ(0, close(ruleset_fd));
2916 }
2917 
TEST_F_FORK(layout1,reparent_exdev_layers_rename1)2918 TEST_F_FORK(layout1, reparent_exdev_layers_rename1)
2919 {
2920 	ASSERT_EQ(0, unlink(file1_s2d2));
2921 	ASSERT_EQ(0, unlink(file1_s2d3));
2922 
2923 	reparent_exdev_layers_enforce1(_metadata);
2924 
2925 	/*
2926 	 * Moving the dir_s1d3 directory below dir_s2d2 is allowed by Landlock
2927 	 * because it doesn't inherit new access rights.
2928 	 */
2929 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
2930 	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
2931 
2932 	/*
2933 	 * Moving the dir_s1d3 directory below dir_s2d3 is allowed, even if it
2934 	 * gets a new inherited access rights (MAKE_REG), because MAKE_REG is
2935 	 * already allowed for dir_s1d3.
2936 	 */
2937 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d3));
2938 	ASSERT_EQ(0, rename(file1_s2d3, dir_s1d3));
2939 
2940 	/*
2941 	 * However, moving the file1_s1d3 file below dir_s2d3 is allowed
2942 	 * because it cannot inherit MAKE_REG right (which is dedicated to
2943 	 * directories).
2944 	 */
2945 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2946 
2947 	reparent_exdev_layers_enforce2(_metadata);
2948 
2949 	/*
2950 	 * Moving the dir_s1d3 directory below dir_s2d2 is now denied because
2951 	 * MAKE_DIR is not tied to dir_s2d2.
2952 	 */
2953 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d2));
2954 	ASSERT_EQ(EACCES, errno);
2955 
2956 	/*
2957 	 * Moving the dir_s1d3 directory below dir_s2d3 is forbidden because it
2958 	 * would grants MAKE_REG and MAKE_DIR rights to it.
2959 	 */
2960 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
2961 	ASSERT_EQ(EXDEV, errno);
2962 
2963 	/*
2964 	 * Moving the file2_s1d3 file below dir_s2d3 is denied because the
2965 	 * second layer does not handle REFER, which is always denied by
2966 	 * default.
2967 	 */
2968 	ASSERT_EQ(-1, rename(file2_s1d3, file1_s2d3));
2969 	ASSERT_EQ(EXDEV, errno);
2970 }
2971 
TEST_F_FORK(layout1,reparent_exdev_layers_rename2)2972 TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
2973 {
2974 	reparent_exdev_layers_enforce1(_metadata);
2975 
2976 	/* Checks EACCES predominance over EXDEV. */
2977 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
2978 	ASSERT_EQ(EACCES, errno);
2979 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d2));
2980 	ASSERT_EQ(EACCES, errno);
2981 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
2982 	ASSERT_EQ(EXDEV, errno);
2983 	/* Modify layout! */
2984 	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d3));
2985 
2986 	/* Without REFER source. */
2987 	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
2988 	ASSERT_EQ(EXDEV, errno);
2989 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
2990 	ASSERT_EQ(EXDEV, errno);
2991 
2992 	reparent_exdev_layers_enforce2(_metadata);
2993 
2994 	/* Checks EACCES predominance over EXDEV. */
2995 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
2996 	ASSERT_EQ(EACCES, errno);
2997 	/* Checks with actual file2_s1d2. */
2998 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d2));
2999 	ASSERT_EQ(EACCES, errno);
3000 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
3001 	ASSERT_EQ(EXDEV, errno);
3002 	/*
3003 	 * Modifying the layout is now denied because the second layer does not
3004 	 * handle REFER, which is always denied by default.
3005 	 */
3006 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
3007 	ASSERT_EQ(EXDEV, errno);
3008 
3009 	/* Without REFER source, EACCES wins over EXDEV. */
3010 	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
3011 	ASSERT_EQ(EACCES, errno);
3012 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
3013 	ASSERT_EQ(EACCES, errno);
3014 }
3015 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange1)3016 TEST_F_FORK(layout1, reparent_exdev_layers_exchange1)
3017 {
3018 	const char *const dir_file1_s1d2 = file1_s1d2, *const dir_file2_s2d3 =
3019 							       file2_s2d3;
3020 
3021 	ASSERT_EQ(0, unlink(file1_s1d2));
3022 	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
3023 	ASSERT_EQ(0, unlink(file2_s2d3));
3024 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3025 
3026 	reparent_exdev_layers_enforce1(_metadata);
3027 
3028 	/* Error predominance with file exchange: returns EXDEV and EACCES. */
3029 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
3030 				RENAME_EXCHANGE));
3031 	ASSERT_EQ(EACCES, errno);
3032 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
3033 				RENAME_EXCHANGE));
3034 	ASSERT_EQ(EACCES, errno);
3035 
3036 	/*
3037 	 * Checks with directories which creation could be allowed, but denied
3038 	 * because of access rights that would be inherited.
3039 	 */
3040 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
3041 				dir_file2_s2d3, RENAME_EXCHANGE));
3042 	ASSERT_EQ(EXDEV, errno);
3043 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
3044 				dir_file1_s1d2, RENAME_EXCHANGE));
3045 	ASSERT_EQ(EXDEV, errno);
3046 
3047 	/* Checks with same access rights. */
3048 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
3049 			       RENAME_EXCHANGE));
3050 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
3051 			       RENAME_EXCHANGE));
3052 
3053 	/* Checks with different (child-only) access rights. */
3054 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
3055 			       RENAME_EXCHANGE));
3056 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
3057 			       RENAME_EXCHANGE));
3058 
3059 	/*
3060 	 * Checks that exchange between file and directory are consistent.
3061 	 *
3062 	 * Moving a file (file1_s2d2) to a directory which only grants more
3063 	 * directory-related access rights is allowed, and at the same time
3064 	 * moving a directory (dir_file2_s2d3) to another directory which
3065 	 * grants less access rights is allowed too.
3066 	 *
3067 	 * See layout1.reparent_exdev_layers_exchange3 for inverted arguments.
3068 	 */
3069 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3070 			       RENAME_EXCHANGE));
3071 	/*
3072 	 * However, moving back the directory is denied because it would get
3073 	 * more access rights than the current state and because file creation
3074 	 * is forbidden (in dir_s2d2).
3075 	 */
3076 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3077 				RENAME_EXCHANGE));
3078 	ASSERT_EQ(EACCES, errno);
3079 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3080 				RENAME_EXCHANGE));
3081 	ASSERT_EQ(EACCES, errno);
3082 
3083 	reparent_exdev_layers_enforce2(_metadata);
3084 
3085 	/* Error predominance with file exchange: returns EXDEV and EACCES. */
3086 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
3087 				RENAME_EXCHANGE));
3088 	ASSERT_EQ(EACCES, errno);
3089 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
3090 				RENAME_EXCHANGE));
3091 	ASSERT_EQ(EACCES, errno);
3092 
3093 	/* Checks with directories which creation is now denied. */
3094 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
3095 				dir_file2_s2d3, RENAME_EXCHANGE));
3096 	ASSERT_EQ(EACCES, errno);
3097 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
3098 				dir_file1_s1d2, RENAME_EXCHANGE));
3099 	ASSERT_EQ(EACCES, errno);
3100 
3101 	/* Checks with different (child-only) access rights. */
3102 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
3103 				RENAME_EXCHANGE));
3104 	/* Denied because of MAKE_DIR. */
3105 	ASSERT_EQ(EACCES, errno);
3106 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
3107 				RENAME_EXCHANGE));
3108 	ASSERT_EQ(EACCES, errno);
3109 
3110 	/* Checks with different (child-only) access rights. */
3111 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
3112 				RENAME_EXCHANGE));
3113 	/* Denied because of MAKE_DIR. */
3114 	ASSERT_EQ(EACCES, errno);
3115 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
3116 				RENAME_EXCHANGE));
3117 	ASSERT_EQ(EACCES, errno);
3118 
3119 	/* See layout1.reparent_exdev_layers_exchange2 for complement. */
3120 }
3121 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange2)3122 TEST_F_FORK(layout1, reparent_exdev_layers_exchange2)
3123 {
3124 	const char *const dir_file2_s2d3 = file2_s2d3;
3125 
3126 	ASSERT_EQ(0, unlink(file2_s2d3));
3127 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3128 
3129 	reparent_exdev_layers_enforce1(_metadata);
3130 	reparent_exdev_layers_enforce2(_metadata);
3131 
3132 	/* Checks that exchange between file and directory are consistent. */
3133 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3134 				RENAME_EXCHANGE));
3135 	ASSERT_EQ(EACCES, errno);
3136 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3137 				RENAME_EXCHANGE));
3138 	ASSERT_EQ(EACCES, errno);
3139 }
3140 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange3)3141 TEST_F_FORK(layout1, reparent_exdev_layers_exchange3)
3142 {
3143 	const char *const dir_file2_s2d3 = file2_s2d3;
3144 
3145 	ASSERT_EQ(0, unlink(file2_s2d3));
3146 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3147 
3148 	reparent_exdev_layers_enforce1(_metadata);
3149 
3150 	/*
3151 	 * Checks that exchange between file and directory are consistent,
3152 	 * including with inverted arguments (see
3153 	 * layout1.reparent_exdev_layers_exchange1).
3154 	 */
3155 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3156 			       RENAME_EXCHANGE));
3157 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3158 				RENAME_EXCHANGE));
3159 	ASSERT_EQ(EACCES, errno);
3160 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3161 				RENAME_EXCHANGE));
3162 	ASSERT_EQ(EACCES, errno);
3163 }
3164 
TEST_F_FORK(layout1,reparent_remove)3165 TEST_F_FORK(layout1, reparent_remove)
3166 {
3167 	const struct rule layer1[] = {
3168 		{
3169 			.path = dir_s1d1,
3170 			.access = LANDLOCK_ACCESS_FS_REFER |
3171 				  LANDLOCK_ACCESS_FS_REMOVE_DIR,
3172 		},
3173 		{
3174 			.path = dir_s1d2,
3175 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
3176 		},
3177 		{
3178 			.path = dir_s2d1,
3179 			.access = LANDLOCK_ACCESS_FS_REFER |
3180 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
3181 		},
3182 		{},
3183 	};
3184 	const int ruleset_fd = create_ruleset(
3185 		_metadata,
3186 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR |
3187 			LANDLOCK_ACCESS_FS_REMOVE_FILE,
3188 		layer1);
3189 
3190 	ASSERT_LE(0, ruleset_fd);
3191 	enforce_ruleset(_metadata, ruleset_fd);
3192 	ASSERT_EQ(0, close(ruleset_fd));
3193 
3194 	/* Access denied because of wrong/swapped remove file/dir. */
3195 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s2d2));
3196 	ASSERT_EQ(EACCES, errno);
3197 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d1));
3198 	ASSERT_EQ(EACCES, errno);
3199 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d2,
3200 				RENAME_EXCHANGE));
3201 	ASSERT_EQ(EACCES, errno);
3202 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d3,
3203 				RENAME_EXCHANGE));
3204 	ASSERT_EQ(EACCES, errno);
3205 
3206 	/* Access allowed thanks to the matching rights. */
3207 	ASSERT_EQ(-1, rename(file1_s2d1, dir_s1d2));
3208 	ASSERT_EQ(EISDIR, errno);
3209 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d1));
3210 	ASSERT_EQ(ENOTDIR, errno);
3211 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
3212 	ASSERT_EQ(ENOTDIR, errno);
3213 	ASSERT_EQ(0, unlink(file1_s2d1));
3214 	ASSERT_EQ(0, unlink(file1_s1d3));
3215 	ASSERT_EQ(0, unlink(file2_s1d3));
3216 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d1));
3217 
3218 	/* Effectively removes a file and a directory by exchanging them. */
3219 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
3220 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
3221 			       RENAME_EXCHANGE));
3222 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
3223 				RENAME_EXCHANGE));
3224 	ASSERT_EQ(EACCES, errno);
3225 }
3226 
TEST_F_FORK(layout1,reparent_dom_superset)3227 TEST_F_FORK(layout1, reparent_dom_superset)
3228 {
3229 	const struct rule layer1[] = {
3230 		{
3231 			.path = dir_s1d2,
3232 			.access = LANDLOCK_ACCESS_FS_REFER,
3233 		},
3234 		{
3235 			.path = file1_s1d2,
3236 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
3237 		},
3238 		{
3239 			.path = dir_s1d3,
3240 			.access = LANDLOCK_ACCESS_FS_MAKE_SOCK |
3241 				  LANDLOCK_ACCESS_FS_EXECUTE,
3242 		},
3243 		{
3244 			.path = dir_s2d2,
3245 			.access = LANDLOCK_ACCESS_FS_REFER |
3246 				  LANDLOCK_ACCESS_FS_EXECUTE |
3247 				  LANDLOCK_ACCESS_FS_MAKE_SOCK,
3248 		},
3249 		{
3250 			.path = dir_s2d3,
3251 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3252 				  LANDLOCK_ACCESS_FS_MAKE_FIFO,
3253 		},
3254 		{},
3255 	};
3256 	int ruleset_fd = create_ruleset(_metadata,
3257 					LANDLOCK_ACCESS_FS_REFER |
3258 						LANDLOCK_ACCESS_FS_EXECUTE |
3259 						LANDLOCK_ACCESS_FS_MAKE_SOCK |
3260 						LANDLOCK_ACCESS_FS_READ_FILE |
3261 						LANDLOCK_ACCESS_FS_MAKE_FIFO,
3262 					layer1);
3263 
3264 	ASSERT_LE(0, ruleset_fd);
3265 	enforce_ruleset(_metadata, ruleset_fd);
3266 	ASSERT_EQ(0, close(ruleset_fd));
3267 
3268 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d1));
3269 	ASSERT_EQ(EXDEV, errno);
3270 	/*
3271 	 * Moving file1_s1d2 beneath dir_s2d3 would grant it the READ_FILE
3272 	 * access right.
3273 	 */
3274 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d3));
3275 	ASSERT_EQ(EXDEV, errno);
3276 	/*
3277 	 * Moving file1_s1d2 should be allowed even if dir_s2d2 grants a
3278 	 * superset of access rights compared to dir_s1d2, because file1_s1d2
3279 	 * already has these access rights anyway.
3280 	 */
3281 	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d2));
3282 	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d2));
3283 
3284 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
3285 	ASSERT_EQ(EXDEV, errno);
3286 	/*
3287 	 * Moving dir_s1d3 beneath dir_s2d3 would grant it the MAKE_FIFO access
3288 	 * right.
3289 	 */
3290 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
3291 	ASSERT_EQ(EXDEV, errno);
3292 	/*
3293 	 * Moving dir_s1d3 should be allowed even if dir_s2d2 grants a superset
3294 	 * of access rights compared to dir_s1d2, because dir_s1d3 already has
3295 	 * these access rights anyway.
3296 	 */
3297 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
3298 	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
3299 
3300 	/*
3301 	 * Moving file1_s2d3 beneath dir_s1d2 is allowed, but moving it back
3302 	 * will be denied because the new inherited access rights from dir_s1d2
3303 	 * will be less than the destination (original) dir_s2d3.  This is a
3304 	 * sinkhole scenario where we cannot move back files or directories.
3305 	 */
3306 	ASSERT_EQ(0, rename(file1_s2d3, file2_s1d2));
3307 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
3308 	ASSERT_EQ(EXDEV, errno);
3309 	ASSERT_EQ(0, unlink(file2_s1d2));
3310 	ASSERT_EQ(0, unlink(file2_s2d3));
3311 	/*
3312 	 * Checks similar directory one-way move: dir_s2d3 loses EXECUTE and
3313 	 * MAKE_SOCK which were inherited from dir_s1d3.
3314 	 */
3315 	ASSERT_EQ(0, rename(dir_s2d3, file2_s1d2));
3316 	ASSERT_EQ(-1, rename(file2_s1d2, dir_s2d3));
3317 	ASSERT_EQ(EXDEV, errno);
3318 }
3319 
TEST_F_FORK(layout1,remove_dir)3320 TEST_F_FORK(layout1, remove_dir)
3321 {
3322 	const struct rule rules[] = {
3323 		{
3324 			.path = dir_s1d2,
3325 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
3326 		},
3327 		{},
3328 	};
3329 	const int ruleset_fd =
3330 		create_ruleset(_metadata, rules[0].access, rules);
3331 
3332 	ASSERT_LE(0, ruleset_fd);
3333 
3334 	ASSERT_EQ(0, unlink(file1_s1d1));
3335 	ASSERT_EQ(0, unlink(file1_s1d2));
3336 	ASSERT_EQ(0, unlink(file1_s1d3));
3337 	ASSERT_EQ(0, unlink(file2_s1d3));
3338 
3339 	enforce_ruleset(_metadata, ruleset_fd);
3340 	ASSERT_EQ(0, close(ruleset_fd));
3341 
3342 	ASSERT_EQ(0, rmdir(dir_s1d3));
3343 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
3344 	ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
3345 
3346 	/* dir_s1d2 itself cannot be removed. */
3347 	ASSERT_EQ(-1, rmdir(dir_s1d2));
3348 	ASSERT_EQ(EACCES, errno);
3349 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR));
3350 	ASSERT_EQ(EACCES, errno);
3351 	ASSERT_EQ(-1, rmdir(dir_s1d1));
3352 	ASSERT_EQ(EACCES, errno);
3353 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR));
3354 	ASSERT_EQ(EACCES, errno);
3355 }
3356 
TEST_F_FORK(layout1,remove_file)3357 TEST_F_FORK(layout1, remove_file)
3358 {
3359 	const struct rule rules[] = {
3360 		{
3361 			.path = dir_s1d2,
3362 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
3363 		},
3364 		{},
3365 	};
3366 	const int ruleset_fd =
3367 		create_ruleset(_metadata, rules[0].access, rules);
3368 
3369 	ASSERT_LE(0, ruleset_fd);
3370 	enforce_ruleset(_metadata, ruleset_fd);
3371 	ASSERT_EQ(0, close(ruleset_fd));
3372 
3373 	ASSERT_EQ(-1, unlink(file1_s1d1));
3374 	ASSERT_EQ(EACCES, errno);
3375 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0));
3376 	ASSERT_EQ(EACCES, errno);
3377 	ASSERT_EQ(0, unlink(file1_s1d2));
3378 	ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0));
3379 }
3380 
test_make_file(struct __test_metadata * const _metadata,const __u64 access,const mode_t mode,const dev_t dev)3381 static void test_make_file(struct __test_metadata *const _metadata,
3382 			   const __u64 access, const mode_t mode,
3383 			   const dev_t dev)
3384 {
3385 	const struct rule rules[] = {
3386 		{
3387 			.path = dir_s1d2,
3388 			.access = access,
3389 		},
3390 		{},
3391 	};
3392 	const int ruleset_fd = create_ruleset(_metadata, access, rules);
3393 
3394 	ASSERT_LE(0, ruleset_fd);
3395 
3396 	ASSERT_EQ(0, unlink(file1_s1d1));
3397 	ASSERT_EQ(0, unlink(file2_s1d1));
3398 	ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev))
3399 	{
3400 		TH_LOG("Failed to make file \"%s\": %s", file2_s1d1,
3401 		       strerror(errno));
3402 	};
3403 
3404 	ASSERT_EQ(0, unlink(file1_s1d2));
3405 	ASSERT_EQ(0, unlink(file2_s1d2));
3406 
3407 	ASSERT_EQ(0, unlink(file1_s1d3));
3408 	ASSERT_EQ(0, unlink(file2_s1d3));
3409 
3410 	enforce_ruleset(_metadata, ruleset_fd);
3411 	ASSERT_EQ(0, close(ruleset_fd));
3412 
3413 	ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev));
3414 	ASSERT_EQ(EACCES, errno);
3415 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3416 	ASSERT_EQ(EACCES, errno);
3417 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3418 	ASSERT_EQ(EACCES, errno);
3419 
3420 	ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev))
3421 	{
3422 		TH_LOG("Failed to make file \"%s\": %s", file1_s1d2,
3423 		       strerror(errno));
3424 	};
3425 	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3426 	ASSERT_EQ(0, unlink(file2_s1d2));
3427 	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3428 
3429 	ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev));
3430 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3431 	ASSERT_EQ(0, unlink(file2_s1d3));
3432 	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3433 }
3434 
TEST_F_FORK(layout1,make_char)3435 TEST_F_FORK(layout1, make_char)
3436 {
3437 	/* Creates a /dev/null device. */
3438 	set_cap(_metadata, CAP_MKNOD);
3439 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR,
3440 		       makedev(1, 3));
3441 }
3442 
TEST_F_FORK(layout1,make_block)3443 TEST_F_FORK(layout1, make_block)
3444 {
3445 	/* Creates a /dev/loop0 device. */
3446 	set_cap(_metadata, CAP_MKNOD);
3447 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK,
3448 		       makedev(7, 0));
3449 }
3450 
TEST_F_FORK(layout1,make_reg_1)3451 TEST_F_FORK(layout1, make_reg_1)
3452 {
3453 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
3454 }
3455 
TEST_F_FORK(layout1,make_reg_2)3456 TEST_F_FORK(layout1, make_reg_2)
3457 {
3458 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
3459 }
3460 
TEST_F_FORK(layout1,make_sock)3461 TEST_F_FORK(layout1, make_sock)
3462 {
3463 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
3464 }
3465 
TEST_F_FORK(layout1,make_fifo)3466 TEST_F_FORK(layout1, make_fifo)
3467 {
3468 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
3469 }
3470 
TEST_F_FORK(layout1,make_sym)3471 TEST_F_FORK(layout1, make_sym)
3472 {
3473 	const struct rule rules[] = {
3474 		{
3475 			.path = dir_s1d2,
3476 			.access = LANDLOCK_ACCESS_FS_MAKE_SYM,
3477 		},
3478 		{},
3479 	};
3480 	const int ruleset_fd =
3481 		create_ruleset(_metadata, rules[0].access, rules);
3482 
3483 	ASSERT_LE(0, ruleset_fd);
3484 
3485 	ASSERT_EQ(0, unlink(file1_s1d1));
3486 	ASSERT_EQ(0, unlink(file2_s1d1));
3487 	ASSERT_EQ(0, symlink("none", file2_s1d1));
3488 
3489 	ASSERT_EQ(0, unlink(file1_s1d2));
3490 	ASSERT_EQ(0, unlink(file2_s1d2));
3491 
3492 	ASSERT_EQ(0, unlink(file1_s1d3));
3493 	ASSERT_EQ(0, unlink(file2_s1d3));
3494 
3495 	enforce_ruleset(_metadata, ruleset_fd);
3496 	ASSERT_EQ(0, close(ruleset_fd));
3497 
3498 	ASSERT_EQ(-1, symlink("none", file1_s1d1));
3499 	ASSERT_EQ(EACCES, errno);
3500 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3501 	ASSERT_EQ(EACCES, errno);
3502 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3503 	ASSERT_EQ(EACCES, errno);
3504 
3505 	ASSERT_EQ(0, symlink("none", file1_s1d2));
3506 	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3507 	ASSERT_EQ(0, unlink(file2_s1d2));
3508 	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3509 
3510 	ASSERT_EQ(0, symlink("none", file1_s1d3));
3511 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3512 	ASSERT_EQ(0, unlink(file2_s1d3));
3513 	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3514 }
3515 
TEST_F_FORK(layout1,make_dir)3516 TEST_F_FORK(layout1, make_dir)
3517 {
3518 	const struct rule rules[] = {
3519 		{
3520 			.path = dir_s1d2,
3521 			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
3522 		},
3523 		{},
3524 	};
3525 	const int ruleset_fd =
3526 		create_ruleset(_metadata, rules[0].access, rules);
3527 
3528 	ASSERT_LE(0, ruleset_fd);
3529 
3530 	ASSERT_EQ(0, unlink(file1_s1d1));
3531 	ASSERT_EQ(0, unlink(file1_s1d2));
3532 	ASSERT_EQ(0, unlink(file1_s1d3));
3533 
3534 	enforce_ruleset(_metadata, ruleset_fd);
3535 	ASSERT_EQ(0, close(ruleset_fd));
3536 
3537 	/* Uses file_* as directory names. */
3538 	ASSERT_EQ(-1, mkdir(file1_s1d1, 0700));
3539 	ASSERT_EQ(EACCES, errno);
3540 	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
3541 	ASSERT_EQ(0, mkdir(file1_s1d3, 0700));
3542 }
3543 
open_proc_fd(struct __test_metadata * const _metadata,const int fd,const int open_flags)3544 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd,
3545 			const int open_flags)
3546 {
3547 	static const char path_template[] = "/proc/self/fd/%d";
3548 	char procfd_path[sizeof(path_template) + 10];
3549 	const int procfd_path_size =
3550 		snprintf(procfd_path, sizeof(procfd_path), path_template, fd);
3551 
3552 	ASSERT_LT(procfd_path_size, sizeof(procfd_path));
3553 	return open(procfd_path, open_flags);
3554 }
3555 
TEST_F_FORK(layout1,proc_unlinked_file)3556 TEST_F_FORK(layout1, proc_unlinked_file)
3557 {
3558 	const struct rule rules[] = {
3559 		{
3560 			.path = file1_s1d2,
3561 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3562 		},
3563 		{},
3564 	};
3565 	int reg_fd, proc_fd;
3566 	const int ruleset_fd = create_ruleset(
3567 		_metadata,
3568 		LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE,
3569 		rules);
3570 
3571 	ASSERT_LE(0, ruleset_fd);
3572 	enforce_ruleset(_metadata, ruleset_fd);
3573 	ASSERT_EQ(0, close(ruleset_fd));
3574 
3575 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
3576 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
3577 	reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC);
3578 	ASSERT_LE(0, reg_fd);
3579 	ASSERT_EQ(0, unlink(file1_s1d2));
3580 
3581 	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC);
3582 	ASSERT_LE(0, proc_fd);
3583 	ASSERT_EQ(0, close(proc_fd));
3584 
3585 	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC);
3586 	ASSERT_EQ(-1, proc_fd)
3587 	{
3588 		TH_LOG("Successfully opened /proc/self/fd/%d: %s", reg_fd,
3589 		       strerror(errno));
3590 	}
3591 	ASSERT_EQ(EACCES, errno);
3592 
3593 	ASSERT_EQ(0, close(reg_fd));
3594 }
3595 
TEST_F_FORK(layout1,proc_pipe)3596 TEST_F_FORK(layout1, proc_pipe)
3597 {
3598 	int proc_fd;
3599 	int pipe_fds[2];
3600 	char buf = '\0';
3601 	const struct rule rules[] = {
3602 		{
3603 			.path = dir_s1d2,
3604 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3605 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3606 		},
3607 		{},
3608 	};
3609 	/* Limits read and write access to files tied to the filesystem. */
3610 	const int ruleset_fd =
3611 		create_ruleset(_metadata, rules[0].access, rules);
3612 
3613 	ASSERT_LE(0, ruleset_fd);
3614 	enforce_ruleset(_metadata, ruleset_fd);
3615 	ASSERT_EQ(0, close(ruleset_fd));
3616 
3617 	/* Checks enforcement for normal files. */
3618 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
3619 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
3620 
3621 	/* Checks access to pipes through FD. */
3622 	ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC));
3623 	ASSERT_EQ(1, write(pipe_fds[1], ".", 1))
3624 	{
3625 		TH_LOG("Failed to write in pipe: %s", strerror(errno));
3626 	}
3627 	ASSERT_EQ(1, read(pipe_fds[0], &buf, 1));
3628 	ASSERT_EQ('.', buf);
3629 
3630 	/* Checks write access to pipe through /proc/self/fd . */
3631 	proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC);
3632 	ASSERT_LE(0, proc_fd);
3633 	ASSERT_EQ(1, write(proc_fd, ".", 1))
3634 	{
3635 		TH_LOG("Failed to write through /proc/self/fd/%d: %s",
3636 		       pipe_fds[1], strerror(errno));
3637 	}
3638 	ASSERT_EQ(0, close(proc_fd));
3639 
3640 	/* Checks read access to pipe through /proc/self/fd . */
3641 	proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC);
3642 	ASSERT_LE(0, proc_fd);
3643 	buf = '\0';
3644 	ASSERT_EQ(1, read(proc_fd, &buf, 1))
3645 	{
3646 		TH_LOG("Failed to read through /proc/self/fd/%d: %s",
3647 		       pipe_fds[1], strerror(errno));
3648 	}
3649 	ASSERT_EQ(0, close(proc_fd));
3650 
3651 	ASSERT_EQ(0, close(pipe_fds[0]));
3652 	ASSERT_EQ(0, close(pipe_fds[1]));
3653 }
3654 
3655 /* Invokes truncate(2) and returns its errno or 0. */
test_truncate(const char * const path)3656 static int test_truncate(const char *const path)
3657 {
3658 	if (truncate(path, 10) < 0)
3659 		return errno;
3660 	return 0;
3661 }
3662 
3663 /*
3664  * Invokes creat(2) and returns its errno or 0.
3665  * Closes the opened file descriptor on success.
3666  */
test_creat(const char * const path)3667 static int test_creat(const char *const path)
3668 {
3669 	int fd = creat(path, 0600);
3670 
3671 	if (fd < 0)
3672 		return errno;
3673 
3674 	/*
3675 	 * Mixing error codes from close(2) and creat(2) should not lead to any
3676 	 * (access type) confusion for this test.
3677 	 */
3678 	if (close(fd) < 0)
3679 		return errno;
3680 	return 0;
3681 }
3682 
3683 /*
3684  * Exercises file truncation when it's not restricted,
3685  * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed.
3686  */
TEST_F_FORK(layout1,truncate_unhandled)3687 TEST_F_FORK(layout1, truncate_unhandled)
3688 {
3689 	const char *const file_r = file1_s1d1;
3690 	const char *const file_w = file2_s1d1;
3691 	const char *const file_none = file1_s1d2;
3692 	const struct rule rules[] = {
3693 		{
3694 			.path = file_r,
3695 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3696 		},
3697 		{
3698 			.path = file_w,
3699 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3700 		},
3701 		/* Implicitly: No rights for file_none. */
3702 		{},
3703 	};
3704 
3705 	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3706 			      LANDLOCK_ACCESS_FS_WRITE_FILE;
3707 	int ruleset_fd;
3708 
3709 	/* Enables Landlock. */
3710 	ruleset_fd = create_ruleset(_metadata, handled, rules);
3711 
3712 	ASSERT_LE(0, ruleset_fd);
3713 	enforce_ruleset(_metadata, ruleset_fd);
3714 	ASSERT_EQ(0, close(ruleset_fd));
3715 
3716 	/*
3717 	 * Checks read right: truncate and open with O_TRUNC work, unless the
3718 	 * file is attempted to be opened for writing.
3719 	 */
3720 	EXPECT_EQ(0, test_truncate(file_r));
3721 	EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC));
3722 	EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC));
3723 	EXPECT_EQ(EACCES, test_creat(file_r));
3724 
3725 	/*
3726 	 * Checks write right: truncate and open with O_TRUNC work, unless the
3727 	 * file is attempted to be opened for reading.
3728 	 */
3729 	EXPECT_EQ(0, test_truncate(file_w));
3730 	EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC));
3731 	EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC));
3732 	EXPECT_EQ(0, test_creat(file_w));
3733 
3734 	/*
3735 	 * Checks "no rights" case: truncate works but all open attempts fail,
3736 	 * including creat.
3737 	 */
3738 	EXPECT_EQ(0, test_truncate(file_none));
3739 	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3740 	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3741 	EXPECT_EQ(EACCES, test_creat(file_none));
3742 }
3743 
TEST_F_FORK(layout1,truncate)3744 TEST_F_FORK(layout1, truncate)
3745 {
3746 	const char *const file_rwt = file1_s1d1;
3747 	const char *const file_rw = file2_s1d1;
3748 	const char *const file_rt = file1_s1d2;
3749 	const char *const file_t = file2_s1d2;
3750 	const char *const file_none = file1_s1d3;
3751 	const char *const dir_t = dir_s2d1;
3752 	const char *const file_in_dir_t = file1_s2d1;
3753 	const char *const dir_w = dir_s3d1;
3754 	const char *const file_in_dir_w = file1_s3d1;
3755 	const struct rule rules[] = {
3756 		{
3757 			.path = file_rwt,
3758 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3759 				  LANDLOCK_ACCESS_FS_WRITE_FILE |
3760 				  LANDLOCK_ACCESS_FS_TRUNCATE,
3761 		},
3762 		{
3763 			.path = file_rw,
3764 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3765 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3766 		},
3767 		{
3768 			.path = file_rt,
3769 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3770 				  LANDLOCK_ACCESS_FS_TRUNCATE,
3771 		},
3772 		{
3773 			.path = file_t,
3774 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3775 		},
3776 		/* Implicitly: No access rights for file_none. */
3777 		{
3778 			.path = dir_t,
3779 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3780 		},
3781 		{
3782 			.path = dir_w,
3783 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3784 		},
3785 		{},
3786 	};
3787 	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3788 			      LANDLOCK_ACCESS_FS_WRITE_FILE |
3789 			      LANDLOCK_ACCESS_FS_TRUNCATE;
3790 	int ruleset_fd;
3791 
3792 	/* Enables Landlock. */
3793 	ruleset_fd = create_ruleset(_metadata, handled, rules);
3794 
3795 	ASSERT_LE(0, ruleset_fd);
3796 	enforce_ruleset(_metadata, ruleset_fd);
3797 	ASSERT_EQ(0, close(ruleset_fd));
3798 
3799 	/* Checks read, write and truncate rights: truncation works. */
3800 	EXPECT_EQ(0, test_truncate(file_rwt));
3801 	EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC));
3802 	EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC));
3803 
3804 	/* Checks read and write rights: no truncate variant works. */
3805 	EXPECT_EQ(EACCES, test_truncate(file_rw));
3806 	EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC));
3807 	EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC));
3808 
3809 	/*
3810 	 * Checks read and truncate rights: truncation works.
3811 	 *
3812 	 * Note: Files can get truncated using open() even with O_RDONLY.
3813 	 */
3814 	EXPECT_EQ(0, test_truncate(file_rt));
3815 	EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC));
3816 	EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC));
3817 
3818 	/* Checks truncate right: truncate works, but can't open file. */
3819 	EXPECT_EQ(0, test_truncate(file_t));
3820 	EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC));
3821 	EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC));
3822 
3823 	/* Checks "no rights" case: No form of truncation works. */
3824 	EXPECT_EQ(EACCES, test_truncate(file_none));
3825 	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3826 	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3827 
3828 	/*
3829 	 * Checks truncate right on directory: truncate works on contained
3830 	 * files.
3831 	 */
3832 	EXPECT_EQ(0, test_truncate(file_in_dir_t));
3833 	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC));
3834 	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC));
3835 
3836 	/*
3837 	 * Checks creat in dir_w: This requires the truncate right when
3838 	 * overwriting an existing file, but does not require it when the file
3839 	 * is new.
3840 	 */
3841 	EXPECT_EQ(EACCES, test_creat(file_in_dir_w));
3842 
3843 	ASSERT_EQ(0, unlink(file_in_dir_w));
3844 	EXPECT_EQ(0, test_creat(file_in_dir_w));
3845 }
3846 
3847 /* Invokes ftruncate(2) and returns its errno or 0. */
test_ftruncate(int fd)3848 static int test_ftruncate(int fd)
3849 {
3850 	if (ftruncate(fd, 10) < 0)
3851 		return errno;
3852 	return 0;
3853 }
3854 
TEST_F_FORK(layout1,ftruncate)3855 TEST_F_FORK(layout1, ftruncate)
3856 {
3857 	/*
3858 	 * This test opens a new file descriptor at different stages of
3859 	 * Landlock restriction:
3860 	 *
3861 	 * without restriction:                    ftruncate works
3862 	 * something else but truncate restricted: ftruncate works
3863 	 * truncate restricted and permitted:      ftruncate works
3864 	 * truncate restricted and not permitted:  ftruncate fails
3865 	 *
3866 	 * Whether this works or not is expected to depend on the time when the
3867 	 * FD was opened, not to depend on the time when ftruncate() was
3868 	 * called.
3869 	 */
3870 	const char *const path = file1_s1d1;
3871 	const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE |
3872 			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3873 	const struct rule layer1[] = {
3874 		{
3875 			.path = path,
3876 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3877 		},
3878 		{},
3879 	};
3880 	const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE;
3881 	const struct rule layer2[] = {
3882 		{
3883 			.path = path,
3884 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3885 		},
3886 		{},
3887 	};
3888 	const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE |
3889 			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3890 	const struct rule layer3[] = {
3891 		{
3892 			.path = path,
3893 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3894 		},
3895 		{},
3896 	};
3897 	int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd;
3898 
3899 	fd_layer0 = open(path, O_WRONLY);
3900 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3901 
3902 	ruleset_fd = create_ruleset(_metadata, handled1, layer1);
3903 	ASSERT_LE(0, ruleset_fd);
3904 	enforce_ruleset(_metadata, ruleset_fd);
3905 	ASSERT_EQ(0, close(ruleset_fd));
3906 
3907 	fd_layer1 = open(path, O_WRONLY);
3908 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3909 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3910 
3911 	ruleset_fd = create_ruleset(_metadata, handled2, layer2);
3912 	ASSERT_LE(0, ruleset_fd);
3913 	enforce_ruleset(_metadata, ruleset_fd);
3914 	ASSERT_EQ(0, close(ruleset_fd));
3915 
3916 	fd_layer2 = open(path, O_WRONLY);
3917 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3918 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3919 	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3920 
3921 	ruleset_fd = create_ruleset(_metadata, handled3, layer3);
3922 	ASSERT_LE(0, ruleset_fd);
3923 	enforce_ruleset(_metadata, ruleset_fd);
3924 	ASSERT_EQ(0, close(ruleset_fd));
3925 
3926 	fd_layer3 = open(path, O_WRONLY);
3927 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3928 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3929 	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3930 	EXPECT_EQ(EACCES, test_ftruncate(fd_layer3));
3931 
3932 	ASSERT_EQ(0, close(fd_layer0));
3933 	ASSERT_EQ(0, close(fd_layer1));
3934 	ASSERT_EQ(0, close(fd_layer2));
3935 	ASSERT_EQ(0, close(fd_layer3));
3936 }
3937 
3938 /* clang-format off */
FIXTURE(ftruncate)3939 FIXTURE(ftruncate) {};
3940 /* clang-format on */
3941 
FIXTURE_SETUP(ftruncate)3942 FIXTURE_SETUP(ftruncate)
3943 {
3944 	prepare_layout(_metadata);
3945 	create_file(_metadata, file1_s1d1);
3946 }
3947 
FIXTURE_TEARDOWN_PARENT(ftruncate)3948 FIXTURE_TEARDOWN_PARENT(ftruncate)
3949 {
3950 	EXPECT_EQ(0, remove_path(file1_s1d1));
3951 	cleanup_layout(_metadata);
3952 }
3953 
FIXTURE_VARIANT(ftruncate)3954 FIXTURE_VARIANT(ftruncate)
3955 {
3956 	const __u64 handled;
3957 	const __u64 allowed;
3958 	const int expected_open_result;
3959 	const int expected_ftruncate_result;
3960 };
3961 
3962 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,w_w)3963 FIXTURE_VARIANT_ADD(ftruncate, w_w) {
3964 	/* clang-format on */
3965 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE,
3966 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
3967 	.expected_open_result = 0,
3968 	.expected_ftruncate_result = 0,
3969 };
3970 
3971 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,t_t)3972 FIXTURE_VARIANT_ADD(ftruncate, t_t) {
3973 	/* clang-format on */
3974 	.handled = LANDLOCK_ACCESS_FS_TRUNCATE,
3975 	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
3976 	.expected_open_result = 0,
3977 	.expected_ftruncate_result = 0,
3978 };
3979 
3980 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_w)3981 FIXTURE_VARIANT_ADD(ftruncate, wt_w) {
3982 	/* clang-format on */
3983 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3984 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
3985 	.expected_open_result = 0,
3986 	.expected_ftruncate_result = EACCES,
3987 };
3988 
3989 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_wt)3990 FIXTURE_VARIANT_ADD(ftruncate, wt_wt) {
3991 	/* clang-format on */
3992 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3993 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3994 	.expected_open_result = 0,
3995 	.expected_ftruncate_result = 0,
3996 };
3997 
3998 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_t)3999 FIXTURE_VARIANT_ADD(ftruncate, wt_t) {
4000 	/* clang-format on */
4001 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
4002 	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
4003 	.expected_open_result = EACCES,
4004 };
4005 
TEST_F_FORK(ftruncate,open_and_ftruncate)4006 TEST_F_FORK(ftruncate, open_and_ftruncate)
4007 {
4008 	const char *const path = file1_s1d1;
4009 	const struct rule rules[] = {
4010 		{
4011 			.path = path,
4012 			.access = variant->allowed,
4013 		},
4014 		{},
4015 	};
4016 	int fd, ruleset_fd;
4017 
4018 	/* Enables Landlock. */
4019 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4020 	ASSERT_LE(0, ruleset_fd);
4021 	enforce_ruleset(_metadata, ruleset_fd);
4022 	ASSERT_EQ(0, close(ruleset_fd));
4023 
4024 	fd = open(path, O_WRONLY);
4025 	EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
4026 	if (fd >= 0) {
4027 		EXPECT_EQ(variant->expected_ftruncate_result,
4028 			  test_ftruncate(fd));
4029 		ASSERT_EQ(0, close(fd));
4030 	}
4031 }
4032 
TEST_F_FORK(ftruncate,open_and_ftruncate_in_different_processes)4033 TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
4034 {
4035 	int child, fd, status;
4036 	int socket_fds[2];
4037 
4038 	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
4039 				socket_fds));
4040 
4041 	child = fork();
4042 	ASSERT_LE(0, child);
4043 	if (child == 0) {
4044 		/*
4045 		 * Enables Landlock in the child process, open a file descriptor
4046 		 * where truncation is forbidden and send it to the
4047 		 * non-landlocked parent process.
4048 		 */
4049 		const char *const path = file1_s1d1;
4050 		const struct rule rules[] = {
4051 			{
4052 				.path = path,
4053 				.access = variant->allowed,
4054 			},
4055 			{},
4056 		};
4057 		int fd, ruleset_fd;
4058 
4059 		ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4060 		ASSERT_LE(0, ruleset_fd);
4061 		enforce_ruleset(_metadata, ruleset_fd);
4062 		ASSERT_EQ(0, close(ruleset_fd));
4063 
4064 		fd = open(path, O_WRONLY);
4065 		ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
4066 
4067 		if (fd >= 0) {
4068 			ASSERT_EQ(0, send_fd(socket_fds[0], fd));
4069 			ASSERT_EQ(0, close(fd));
4070 		}
4071 
4072 		ASSERT_EQ(0, close(socket_fds[0]));
4073 
4074 		_exit(_metadata->exit_code);
4075 		return;
4076 	}
4077 
4078 	if (variant->expected_open_result == 0) {
4079 		fd = recv_fd(socket_fds[1]);
4080 		ASSERT_LE(0, fd);
4081 
4082 		EXPECT_EQ(variant->expected_ftruncate_result,
4083 			  test_ftruncate(fd));
4084 		ASSERT_EQ(0, close(fd));
4085 	}
4086 
4087 	ASSERT_EQ(child, waitpid(child, &status, 0));
4088 	ASSERT_EQ(1, WIFEXITED(status));
4089 	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
4090 
4091 	ASSERT_EQ(0, close(socket_fds[0]));
4092 	ASSERT_EQ(0, close(socket_fds[1]));
4093 }
4094 
4095 /* Invokes the FS_IOC_GETFLAGS IOCTL and returns its errno or 0. */
test_fs_ioc_getflags_ioctl(int fd)4096 static int test_fs_ioc_getflags_ioctl(int fd)
4097 {
4098 	uint32_t flags;
4099 
4100 	if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0)
4101 		return errno;
4102 	return 0;
4103 }
4104 
TEST(memfd_ftruncate_and_ioctl)4105 TEST(memfd_ftruncate_and_ioctl)
4106 {
4107 	const struct landlock_ruleset_attr attr = {
4108 		.handled_access_fs = ACCESS_ALL,
4109 	};
4110 	int ruleset_fd, fd, i;
4111 
4112 	/*
4113 	 * We exercise the same test both with and without Landlock enabled, to
4114 	 * ensure that it behaves the same in both cases.
4115 	 */
4116 	for (i = 0; i < 2; i++) {
4117 		/* Creates a new memfd. */
4118 		fd = memfd_create("name", MFD_CLOEXEC);
4119 		ASSERT_LE(0, fd);
4120 
4121 		/*
4122 		 * Checks that operations associated with the opened file
4123 		 * (ftruncate, ioctl) are permitted on file descriptors that are
4124 		 * created in ways other than open(2).
4125 		 */
4126 		EXPECT_EQ(0, test_ftruncate(fd));
4127 		EXPECT_EQ(0, test_fs_ioc_getflags_ioctl(fd));
4128 
4129 		ASSERT_EQ(0, close(fd));
4130 
4131 		/* Enables Landlock. */
4132 		ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4133 		ASSERT_LE(0, ruleset_fd);
4134 		enforce_ruleset(_metadata, ruleset_fd);
4135 		ASSERT_EQ(0, close(ruleset_fd));
4136 	}
4137 }
4138 
test_fionread_ioctl(int fd)4139 static int test_fionread_ioctl(int fd)
4140 {
4141 	size_t sz = 0;
4142 
4143 	if (ioctl(fd, FIONREAD, &sz) < 0 && errno == EACCES)
4144 		return errno;
4145 	return 0;
4146 }
4147 
TEST_F_FORK(layout1,o_path_ftruncate_and_ioctl)4148 TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl)
4149 {
4150 	const struct landlock_ruleset_attr attr = {
4151 		.handled_access_fs = ACCESS_ALL,
4152 	};
4153 	int ruleset_fd, fd;
4154 
4155 	/*
4156 	 * Checks that for files opened with O_PATH, both ioctl(2) and
4157 	 * ftruncate(2) yield EBADF, as it is documented in open(2) for the
4158 	 * O_PATH flag.
4159 	 */
4160 	fd = open(dir_s1d1, O_PATH | O_CLOEXEC);
4161 	ASSERT_LE(0, fd);
4162 
4163 	EXPECT_EQ(EBADF, test_ftruncate(fd));
4164 	EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd));
4165 
4166 	ASSERT_EQ(0, close(fd));
4167 
4168 	/* Enables Landlock. */
4169 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4170 	ASSERT_LE(0, ruleset_fd);
4171 	enforce_ruleset(_metadata, ruleset_fd);
4172 	ASSERT_EQ(0, close(ruleset_fd));
4173 
4174 	/*
4175 	 * Checks that after enabling Landlock,
4176 	 * - the file can still be opened with O_PATH
4177 	 * - both ioctl and truncate still yield EBADF (not EACCES).
4178 	 */
4179 	fd = open(dir_s1d1, O_PATH | O_CLOEXEC);
4180 	ASSERT_LE(0, fd);
4181 
4182 	EXPECT_EQ(EBADF, test_ftruncate(fd));
4183 	EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd));
4184 
4185 	ASSERT_EQ(0, close(fd));
4186 }
4187 
4188 /*
4189  * ioctl_error - generically call the given ioctl with a pointer to a
4190  * sufficiently large zeroed-out memory region.
4191  *
4192  * Returns the IOCTLs error, or 0.
4193  */
ioctl_error(struct __test_metadata * const _metadata,int fd,unsigned int cmd)4194 static int ioctl_error(struct __test_metadata *const _metadata, int fd,
4195 		       unsigned int cmd)
4196 {
4197 	char buf[128]; /* sufficiently large */
4198 	int res, stdinbak_fd;
4199 
4200 	/*
4201 	 * Depending on the IOCTL command, parts of the zeroed-out buffer might
4202 	 * be interpreted as file descriptor numbers.  We do not want to
4203 	 * accidentally operate on file descriptor 0 (stdin), so we temporarily
4204 	 * move stdin to a different FD and close FD 0 for the IOCTL call.
4205 	 */
4206 	stdinbak_fd = dup(0);
4207 	ASSERT_LT(0, stdinbak_fd);
4208 	ASSERT_EQ(0, close(0));
4209 
4210 	/* Invokes the IOCTL with a zeroed-out buffer. */
4211 	bzero(&buf, sizeof(buf));
4212 	res = ioctl(fd, cmd, &buf);
4213 
4214 	/* Restores the old FD 0 and closes the backup FD. */
4215 	ASSERT_EQ(0, dup2(stdinbak_fd, 0));
4216 	ASSERT_EQ(0, close(stdinbak_fd));
4217 
4218 	if (res < 0)
4219 		return errno;
4220 
4221 	return 0;
4222 }
4223 
4224 /* Define some linux/falloc.h IOCTL commands which are not available in uapi headers. */
4225 struct space_resv {
4226 	__s16 l_type;
4227 	__s16 l_whence;
4228 	__s64 l_start;
4229 	__s64 l_len; /* len == 0 means until end of file */
4230 	__s32 l_sysid;
4231 	__u32 l_pid;
4232 	__s32 l_pad[4]; /* reserved area */
4233 };
4234 
4235 #define FS_IOC_RESVSP _IOW('X', 40, struct space_resv)
4236 #define FS_IOC_UNRESVSP _IOW('X', 41, struct space_resv)
4237 #define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv)
4238 #define FS_IOC_UNRESVSP64 _IOW('X', 43, struct space_resv)
4239 #define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv)
4240 
4241 /*
4242  * Tests a series of blanket-permitted and denied IOCTLs.
4243  */
TEST_F_FORK(layout1,blanket_permitted_ioctls)4244 TEST_F_FORK(layout1, blanket_permitted_ioctls)
4245 {
4246 	const struct landlock_ruleset_attr attr = {
4247 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4248 	};
4249 	int ruleset_fd, fd;
4250 
4251 	/* Enables Landlock. */
4252 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4253 	ASSERT_LE(0, ruleset_fd);
4254 	enforce_ruleset(_metadata, ruleset_fd);
4255 	ASSERT_EQ(0, close(ruleset_fd));
4256 
4257 	fd = open("/dev/null", O_RDWR | O_CLOEXEC);
4258 	ASSERT_LE(0, fd);
4259 
4260 	/*
4261 	 * Checks permitted commands.
4262 	 * These ones may return errors, but should not be blocked by Landlock.
4263 	 */
4264 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOCLEX));
4265 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONCLEX));
4266 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONBIO));
4267 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOASYNC));
4268 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOQSIZE));
4269 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIFREEZE));
4270 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FITHAW));
4271 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_FIEMAP));
4272 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIGETBSZ));
4273 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONE));
4274 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONERANGE));
4275 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIDEDUPERANGE));
4276 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSUUID));
4277 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSSYSFSPATH));
4278 
4279 	/*
4280 	 * Checks blocked commands.
4281 	 * A call to a blocked IOCTL command always returns EACCES.
4282 	 */
4283 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
4284 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFLAGS));
4285 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_SETFLAGS));
4286 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSGETXATTR));
4287 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSSETXATTR));
4288 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIBMAP));
4289 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP));
4290 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP64));
4291 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP));
4292 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP64));
4293 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_ZERO_RANGE));
4294 
4295 	/* Default case is also blocked. */
4296 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, 0xc00ffeee));
4297 
4298 	ASSERT_EQ(0, close(fd));
4299 }
4300 
4301 /*
4302  * Named pipes are not governed by the LANDLOCK_ACCESS_FS_IOCTL_DEV right,
4303  * because they are not character or block devices.
4304  */
TEST_F_FORK(layout1,named_pipe_ioctl)4305 TEST_F_FORK(layout1, named_pipe_ioctl)
4306 {
4307 	pid_t child_pid;
4308 	int fd, ruleset_fd;
4309 	const char *const path = file1_s1d1;
4310 	const struct landlock_ruleset_attr attr = {
4311 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4312 	};
4313 
4314 	ASSERT_EQ(0, unlink(path));
4315 	ASSERT_EQ(0, mkfifo(path, 0600));
4316 
4317 	/* Enables Landlock. */
4318 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4319 	ASSERT_LE(0, ruleset_fd);
4320 	enforce_ruleset(_metadata, ruleset_fd);
4321 	ASSERT_EQ(0, close(ruleset_fd));
4322 
4323 	/* The child process opens the pipe for writing. */
4324 	child_pid = fork();
4325 	ASSERT_NE(-1, child_pid);
4326 	if (child_pid == 0) {
4327 		fd = open(path, O_WRONLY);
4328 		close(fd);
4329 		exit(0);
4330 	}
4331 
4332 	fd = open(path, O_RDONLY);
4333 	ASSERT_LE(0, fd);
4334 
4335 	/* FIONREAD is implemented by pipefifo_fops. */
4336 	EXPECT_EQ(0, test_fionread_ioctl(fd));
4337 
4338 	ASSERT_EQ(0, close(fd));
4339 	ASSERT_EQ(0, unlink(path));
4340 
4341 	ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
4342 }
4343 
4344 /* For named UNIX domain sockets, no IOCTL restrictions apply. */
TEST_F_FORK(layout1,named_unix_domain_socket_ioctl)4345 TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
4346 {
4347 	const char *const path = file1_s1d1;
4348 	int srv_fd, cli_fd, ruleset_fd;
4349 	socklen_t size;
4350 	struct sockaddr_un srv_un, cli_un;
4351 	const struct landlock_ruleset_attr attr = {
4352 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4353 	};
4354 
4355 	/* Sets up a server */
4356 	srv_un.sun_family = AF_UNIX;
4357 	strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path));
4358 
4359 	ASSERT_EQ(0, unlink(path));
4360 	srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4361 	ASSERT_LE(0, srv_fd);
4362 
4363 	size = offsetof(struct sockaddr_un, sun_path) + strlen(srv_un.sun_path);
4364 	ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, size));
4365 	ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */));
4366 
4367 	/* Enables Landlock. */
4368 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4369 	ASSERT_LE(0, ruleset_fd);
4370 	enforce_ruleset(_metadata, ruleset_fd);
4371 	ASSERT_EQ(0, close(ruleset_fd));
4372 
4373 	/* Sets up a client connection to it */
4374 	cli_un.sun_family = AF_UNIX;
4375 	cli_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4376 	ASSERT_LE(0, cli_fd);
4377 
4378 	size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path);
4379 	ASSERT_EQ(0, bind(cli_fd, (struct sockaddr *)&cli_un, size));
4380 
4381 	bzero(&cli_un, sizeof(cli_un));
4382 	cli_un.sun_family = AF_UNIX;
4383 	strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path));
4384 	size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path);
4385 
4386 	ASSERT_EQ(0, connect(cli_fd, (struct sockaddr *)&cli_un, size));
4387 
4388 	/* FIONREAD and other IOCTLs should not be forbidden. */
4389 	EXPECT_EQ(0, test_fionread_ioctl(cli_fd));
4390 
4391 	ASSERT_EQ(0, close(cli_fd));
4392 }
4393 
4394 /* clang-format off */
FIXTURE(ioctl)4395 FIXTURE(ioctl) {};
4396 
FIXTURE_SETUP(ioctl)4397 FIXTURE_SETUP(ioctl) {};
4398 
FIXTURE_TEARDOWN(ioctl)4399 FIXTURE_TEARDOWN(ioctl) {};
4400 /* clang-format on */
4401 
FIXTURE_VARIANT(ioctl)4402 FIXTURE_VARIANT(ioctl)
4403 {
4404 	const __u64 handled;
4405 	const __u64 allowed;
4406 	const mode_t open_mode;
4407 	/*
4408 	 * FIONREAD is used as a characteristic device-specific IOCTL command.
4409 	 * It is implemented in fs/ioctl.c for regular files,
4410 	 * but we do not blanket-permit it for devices.
4411 	 */
4412 	const int expected_fionread_result;
4413 };
4414 
4415 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,handled_i_allowed_none)4416 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_none) {
4417 	/* clang-format on */
4418 	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4419 	.allowed = 0,
4420 	.open_mode = O_RDWR,
4421 	.expected_fionread_result = EACCES,
4422 };
4423 
4424 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,handled_i_allowed_i)4425 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_i) {
4426 	/* clang-format on */
4427 	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4428 	.allowed = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4429 	.open_mode = O_RDWR,
4430 	.expected_fionread_result = 0,
4431 };
4432 
4433 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,unhandled)4434 FIXTURE_VARIANT_ADD(ioctl, unhandled) {
4435 	/* clang-format on */
4436 	.handled = LANDLOCK_ACCESS_FS_EXECUTE,
4437 	.allowed = LANDLOCK_ACCESS_FS_EXECUTE,
4438 	.open_mode = O_RDWR,
4439 	.expected_fionread_result = 0,
4440 };
4441 
TEST_F_FORK(ioctl,handle_dir_access_file)4442 TEST_F_FORK(ioctl, handle_dir_access_file)
4443 {
4444 	const int flag = 0;
4445 	const struct rule rules[] = {
4446 		{
4447 			.path = "/dev",
4448 			.access = variant->allowed,
4449 		},
4450 		{},
4451 	};
4452 	int file_fd, ruleset_fd;
4453 
4454 	/* Enables Landlock. */
4455 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4456 	ASSERT_LE(0, ruleset_fd);
4457 	enforce_ruleset(_metadata, ruleset_fd);
4458 	ASSERT_EQ(0, close(ruleset_fd));
4459 
4460 	file_fd = open("/dev/zero", variant->open_mode);
4461 	ASSERT_LE(0, file_fd);
4462 
4463 	/* Checks that IOCTL commands return the expected errors. */
4464 	EXPECT_EQ(variant->expected_fionread_result,
4465 		  test_fionread_ioctl(file_fd));
4466 
4467 	/* Checks that unrestrictable commands are unrestricted. */
4468 	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4469 	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4470 	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4471 	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4472 	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4473 
4474 	ASSERT_EQ(0, close(file_fd));
4475 }
4476 
TEST_F_FORK(ioctl,handle_dir_access_dir)4477 TEST_F_FORK(ioctl, handle_dir_access_dir)
4478 {
4479 	const int flag = 0;
4480 	const struct rule rules[] = {
4481 		{
4482 			.path = "/dev",
4483 			.access = variant->allowed,
4484 		},
4485 		{},
4486 	};
4487 	int dir_fd, ruleset_fd;
4488 
4489 	/* Enables Landlock. */
4490 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4491 	ASSERT_LE(0, ruleset_fd);
4492 	enforce_ruleset(_metadata, ruleset_fd);
4493 	ASSERT_EQ(0, close(ruleset_fd));
4494 
4495 	/*
4496 	 * Ignore variant->open_mode for this test, as we intend to open a
4497 	 * directory.  If the directory can not be opened, the variant is
4498 	 * infeasible to test with an opened directory.
4499 	 */
4500 	dir_fd = open("/dev", O_RDONLY);
4501 	if (dir_fd < 0)
4502 		return;
4503 
4504 	/*
4505 	 * Checks that IOCTL commands return the expected errors.
4506 	 * We do not use the expected values from the fixture here.
4507 	 *
4508 	 * When using IOCTL on a directory, no Landlock restrictions apply.
4509 	 */
4510 	EXPECT_EQ(0, test_fionread_ioctl(dir_fd));
4511 
4512 	/* Checks that unrestrictable commands are unrestricted. */
4513 	EXPECT_EQ(0, ioctl(dir_fd, FIOCLEX));
4514 	EXPECT_EQ(0, ioctl(dir_fd, FIONCLEX));
4515 	EXPECT_EQ(0, ioctl(dir_fd, FIONBIO, &flag));
4516 	EXPECT_EQ(0, ioctl(dir_fd, FIOASYNC, &flag));
4517 	EXPECT_EQ(0, ioctl(dir_fd, FIGETBSZ, &flag));
4518 
4519 	ASSERT_EQ(0, close(dir_fd));
4520 }
4521 
TEST_F_FORK(ioctl,handle_file_access_file)4522 TEST_F_FORK(ioctl, handle_file_access_file)
4523 {
4524 	const int flag = 0;
4525 	const struct rule rules[] = {
4526 		{
4527 			.path = "/dev/zero",
4528 			.access = variant->allowed,
4529 		},
4530 		{},
4531 	};
4532 	int file_fd, ruleset_fd;
4533 
4534 	/* Enables Landlock. */
4535 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4536 	ASSERT_LE(0, ruleset_fd);
4537 	enforce_ruleset(_metadata, ruleset_fd);
4538 	ASSERT_EQ(0, close(ruleset_fd));
4539 
4540 	file_fd = open("/dev/zero", variant->open_mode);
4541 	ASSERT_LE(0, file_fd)
4542 	{
4543 		TH_LOG("Failed to open /dev/zero: %s", strerror(errno));
4544 	}
4545 
4546 	/* Checks that IOCTL commands return the expected errors. */
4547 	EXPECT_EQ(variant->expected_fionread_result,
4548 		  test_fionread_ioctl(file_fd));
4549 
4550 	/* Checks that unrestrictable commands are unrestricted. */
4551 	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4552 	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4553 	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4554 	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4555 	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4556 
4557 	ASSERT_EQ(0, close(file_fd));
4558 }
4559 
4560 /* clang-format off */
FIXTURE(layout1_bind)4561 FIXTURE(layout1_bind) {};
4562 /* clang-format on */
4563 
FIXTURE_SETUP(layout1_bind)4564 FIXTURE_SETUP(layout1_bind)
4565 {
4566 	prepare_layout(_metadata);
4567 
4568 	create_layout1(_metadata);
4569 
4570 	set_cap(_metadata, CAP_SYS_ADMIN);
4571 	ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL));
4572 	clear_cap(_metadata, CAP_SYS_ADMIN);
4573 }
4574 
FIXTURE_TEARDOWN_PARENT(layout1_bind)4575 FIXTURE_TEARDOWN_PARENT(layout1_bind)
4576 {
4577 	/* umount(dir_s2d2)) is handled by namespace lifetime. */
4578 
4579 	remove_layout1(_metadata);
4580 
4581 	cleanup_layout(_metadata);
4582 }
4583 
4584 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
4585 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
4586 
4587 /*
4588  * layout1_bind hierarchy:
4589  *
4590  * tmp
4591  * ├── s1d1
4592  * │   ├── f1
4593  * │   ├── f2
4594  * │   └── s1d2
4595  * │       ├── f1
4596  * │       ├── f2
4597  * │       └── s1d3
4598  * │           ├── f1
4599  * │           └── f2
4600  * ├── s2d1
4601  * │   ├── f1
4602  * │   └── s2d2
4603  * │       ├── f1
4604  * │       ├── f2
4605  * │       └── s1d3
4606  * │           ├── f1
4607  * │           └── f2
4608  * └── s3d1
4609  *     └── s3d2
4610  *         └── s3d3
4611  */
4612 
TEST_F_FORK(layout1_bind,no_restriction)4613 TEST_F_FORK(layout1_bind, no_restriction)
4614 {
4615 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
4616 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4617 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
4618 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4619 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
4620 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4621 
4622 	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
4623 	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
4624 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
4625 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
4626 	ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY));
4627 	ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY));
4628 
4629 	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY));
4630 	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4631 
4632 	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
4633 }
4634 
TEST_F_FORK(layout1_bind,same_content_same_file)4635 TEST_F_FORK(layout1_bind, same_content_same_file)
4636 {
4637 	/*
4638 	 * Sets access right on parent directories of both source and
4639 	 * destination mount points.
4640 	 */
4641 	const struct rule layer1_parent[] = {
4642 		{
4643 			.path = dir_s1d1,
4644 			.access = ACCESS_RO,
4645 		},
4646 		{
4647 			.path = dir_s2d1,
4648 			.access = ACCESS_RW,
4649 		},
4650 		{},
4651 	};
4652 	/*
4653 	 * Sets access rights on the same bind-mounted directories.  The result
4654 	 * should be ACCESS_RW for both directories, but not both hierarchies
4655 	 * because of the first layer.
4656 	 */
4657 	const struct rule layer2_mount_point[] = {
4658 		{
4659 			.path = dir_s1d2,
4660 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4661 		},
4662 		{
4663 			.path = dir_s2d2,
4664 			.access = ACCESS_RW,
4665 		},
4666 		{},
4667 	};
4668 	/* Only allow read-access to the s1d3 hierarchies. */
4669 	const struct rule layer3_source[] = {
4670 		{
4671 			.path = dir_s1d3,
4672 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4673 		},
4674 		{},
4675 	};
4676 	/* Removes all access rights. */
4677 	const struct rule layer4_destination[] = {
4678 		{
4679 			.path = bind_file1_s1d3,
4680 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
4681 		},
4682 		{},
4683 	};
4684 	int ruleset_fd;
4685 
4686 	/* Sets rules for the parent directories. */
4687 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent);
4688 	ASSERT_LE(0, ruleset_fd);
4689 	enforce_ruleset(_metadata, ruleset_fd);
4690 	ASSERT_EQ(0, close(ruleset_fd));
4691 
4692 	/* Checks source hierarchy. */
4693 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4694 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4695 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4696 
4697 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4698 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4699 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4700 
4701 	/* Checks destination hierarchy. */
4702 	ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR));
4703 	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4704 
4705 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4706 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4707 
4708 	/* Sets rules for the mount points. */
4709 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point);
4710 	ASSERT_LE(0, ruleset_fd);
4711 	enforce_ruleset(_metadata, ruleset_fd);
4712 	ASSERT_EQ(0, close(ruleset_fd));
4713 
4714 	/* Checks source hierarchy. */
4715 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
4716 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4717 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4718 
4719 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4720 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4721 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4722 
4723 	/* Checks destination hierarchy. */
4724 	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY));
4725 	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY));
4726 	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4727 
4728 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4729 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4730 	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4731 
4732 	/* Sets a (shared) rule only on the source. */
4733 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source);
4734 	ASSERT_LE(0, ruleset_fd);
4735 	enforce_ruleset(_metadata, ruleset_fd);
4736 	ASSERT_EQ(0, close(ruleset_fd));
4737 
4738 	/* Checks source hierarchy. */
4739 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
4740 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4741 	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4742 
4743 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4744 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4745 	ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
4746 
4747 	/* Checks destination hierarchy. */
4748 	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY));
4749 	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY));
4750 	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4751 
4752 	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4753 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4754 	ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4755 
4756 	/* Sets a (shared) rule only on the destination. */
4757 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination);
4758 	ASSERT_LE(0, ruleset_fd);
4759 	enforce_ruleset(_metadata, ruleset_fd);
4760 	ASSERT_EQ(0, close(ruleset_fd));
4761 
4762 	/* Checks source hierarchy. */
4763 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
4764 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4765 
4766 	/* Checks destination hierarchy. */
4767 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY));
4768 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4769 }
4770 
TEST_F_FORK(layout1_bind,reparent_cross_mount)4771 TEST_F_FORK(layout1_bind, reparent_cross_mount)
4772 {
4773 	const struct rule layer1[] = {
4774 		{
4775 			/* dir_s2d1 is beneath the dir_s2d2 mount point. */
4776 			.path = dir_s2d1,
4777 			.access = LANDLOCK_ACCESS_FS_REFER,
4778 		},
4779 		{
4780 			.path = bind_dir_s1d3,
4781 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
4782 		},
4783 		{},
4784 	};
4785 	int ruleset_fd = create_ruleset(
4786 		_metadata,
4787 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1);
4788 
4789 	ASSERT_LE(0, ruleset_fd);
4790 	enforce_ruleset(_metadata, ruleset_fd);
4791 	ASSERT_EQ(0, close(ruleset_fd));
4792 
4793 	/* Checks basic denied move. */
4794 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2));
4795 	ASSERT_EQ(EXDEV, errno);
4796 
4797 	/* Checks real cross-mount move (Landlock is not involved). */
4798 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s2d2));
4799 	ASSERT_EQ(EXDEV, errno);
4800 
4801 	/* Checks move that will give more accesses. */
4802 	ASSERT_EQ(-1, rename(file1_s2d2, bind_file1_s1d3));
4803 	ASSERT_EQ(EXDEV, errno);
4804 
4805 	/* Checks legitimate downgrade move. */
4806 	ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2));
4807 }
4808 
4809 #define LOWER_BASE TMP_DIR "/lower"
4810 #define LOWER_DATA LOWER_BASE "/data"
4811 static const char lower_fl1[] = LOWER_DATA "/fl1";
4812 static const char lower_dl1[] = LOWER_DATA "/dl1";
4813 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
4814 static const char lower_fo1[] = LOWER_DATA "/fo1";
4815 static const char lower_do1[] = LOWER_DATA "/do1";
4816 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
4817 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
4818 
4819 static const char (*lower_base_files[])[] = {
4820 	&lower_fl1,
4821 	&lower_fo1,
4822 	NULL,
4823 };
4824 static const char (*lower_base_directories[])[] = {
4825 	&lower_dl1,
4826 	&lower_do1,
4827 	NULL,
4828 };
4829 static const char (*lower_sub_files[])[] = {
4830 	&lower_dl1_fl2,
4831 	&lower_do1_fo2,
4832 	&lower_do1_fl3,
4833 	NULL,
4834 };
4835 
4836 #define UPPER_BASE TMP_DIR "/upper"
4837 #define UPPER_DATA UPPER_BASE "/data"
4838 #define UPPER_WORK UPPER_BASE "/work"
4839 static const char upper_fu1[] = UPPER_DATA "/fu1";
4840 static const char upper_du1[] = UPPER_DATA "/du1";
4841 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
4842 static const char upper_fo1[] = UPPER_DATA "/fo1";
4843 static const char upper_do1[] = UPPER_DATA "/do1";
4844 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
4845 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
4846 
4847 static const char (*upper_base_files[])[] = {
4848 	&upper_fu1,
4849 	&upper_fo1,
4850 	NULL,
4851 };
4852 static const char (*upper_base_directories[])[] = {
4853 	&upper_du1,
4854 	&upper_do1,
4855 	NULL,
4856 };
4857 static const char (*upper_sub_files[])[] = {
4858 	&upper_du1_fu2,
4859 	&upper_do1_fo2,
4860 	&upper_do1_fu3,
4861 	NULL,
4862 };
4863 
4864 #define MERGE_BASE TMP_DIR "/merge"
4865 #define MERGE_DATA MERGE_BASE "/data"
4866 static const char merge_fl1[] = MERGE_DATA "/fl1";
4867 static const char merge_dl1[] = MERGE_DATA "/dl1";
4868 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
4869 static const char merge_fu1[] = MERGE_DATA "/fu1";
4870 static const char merge_du1[] = MERGE_DATA "/du1";
4871 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
4872 static const char merge_fo1[] = MERGE_DATA "/fo1";
4873 static const char merge_do1[] = MERGE_DATA "/do1";
4874 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
4875 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
4876 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
4877 
4878 static const char (*merge_base_files[])[] = {
4879 	&merge_fl1,
4880 	&merge_fu1,
4881 	&merge_fo1,
4882 	NULL,
4883 };
4884 static const char (*merge_base_directories[])[] = {
4885 	&merge_dl1,
4886 	&merge_du1,
4887 	&merge_do1,
4888 	NULL,
4889 };
4890 static const char (*merge_sub_files[])[] = {
4891 	&merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2,
4892 	&merge_do1_fl3, &merge_do1_fu3, NULL,
4893 };
4894 
4895 /*
4896  * layout2_overlay hierarchy:
4897  *
4898  * tmp
4899  * ├── lower
4900  * │   └── data
4901  * │       ├── dl1
4902  * │       │   └── fl2
4903  * │       ├── do1
4904  * │       │   ├── fl3
4905  * │       │   └── fo2
4906  * │       ├── fl1
4907  * │       └── fo1
4908  * ├── merge
4909  * │   └── data
4910  * │       ├── dl1
4911  * │       │   └── fl2
4912  * │       ├── do1
4913  * │       │   ├── fl3
4914  * │       │   ├── fo2
4915  * │       │   └── fu3
4916  * │       ├── du1
4917  * │       │   └── fu2
4918  * │       ├── fl1
4919  * │       ├── fo1
4920  * │       └── fu1
4921  * └── upper
4922  *     ├── data
4923  *     │   ├── do1
4924  *     │   │   ├── fo2
4925  *     │   │   └── fu3
4926  *     │   ├── du1
4927  *     │   │   └── fu2
4928  *     │   ├── fo1
4929  *     │   └── fu1
4930  *     └── work
4931  *         └── work
4932  */
4933 
FIXTURE(layout2_overlay)4934 FIXTURE(layout2_overlay)
4935 {
4936 	bool skip_test;
4937 };
4938 
FIXTURE_SETUP(layout2_overlay)4939 FIXTURE_SETUP(layout2_overlay)
4940 {
4941 	if (!supports_filesystem("overlay")) {
4942 		self->skip_test = true;
4943 		SKIP(return, "overlayfs is not supported (setup)");
4944 	}
4945 
4946 	prepare_layout(_metadata);
4947 
4948 	create_directory(_metadata, LOWER_BASE);
4949 	set_cap(_metadata, CAP_SYS_ADMIN);
4950 	/* Creates tmpfs mount points to get deterministic overlayfs. */
4951 	ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE));
4952 	clear_cap(_metadata, CAP_SYS_ADMIN);
4953 	create_file(_metadata, lower_fl1);
4954 	create_file(_metadata, lower_dl1_fl2);
4955 	create_file(_metadata, lower_fo1);
4956 	create_file(_metadata, lower_do1_fo2);
4957 	create_file(_metadata, lower_do1_fl3);
4958 
4959 	create_directory(_metadata, UPPER_BASE);
4960 	set_cap(_metadata, CAP_SYS_ADMIN);
4961 	ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE));
4962 	clear_cap(_metadata, CAP_SYS_ADMIN);
4963 	create_file(_metadata, upper_fu1);
4964 	create_file(_metadata, upper_du1_fu2);
4965 	create_file(_metadata, upper_fo1);
4966 	create_file(_metadata, upper_do1_fo2);
4967 	create_file(_metadata, upper_do1_fu3);
4968 	ASSERT_EQ(0, mkdir(UPPER_WORK, 0700));
4969 
4970 	create_directory(_metadata, MERGE_DATA);
4971 	set_cap(_metadata, CAP_SYS_ADMIN);
4972 	set_cap(_metadata, CAP_DAC_OVERRIDE);
4973 	ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0,
4974 			   "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA
4975 			   ",workdir=" UPPER_WORK));
4976 	clear_cap(_metadata, CAP_DAC_OVERRIDE);
4977 	clear_cap(_metadata, CAP_SYS_ADMIN);
4978 }
4979 
FIXTURE_TEARDOWN_PARENT(layout2_overlay)4980 FIXTURE_TEARDOWN_PARENT(layout2_overlay)
4981 {
4982 	if (self->skip_test)
4983 		SKIP(return, "overlayfs is not supported (teardown)");
4984 
4985 	EXPECT_EQ(0, remove_path(lower_do1_fl3));
4986 	EXPECT_EQ(0, remove_path(lower_dl1_fl2));
4987 	EXPECT_EQ(0, remove_path(lower_fl1));
4988 	EXPECT_EQ(0, remove_path(lower_do1_fo2));
4989 	EXPECT_EQ(0, remove_path(lower_fo1));
4990 
4991 	/* umount(LOWER_BASE)) is handled by namespace lifetime. */
4992 	EXPECT_EQ(0, remove_path(LOWER_BASE));
4993 
4994 	EXPECT_EQ(0, remove_path(upper_do1_fu3));
4995 	EXPECT_EQ(0, remove_path(upper_du1_fu2));
4996 	EXPECT_EQ(0, remove_path(upper_fu1));
4997 	EXPECT_EQ(0, remove_path(upper_do1_fo2));
4998 	EXPECT_EQ(0, remove_path(upper_fo1));
4999 	EXPECT_EQ(0, remove_path(UPPER_WORK "/work"));
5000 
5001 	/* umount(UPPER_BASE)) is handled by namespace lifetime. */
5002 	EXPECT_EQ(0, remove_path(UPPER_BASE));
5003 
5004 	/* umount(MERGE_DATA)) is handled by namespace lifetime. */
5005 	EXPECT_EQ(0, remove_path(MERGE_DATA));
5006 
5007 	cleanup_layout(_metadata);
5008 }
5009 
TEST_F_FORK(layout2_overlay,no_restriction)5010 TEST_F_FORK(layout2_overlay, no_restriction)
5011 {
5012 	if (self->skip_test)
5013 		SKIP(return, "overlayfs is not supported (test)");
5014 
5015 	ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
5016 	ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
5017 	ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY));
5018 	ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY));
5019 	ASSERT_EQ(0, test_open(lower_do1, O_RDONLY));
5020 	ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY));
5021 	ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY));
5022 
5023 	ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY));
5024 	ASSERT_EQ(0, test_open(upper_du1, O_RDONLY));
5025 	ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY));
5026 	ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY));
5027 	ASSERT_EQ(0, test_open(upper_do1, O_RDONLY));
5028 	ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY));
5029 	ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY));
5030 
5031 	ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY));
5032 	ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY));
5033 	ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY));
5034 	ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY));
5035 	ASSERT_EQ(0, test_open(merge_du1, O_RDONLY));
5036 	ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY));
5037 	ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY));
5038 	ASSERT_EQ(0, test_open(merge_do1, O_RDONLY));
5039 	ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY));
5040 	ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY));
5041 	ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY));
5042 }
5043 
5044 #define for_each_path(path_list, path_entry, i)               \
5045 	for (i = 0, path_entry = *path_list[i]; path_list[i]; \
5046 	     path_entry = *path_list[++i])
5047 
TEST_F_FORK(layout2_overlay,same_content_different_file)5048 TEST_F_FORK(layout2_overlay, same_content_different_file)
5049 {
5050 	/* Sets access right on parent directories of both layers. */
5051 	const struct rule layer1_base[] = {
5052 		{
5053 			.path = LOWER_BASE,
5054 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5055 		},
5056 		{
5057 			.path = UPPER_BASE,
5058 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5059 		},
5060 		{
5061 			.path = MERGE_BASE,
5062 			.access = ACCESS_RW,
5063 		},
5064 		{},
5065 	};
5066 	const struct rule layer2_data[] = {
5067 		{
5068 			.path = LOWER_DATA,
5069 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5070 		},
5071 		{
5072 			.path = UPPER_DATA,
5073 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5074 		},
5075 		{
5076 			.path = MERGE_DATA,
5077 			.access = ACCESS_RW,
5078 		},
5079 		{},
5080 	};
5081 	/* Sets access right on directories inside both layers. */
5082 	const struct rule layer3_subdirs[] = {
5083 		{
5084 			.path = lower_dl1,
5085 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5086 		},
5087 		{
5088 			.path = lower_do1,
5089 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5090 		},
5091 		{
5092 			.path = upper_du1,
5093 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5094 		},
5095 		{
5096 			.path = upper_do1,
5097 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5098 		},
5099 		{
5100 			.path = merge_dl1,
5101 			.access = ACCESS_RW,
5102 		},
5103 		{
5104 			.path = merge_du1,
5105 			.access = ACCESS_RW,
5106 		},
5107 		{
5108 			.path = merge_do1,
5109 			.access = ACCESS_RW,
5110 		},
5111 		{},
5112 	};
5113 	/* Tighten access rights to the files. */
5114 	const struct rule layer4_files[] = {
5115 		{
5116 			.path = lower_dl1_fl2,
5117 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5118 		},
5119 		{
5120 			.path = lower_do1_fo2,
5121 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5122 		},
5123 		{
5124 			.path = lower_do1_fl3,
5125 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5126 		},
5127 		{
5128 			.path = upper_du1_fu2,
5129 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5130 		},
5131 		{
5132 			.path = upper_do1_fo2,
5133 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5134 		},
5135 		{
5136 			.path = upper_do1_fu3,
5137 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5138 		},
5139 		{
5140 			.path = merge_dl1_fl2,
5141 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5142 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5143 		},
5144 		{
5145 			.path = merge_du1_fu2,
5146 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5147 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5148 		},
5149 		{
5150 			.path = merge_do1_fo2,
5151 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5152 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5153 		},
5154 		{
5155 			.path = merge_do1_fl3,
5156 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5157 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5158 		},
5159 		{
5160 			.path = merge_do1_fu3,
5161 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5162 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5163 		},
5164 		{},
5165 	};
5166 	const struct rule layer5_merge_only[] = {
5167 		{
5168 			.path = MERGE_DATA,
5169 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
5170 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
5171 		},
5172 		{},
5173 	};
5174 	int ruleset_fd;
5175 	size_t i;
5176 	const char *path_entry;
5177 
5178 	if (self->skip_test)
5179 		SKIP(return, "overlayfs is not supported (test)");
5180 
5181 	/* Sets rules on base directories (i.e. outside overlay scope). */
5182 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
5183 	ASSERT_LE(0, ruleset_fd);
5184 	enforce_ruleset(_metadata, ruleset_fd);
5185 	ASSERT_EQ(0, close(ruleset_fd));
5186 
5187 	/* Checks lower layer. */
5188 	for_each_path(lower_base_files, path_entry, i) {
5189 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5190 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5191 	}
5192 	for_each_path(lower_base_directories, path_entry, i) {
5193 		ASSERT_EQ(EACCES,
5194 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
5195 	}
5196 	for_each_path(lower_sub_files, path_entry, i) {
5197 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5198 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5199 	}
5200 	/* Checks upper layer. */
5201 	for_each_path(upper_base_files, path_entry, i) {
5202 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5203 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5204 	}
5205 	for_each_path(upper_base_directories, path_entry, i) {
5206 		ASSERT_EQ(EACCES,
5207 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
5208 	}
5209 	for_each_path(upper_sub_files, path_entry, i) {
5210 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5211 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5212 	}
5213 	/*
5214 	 * Checks that access rights are independent from the lower and upper
5215 	 * layers: write access to upper files viewed through the merge point
5216 	 * is still allowed, and write access to lower file viewed (and copied)
5217 	 * through the merge point is still allowed.
5218 	 */
5219 	for_each_path(merge_base_files, path_entry, i) {
5220 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5221 	}
5222 	for_each_path(merge_base_directories, path_entry, i) {
5223 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
5224 	}
5225 	for_each_path(merge_sub_files, path_entry, i) {
5226 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5227 	}
5228 
5229 	/* Sets rules on data directories (i.e. inside overlay scope). */
5230 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data);
5231 	ASSERT_LE(0, ruleset_fd);
5232 	enforce_ruleset(_metadata, ruleset_fd);
5233 	ASSERT_EQ(0, close(ruleset_fd));
5234 
5235 	/* Checks merge. */
5236 	for_each_path(merge_base_files, path_entry, i) {
5237 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5238 	}
5239 	for_each_path(merge_base_directories, path_entry, i) {
5240 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
5241 	}
5242 	for_each_path(merge_sub_files, path_entry, i) {
5243 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5244 	}
5245 
5246 	/* Same checks with tighter rules. */
5247 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs);
5248 	ASSERT_LE(0, ruleset_fd);
5249 	enforce_ruleset(_metadata, ruleset_fd);
5250 	ASSERT_EQ(0, close(ruleset_fd));
5251 
5252 	/* Checks changes for lower layer. */
5253 	for_each_path(lower_base_files, path_entry, i) {
5254 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
5255 	}
5256 	/* Checks changes for upper layer. */
5257 	for_each_path(upper_base_files, path_entry, i) {
5258 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
5259 	}
5260 	/* Checks all merge accesses. */
5261 	for_each_path(merge_base_files, path_entry, i) {
5262 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
5263 	}
5264 	for_each_path(merge_base_directories, path_entry, i) {
5265 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
5266 	}
5267 	for_each_path(merge_sub_files, path_entry, i) {
5268 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5269 	}
5270 
5271 	/* Sets rules directly on overlayed files. */
5272 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files);
5273 	ASSERT_LE(0, ruleset_fd);
5274 	enforce_ruleset(_metadata, ruleset_fd);
5275 	ASSERT_EQ(0, close(ruleset_fd));
5276 
5277 	/* Checks unchanged accesses on lower layer. */
5278 	for_each_path(lower_sub_files, path_entry, i) {
5279 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5280 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5281 	}
5282 	/* Checks unchanged accesses on upper layer. */
5283 	for_each_path(upper_sub_files, path_entry, i) {
5284 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
5285 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
5286 	}
5287 	/* Checks all merge accesses. */
5288 	for_each_path(merge_base_files, path_entry, i) {
5289 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
5290 	}
5291 	for_each_path(merge_base_directories, path_entry, i) {
5292 		ASSERT_EQ(EACCES,
5293 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
5294 	}
5295 	for_each_path(merge_sub_files, path_entry, i) {
5296 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5297 	}
5298 
5299 	/* Only allowes access to the merge hierarchy. */
5300 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only);
5301 	ASSERT_LE(0, ruleset_fd);
5302 	enforce_ruleset(_metadata, ruleset_fd);
5303 	ASSERT_EQ(0, close(ruleset_fd));
5304 
5305 	/* Checks new accesses on lower layer. */
5306 	for_each_path(lower_sub_files, path_entry, i) {
5307 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
5308 	}
5309 	/* Checks new accesses on upper layer. */
5310 	for_each_path(upper_sub_files, path_entry, i) {
5311 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
5312 	}
5313 	/* Checks all merge accesses. */
5314 	for_each_path(merge_base_files, path_entry, i) {
5315 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
5316 	}
5317 	for_each_path(merge_base_directories, path_entry, i) {
5318 		ASSERT_EQ(EACCES,
5319 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
5320 	}
5321 	for_each_path(merge_sub_files, path_entry, i) {
5322 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
5323 	}
5324 }
5325 
FIXTURE(layout3_fs)5326 FIXTURE(layout3_fs)
5327 {
5328 	bool has_created_dir;
5329 	bool has_created_file;
5330 	bool skip_test;
5331 };
5332 
FIXTURE_VARIANT(layout3_fs)5333 FIXTURE_VARIANT(layout3_fs)
5334 {
5335 	const struct mnt_opt mnt;
5336 	const char *const file_path;
5337 	unsigned int cwd_fs_magic;
5338 };
5339 
5340 /* clang-format off */
FIXTURE_VARIANT_ADD(layout3_fs,tmpfs)5341 FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
5342 	/* clang-format on */
5343 	.mnt = {
5344 		.type = "tmpfs",
5345 		.data = MNT_TMP_DATA,
5346 	},
5347 	.file_path = file1_s1d1,
5348 };
5349 
FIXTURE_VARIANT_ADD(layout3_fs,ramfs)5350 FIXTURE_VARIANT_ADD(layout3_fs, ramfs) {
5351 	.mnt = {
5352 		.type = "ramfs",
5353 		.data = "mode=700",
5354 	},
5355 	.file_path = TMP_DIR "/dir/file",
5356 };
5357 
FIXTURE_VARIANT_ADD(layout3_fs,cgroup2)5358 FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) {
5359 	.mnt = {
5360 		.type = "cgroup2",
5361 	},
5362 	.file_path = TMP_DIR "/test/cgroup.procs",
5363 };
5364 
FIXTURE_VARIANT_ADD(layout3_fs,proc)5365 FIXTURE_VARIANT_ADD(layout3_fs, proc) {
5366 	.mnt = {
5367 		.type = "proc",
5368 	},
5369 	.file_path = TMP_DIR "/self/status",
5370 };
5371 
FIXTURE_VARIANT_ADD(layout3_fs,sysfs)5372 FIXTURE_VARIANT_ADD(layout3_fs, sysfs) {
5373 	.mnt = {
5374 		.type = "sysfs",
5375 	},
5376 	.file_path = TMP_DIR "/kernel/notes",
5377 };
5378 
FIXTURE_VARIANT_ADD(layout3_fs,hostfs)5379 FIXTURE_VARIANT_ADD(layout3_fs, hostfs) {
5380 	.mnt = {
5381 		.source = TMP_DIR,
5382 		.flags = MS_BIND,
5383 	},
5384 	.file_path = TMP_DIR "/dir/file",
5385 	.cwd_fs_magic = HOSTFS_SUPER_MAGIC,
5386 };
5387 
dirname_alloc(const char * path)5388 static char *dirname_alloc(const char *path)
5389 {
5390 	char *dup;
5391 
5392 	if (!path)
5393 		return NULL;
5394 
5395 	dup = strdup(path);
5396 	if (!dup)
5397 		return NULL;
5398 
5399 	return dirname(dup);
5400 }
5401 
FIXTURE_SETUP(layout3_fs)5402 FIXTURE_SETUP(layout3_fs)
5403 {
5404 	struct stat statbuf;
5405 	char *dir_path = dirname_alloc(variant->file_path);
5406 
5407 	if (!supports_filesystem(variant->mnt.type) ||
5408 	    !cwd_matches_fs(variant->cwd_fs_magic)) {
5409 		self->skip_test = true;
5410 		SKIP(return, "this filesystem is not supported (setup)");
5411 	}
5412 
5413 	prepare_layout_opt(_metadata, &variant->mnt);
5414 
5415 	/* Creates directory when required. */
5416 	if (stat(dir_path, &statbuf)) {
5417 		set_cap(_metadata, CAP_DAC_OVERRIDE);
5418 		EXPECT_EQ(0, mkdir(dir_path, 0700))
5419 		{
5420 			TH_LOG("Failed to create directory \"%s\": %s",
5421 			       dir_path, strerror(errno));
5422 		}
5423 		self->has_created_dir = true;
5424 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
5425 	}
5426 
5427 	/* Creates file when required. */
5428 	if (stat(variant->file_path, &statbuf)) {
5429 		int fd;
5430 
5431 		set_cap(_metadata, CAP_DAC_OVERRIDE);
5432 		fd = creat(variant->file_path, 0600);
5433 		EXPECT_LE(0, fd)
5434 		{
5435 			TH_LOG("Failed to create file \"%s\": %s",
5436 			       variant->file_path, strerror(errno));
5437 		}
5438 		EXPECT_EQ(0, close(fd));
5439 		self->has_created_file = true;
5440 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
5441 	}
5442 
5443 	free(dir_path);
5444 }
5445 
FIXTURE_TEARDOWN_PARENT(layout3_fs)5446 FIXTURE_TEARDOWN_PARENT(layout3_fs)
5447 {
5448 	if (self->skip_test)
5449 		SKIP(return, "this filesystem is not supported (teardown)");
5450 
5451 	if (self->has_created_file) {
5452 		set_cap(_metadata, CAP_DAC_OVERRIDE);
5453 		/*
5454 		 * Don't check for error because the file might already
5455 		 * have been removed (cf. release_inode test).
5456 		 */
5457 		unlink(variant->file_path);
5458 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
5459 	}
5460 
5461 	if (self->has_created_dir) {
5462 		char *dir_path = dirname_alloc(variant->file_path);
5463 
5464 		set_cap(_metadata, CAP_DAC_OVERRIDE);
5465 		/*
5466 		 * Don't check for error because the directory might already
5467 		 * have been removed (cf. release_inode test).
5468 		 */
5469 		rmdir(dir_path);
5470 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
5471 		free(dir_path);
5472 	}
5473 
5474 	cleanup_layout(_metadata);
5475 }
5476 
layer3_fs_tag_inode(struct __test_metadata * const _metadata,FIXTURE_DATA (layout3_fs)* self,const FIXTURE_VARIANT (layout3_fs)* variant,const char * const rule_path)5477 static void layer3_fs_tag_inode(struct __test_metadata *const _metadata,
5478 				FIXTURE_DATA(layout3_fs) * self,
5479 				const FIXTURE_VARIANT(layout3_fs) * variant,
5480 				const char *const rule_path)
5481 {
5482 	const struct rule layer1_allow_read_file[] = {
5483 		{
5484 			.path = rule_path,
5485 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
5486 		},
5487 		{},
5488 	};
5489 	const struct landlock_ruleset_attr layer2_deny_everything_attr = {
5490 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
5491 	};
5492 	const char *const dev_null_path = "/dev/null";
5493 	int ruleset_fd;
5494 
5495 	if (self->skip_test)
5496 		SKIP(return, "this filesystem is not supported (test)");
5497 
5498 	/* Checks without Landlock. */
5499 	EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
5500 	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
5501 
5502 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
5503 				    layer1_allow_read_file);
5504 	EXPECT_LE(0, ruleset_fd);
5505 	enforce_ruleset(_metadata, ruleset_fd);
5506 	EXPECT_EQ(0, close(ruleset_fd));
5507 
5508 	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
5509 	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
5510 
5511 	/* Forbids directory reading. */
5512 	ruleset_fd =
5513 		landlock_create_ruleset(&layer2_deny_everything_attr,
5514 					sizeof(layer2_deny_everything_attr), 0);
5515 	EXPECT_LE(0, ruleset_fd);
5516 	enforce_ruleset(_metadata, ruleset_fd);
5517 	EXPECT_EQ(0, close(ruleset_fd));
5518 
5519 	/* Checks with Landlock and forbidden access. */
5520 	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
5521 	EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
5522 }
5523 
5524 /* Matrix of tests to check file hierarchy evaluation. */
5525 
TEST_F_FORK(layout3_fs,tag_inode_dir_parent)5526 TEST_F_FORK(layout3_fs, tag_inode_dir_parent)
5527 {
5528 	/* The current directory must not be the root for this test. */
5529 	layer3_fs_tag_inode(_metadata, self, variant, ".");
5530 }
5531 
TEST_F_FORK(layout3_fs,tag_inode_dir_mnt)5532 TEST_F_FORK(layout3_fs, tag_inode_dir_mnt)
5533 {
5534 	layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR);
5535 }
5536 
TEST_F_FORK(layout3_fs,tag_inode_dir_child)5537 TEST_F_FORK(layout3_fs, tag_inode_dir_child)
5538 {
5539 	char *dir_path = dirname_alloc(variant->file_path);
5540 
5541 	layer3_fs_tag_inode(_metadata, self, variant, dir_path);
5542 	free(dir_path);
5543 }
5544 
TEST_F_FORK(layout3_fs,tag_inode_file)5545 TEST_F_FORK(layout3_fs, tag_inode_file)
5546 {
5547 	layer3_fs_tag_inode(_metadata, self, variant, variant->file_path);
5548 }
5549 
5550 /* Light version of layout1.release_inodes */
TEST_F_FORK(layout3_fs,release_inodes)5551 TEST_F_FORK(layout3_fs, release_inodes)
5552 {
5553 	const struct rule layer1[] = {
5554 		{
5555 			.path = TMP_DIR,
5556 			.access = LANDLOCK_ACCESS_FS_READ_DIR,
5557 		},
5558 		{},
5559 	};
5560 	int ruleset_fd;
5561 
5562 	if (self->skip_test)
5563 		SKIP(return, "this filesystem is not supported (test)");
5564 
5565 	/* Clean up for the teardown to not fail. */
5566 	if (self->has_created_file)
5567 		EXPECT_EQ(0, remove_path(variant->file_path));
5568 
5569 	if (self->has_created_dir) {
5570 		char *dir_path = dirname_alloc(variant->file_path);
5571 
5572 		/* Don't check for error because of cgroup specificities. */
5573 		remove_path(dir_path);
5574 		free(dir_path);
5575 	}
5576 
5577 	ruleset_fd =
5578 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
5579 	ASSERT_LE(0, ruleset_fd);
5580 
5581 	/* Unmount the filesystem while it is being used by a ruleset. */
5582 	set_cap(_metadata, CAP_SYS_ADMIN);
5583 	ASSERT_EQ(0, umount(TMP_DIR));
5584 	clear_cap(_metadata, CAP_SYS_ADMIN);
5585 
5586 	/* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */
5587 	set_cap(_metadata, CAP_SYS_ADMIN);
5588 	ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR));
5589 	clear_cap(_metadata, CAP_SYS_ADMIN);
5590 
5591 	enforce_ruleset(_metadata, ruleset_fd);
5592 	ASSERT_EQ(0, close(ruleset_fd));
5593 
5594 	/* Checks that access to the new mount point is denied. */
5595 	ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY));
5596 }
5597 
matches_log_fs_extra(struct __test_metadata * const _metadata,int audit_fd,const char * const blockers,const char * const path,const char * const extra)5598 static int matches_log_fs_extra(struct __test_metadata *const _metadata,
5599 				int audit_fd, const char *const blockers,
5600 				const char *const path, const char *const extra)
5601 {
5602 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
5603 		" blockers=fs\\.%s path=\"%s\" dev=\"[^\"]\\+\" ino=[0-9]\\+$";
5604 	char *absolute_path = NULL;
5605 	size_t log_match_remaining = sizeof(log_template) + strlen(blockers) +
5606 				     PATH_MAX * 2 +
5607 				     (extra ? strlen(extra) : 0) + 1;
5608 	char log_match[log_match_remaining];
5609 	char *log_match_cursor = log_match;
5610 	size_t chunk_len;
5611 
5612 	chunk_len = snprintf(log_match_cursor, log_match_remaining,
5613 			     REGEX_LANDLOCK_PREFIX " blockers=%s path=\"",
5614 			     blockers);
5615 	if (chunk_len < 0 || chunk_len >= log_match_remaining)
5616 		return -E2BIG;
5617 
5618 	/*
5619 	 * It is assume that absolute_path does not contain control characters nor
5620 	 * spaces, see audit_string_contains_control().
5621 	 */
5622 	absolute_path = realpath(path, NULL);
5623 	if (!absolute_path)
5624 		return -errno;
5625 
5626 	log_match_remaining -= chunk_len;
5627 	log_match_cursor += chunk_len;
5628 	log_match_cursor = regex_escape(absolute_path, log_match_cursor,
5629 					log_match_remaining);
5630 	free(absolute_path);
5631 	if (log_match_cursor < 0)
5632 		return (long long)log_match_cursor;
5633 
5634 	log_match_remaining -= log_match_cursor - log_match;
5635 	chunk_len = snprintf(log_match_cursor, log_match_remaining,
5636 			     "\" dev=\"[^\"]\\+\" ino=[0-9]\\+%s$",
5637 			     extra ?: "");
5638 	if (chunk_len < 0 || chunk_len >= log_match_remaining)
5639 		return -E2BIG;
5640 
5641 	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
5642 				  NULL);
5643 }
5644 
matches_log_fs(struct __test_metadata * const _metadata,int audit_fd,const char * const blockers,const char * const path)5645 static int matches_log_fs(struct __test_metadata *const _metadata, int audit_fd,
5646 			  const char *const blockers, const char *const path)
5647 {
5648 	return matches_log_fs_extra(_metadata, audit_fd, blockers, path, NULL);
5649 }
5650 
FIXTURE(audit_layout1)5651 FIXTURE(audit_layout1)
5652 {
5653 	struct audit_filter audit_filter;
5654 	int audit_fd;
5655 };
5656 
FIXTURE_SETUP(audit_layout1)5657 FIXTURE_SETUP(audit_layout1)
5658 {
5659 	prepare_layout(_metadata);
5660 
5661 	create_layout1(_metadata);
5662 
5663 	set_cap(_metadata, CAP_AUDIT_CONTROL);
5664 	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
5665 	EXPECT_LE(0, self->audit_fd);
5666 	disable_caps(_metadata);
5667 }
5668 
FIXTURE_TEARDOWN_PARENT(audit_layout1)5669 FIXTURE_TEARDOWN_PARENT(audit_layout1)
5670 {
5671 	remove_layout1(_metadata);
5672 
5673 	cleanup_layout(_metadata);
5674 
5675 	EXPECT_EQ(0, audit_cleanup(-1, NULL));
5676 }
5677 
TEST_F(audit_layout1,execute_make)5678 TEST_F(audit_layout1, execute_make)
5679 {
5680 	struct audit_records records;
5681 
5682 	copy_file(_metadata, bin_true, file1_s1d1);
5683 	test_execute(_metadata, 0, file1_s1d1);
5684 	test_check_exec(_metadata, 0, file1_s1d1);
5685 
5686 	drop_access_rights(_metadata,
5687 			   &(struct landlock_ruleset_attr){
5688 				   .handled_access_fs =
5689 					   LANDLOCK_ACCESS_FS_EXECUTE,
5690 			   });
5691 
5692 	test_execute(_metadata, EACCES, file1_s1d1);
5693 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
5694 				    file1_s1d1));
5695 	test_check_exec(_metadata, EACCES, file1_s1d1);
5696 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
5697 				    file1_s1d1));
5698 
5699 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5700 	EXPECT_EQ(0, records.access);
5701 	EXPECT_EQ(0, records.domain);
5702 }
5703 
5704 /*
5705  * Using a set of handled/denied access rights make it possible to check that
5706  * only the blocked ones are logged.
5707  */
5708 
5709 /* clang-format off */
5710 static const __u64 access_fs_16 =
5711 	LANDLOCK_ACCESS_FS_EXECUTE |
5712 	LANDLOCK_ACCESS_FS_WRITE_FILE |
5713 	LANDLOCK_ACCESS_FS_READ_FILE |
5714 	LANDLOCK_ACCESS_FS_READ_DIR |
5715 	LANDLOCK_ACCESS_FS_REMOVE_DIR |
5716 	LANDLOCK_ACCESS_FS_REMOVE_FILE |
5717 	LANDLOCK_ACCESS_FS_MAKE_CHAR |
5718 	LANDLOCK_ACCESS_FS_MAKE_DIR |
5719 	LANDLOCK_ACCESS_FS_MAKE_REG |
5720 	LANDLOCK_ACCESS_FS_MAKE_SOCK |
5721 	LANDLOCK_ACCESS_FS_MAKE_FIFO |
5722 	LANDLOCK_ACCESS_FS_MAKE_BLOCK |
5723 	LANDLOCK_ACCESS_FS_MAKE_SYM |
5724 	LANDLOCK_ACCESS_FS_REFER |
5725 	LANDLOCK_ACCESS_FS_TRUNCATE |
5726 	LANDLOCK_ACCESS_FS_IOCTL_DEV;
5727 /* clang-format on */
5728 
TEST_F(audit_layout1,execute_read)5729 TEST_F(audit_layout1, execute_read)
5730 {
5731 	struct audit_records records;
5732 
5733 	copy_file(_metadata, bin_true, file1_s1d1);
5734 	test_execute(_metadata, 0, file1_s1d1);
5735 	test_check_exec(_metadata, 0, file1_s1d1);
5736 
5737 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5738 					      .handled_access_fs = access_fs_16,
5739 				      });
5740 
5741 	/*
5742 	 * The only difference with the previous audit_layout1.execute_read test is
5743 	 * the extra ",fs\\.read_file" blocked by the executable file.
5744 	 */
5745 	test_execute(_metadata, EACCES, file1_s1d1);
5746 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5747 				    "fs\\.execute,fs\\.read_file", file1_s1d1));
5748 	test_check_exec(_metadata, EACCES, file1_s1d1);
5749 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5750 				    "fs\\.execute,fs\\.read_file", file1_s1d1));
5751 
5752 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5753 	EXPECT_EQ(0, records.access);
5754 	EXPECT_EQ(0, records.domain);
5755 }
5756 
TEST_F(audit_layout1,write_file)5757 TEST_F(audit_layout1, write_file)
5758 {
5759 	struct audit_records records;
5760 
5761 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5762 					      .handled_access_fs = access_fs_16,
5763 				      });
5764 
5765 	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
5766 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5767 				    "fs\\.write_file", file1_s1d1));
5768 
5769 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5770 	EXPECT_EQ(0, records.access);
5771 	EXPECT_EQ(1, records.domain);
5772 }
5773 
TEST_F(audit_layout1,read_file)5774 TEST_F(audit_layout1, read_file)
5775 {
5776 	struct audit_records records;
5777 
5778 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5779 					      .handled_access_fs = access_fs_16,
5780 				      });
5781 
5782 	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
5783 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_file",
5784 				    file1_s1d1));
5785 
5786 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5787 	EXPECT_EQ(0, records.access);
5788 	EXPECT_EQ(1, records.domain);
5789 }
5790 
TEST_F(audit_layout1,read_dir)5791 TEST_F(audit_layout1, read_dir)
5792 {
5793 	struct audit_records records;
5794 
5795 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5796 					      .handled_access_fs = access_fs_16,
5797 				      });
5798 
5799 	EXPECT_EQ(EACCES, test_open(dir_s1d1, O_DIRECTORY));
5800 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_dir",
5801 				    dir_s1d1));
5802 
5803 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5804 	EXPECT_EQ(0, records.access);
5805 	EXPECT_EQ(1, records.domain);
5806 }
5807 
TEST_F(audit_layout1,remove_dir)5808 TEST_F(audit_layout1, remove_dir)
5809 {
5810 	struct audit_records records;
5811 
5812 	EXPECT_EQ(0, unlink(file1_s1d3));
5813 	EXPECT_EQ(0, unlink(file2_s1d3));
5814 
5815 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5816 					      .handled_access_fs = access_fs_16,
5817 				      });
5818 
5819 	EXPECT_EQ(-1, rmdir(dir_s1d3));
5820 	EXPECT_EQ(EACCES, errno);
5821 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5822 				    "fs\\.remove_dir", dir_s1d2));
5823 
5824 	EXPECT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
5825 	EXPECT_EQ(EACCES, errno);
5826 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5827 				    "fs\\.remove_dir", dir_s1d2));
5828 
5829 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5830 	EXPECT_EQ(0, records.access);
5831 	EXPECT_EQ(0, records.domain);
5832 }
5833 
TEST_F(audit_layout1,remove_file)5834 TEST_F(audit_layout1, remove_file)
5835 {
5836 	struct audit_records records;
5837 
5838 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5839 					      .handled_access_fs = access_fs_16,
5840 				      });
5841 
5842 	EXPECT_EQ(-1, unlink(file1_s1d3));
5843 	EXPECT_EQ(EACCES, errno);
5844 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5845 				    "fs\\.remove_file", dir_s1d3));
5846 
5847 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5848 	EXPECT_EQ(0, records.access);
5849 	EXPECT_EQ(1, records.domain);
5850 }
5851 
TEST_F(audit_layout1,make_char)5852 TEST_F(audit_layout1, make_char)
5853 {
5854 	struct audit_records records;
5855 
5856 	EXPECT_EQ(0, unlink(file1_s1d3));
5857 
5858 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5859 					      .handled_access_fs = access_fs_16,
5860 				      });
5861 
5862 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0));
5863 	EXPECT_EQ(EACCES, errno);
5864 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char",
5865 				    dir_s1d3));
5866 
5867 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5868 	EXPECT_EQ(0, records.access);
5869 	EXPECT_EQ(1, records.domain);
5870 }
5871 
TEST_F(audit_layout1,make_dir)5872 TEST_F(audit_layout1, make_dir)
5873 {
5874 	struct audit_records records;
5875 
5876 	EXPECT_EQ(0, unlink(file1_s1d3));
5877 
5878 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5879 					      .handled_access_fs = access_fs_16,
5880 				      });
5881 
5882 	EXPECT_EQ(-1, mkdir(file1_s1d3, 0755));
5883 	EXPECT_EQ(EACCES, errno);
5884 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_dir",
5885 				    dir_s1d3));
5886 
5887 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5888 	EXPECT_EQ(0, records.access);
5889 	EXPECT_EQ(1, records.domain);
5890 }
5891 
TEST_F(audit_layout1,make_reg)5892 TEST_F(audit_layout1, make_reg)
5893 {
5894 	struct audit_records records;
5895 
5896 	EXPECT_EQ(0, unlink(file1_s1d3));
5897 
5898 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5899 					      .handled_access_fs = access_fs_16,
5900 				      });
5901 
5902 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFREG | 0644, 0));
5903 	EXPECT_EQ(EACCES, errno);
5904 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_reg",
5905 				    dir_s1d3));
5906 
5907 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5908 	EXPECT_EQ(0, records.access);
5909 	EXPECT_EQ(1, records.domain);
5910 }
5911 
TEST_F(audit_layout1,make_sock)5912 TEST_F(audit_layout1, make_sock)
5913 {
5914 	struct audit_records records;
5915 
5916 	EXPECT_EQ(0, unlink(file1_s1d3));
5917 
5918 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5919 					      .handled_access_fs = access_fs_16,
5920 				      });
5921 
5922 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFSOCK | 0644, 0));
5923 	EXPECT_EQ(EACCES, errno);
5924 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sock",
5925 				    dir_s1d3));
5926 
5927 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5928 	EXPECT_EQ(0, records.access);
5929 	EXPECT_EQ(1, records.domain);
5930 }
5931 
TEST_F(audit_layout1,make_fifo)5932 TEST_F(audit_layout1, make_fifo)
5933 {
5934 	struct audit_records records;
5935 
5936 	EXPECT_EQ(0, unlink(file1_s1d3));
5937 
5938 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5939 					      .handled_access_fs = access_fs_16,
5940 				      });
5941 
5942 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFIFO | 0644, 0));
5943 	EXPECT_EQ(EACCES, errno);
5944 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_fifo",
5945 				    dir_s1d3));
5946 
5947 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5948 	EXPECT_EQ(0, records.access);
5949 	EXPECT_EQ(1, records.domain);
5950 }
5951 
TEST_F(audit_layout1,make_block)5952 TEST_F(audit_layout1, make_block)
5953 {
5954 	struct audit_records records;
5955 
5956 	EXPECT_EQ(0, unlink(file1_s1d3));
5957 
5958 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5959 					      .handled_access_fs = access_fs_16,
5960 				      });
5961 
5962 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFBLK | 0644, 0));
5963 	EXPECT_EQ(EACCES, errno);
5964 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
5965 				    "fs\\.make_block", dir_s1d3));
5966 
5967 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5968 	EXPECT_EQ(0, records.access);
5969 	EXPECT_EQ(1, records.domain);
5970 }
5971 
TEST_F(audit_layout1,make_sym)5972 TEST_F(audit_layout1, make_sym)
5973 {
5974 	struct audit_records records;
5975 
5976 	EXPECT_EQ(0, unlink(file1_s1d3));
5977 
5978 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5979 					      .handled_access_fs = access_fs_16,
5980 				      });
5981 
5982 	EXPECT_EQ(-1, symlink("target", file1_s1d3));
5983 	EXPECT_EQ(EACCES, errno);
5984 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sym",
5985 				    dir_s1d3));
5986 
5987 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
5988 	EXPECT_EQ(0, records.access);
5989 	EXPECT_EQ(1, records.domain);
5990 }
5991 
TEST_F(audit_layout1,refer_handled)5992 TEST_F(audit_layout1, refer_handled)
5993 {
5994 	struct audit_records records;
5995 
5996 	EXPECT_EQ(0, unlink(file1_s1d3));
5997 
5998 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
5999 					      .handled_access_fs =
6000 						      LANDLOCK_ACCESS_FS_REFER,
6001 				      });
6002 
6003 	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
6004 	EXPECT_EQ(EXDEV, errno);
6005 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
6006 				    dir_s1d1));
6007 	EXPECT_EQ(0,
6008 		  matches_log_domain_allocated(self->audit_fd, getpid(), NULL));
6009 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
6010 				    dir_s1d3));
6011 
6012 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6013 	EXPECT_EQ(0, records.access);
6014 	EXPECT_EQ(0, records.domain);
6015 }
6016 
TEST_F(audit_layout1,refer_make)6017 TEST_F(audit_layout1, refer_make)
6018 {
6019 	struct audit_records records;
6020 
6021 	EXPECT_EQ(0, unlink(file1_s1d3));
6022 
6023 	drop_access_rights(_metadata,
6024 			   &(struct landlock_ruleset_attr){
6025 				   .handled_access_fs =
6026 					   LANDLOCK_ACCESS_FS_MAKE_REG |
6027 					   LANDLOCK_ACCESS_FS_REFER,
6028 			   });
6029 
6030 	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
6031 	EXPECT_EQ(EACCES, errno);
6032 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
6033 				    dir_s1d1));
6034 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6035 				    "fs\\.make_reg,fs\\.refer", dir_s1d3));
6036 
6037 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6038 	EXPECT_EQ(0, records.access);
6039 	EXPECT_EQ(0, records.domain);
6040 }
6041 
TEST_F(audit_layout1,refer_rename)6042 TEST_F(audit_layout1, refer_rename)
6043 {
6044 	struct audit_records records;
6045 
6046 	EXPECT_EQ(0, unlink(file1_s1d3));
6047 
6048 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
6049 					      .handled_access_fs = access_fs_16,
6050 				      });
6051 
6052 	EXPECT_EQ(EACCES, test_rename(file1_s1d2, file1_s2d3));
6053 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6054 				    "fs\\.remove_file,fs\\.refer", dir_s1d2));
6055 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6056 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
6057 				    dir_s2d3));
6058 
6059 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6060 	EXPECT_EQ(0, records.access);
6061 	EXPECT_EQ(0, records.domain);
6062 }
6063 
TEST_F(audit_layout1,refer_exchange)6064 TEST_F(audit_layout1, refer_exchange)
6065 {
6066 	struct audit_records records;
6067 
6068 	EXPECT_EQ(0, unlink(file1_s1d3));
6069 
6070 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
6071 					      .handled_access_fs = access_fs_16,
6072 				      });
6073 
6074 	/*
6075 	 * The only difference with the previous audit_layout1.refer_rename test is
6076 	 * the extra ",fs\\.make_reg" blocked by the source directory.
6077 	 */
6078 	EXPECT_EQ(EACCES, test_exchange(file1_s1d2, file1_s2d3));
6079 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6080 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
6081 				    dir_s1d2));
6082 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6083 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
6084 				    dir_s2d3));
6085 
6086 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6087 	EXPECT_EQ(0, records.access);
6088 	EXPECT_EQ(0, records.domain);
6089 }
6090 
6091 /*
6092  * This test checks that the audit record is correctly generated when the
6093  * operation is only partially denied.  This is the case for rename(2) when the
6094  * source file is allowed to be referenced but the destination directory is not.
6095  *
6096  * This is also a regression test for commit d617f0d72d80 ("landlock: Optimize
6097  * file path walks and prepare for audit support") and commit 058518c20920
6098  * ("landlock: Align partial refer access checks with final ones").
6099  */
TEST_F(audit_layout1,refer_rename_half)6100 TEST_F(audit_layout1, refer_rename_half)
6101 {
6102 	struct audit_records records;
6103 	const struct rule layer1[] = {
6104 		{
6105 			.path = dir_s2d2,
6106 			.access = LANDLOCK_ACCESS_FS_REFER,
6107 		},
6108 		{},
6109 	};
6110 	int ruleset_fd =
6111 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
6112 
6113 	ASSERT_LE(0, ruleset_fd);
6114 	enforce_ruleset(_metadata, ruleset_fd);
6115 	ASSERT_EQ(0, close(ruleset_fd));
6116 
6117 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
6118 	ASSERT_EQ(EXDEV, errno);
6119 
6120 	/* Only half of the request is denied. */
6121 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
6122 				    dir_s1d1));
6123 
6124 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6125 	EXPECT_EQ(0, records.access);
6126 	EXPECT_EQ(1, records.domain);
6127 }
6128 
TEST_F(audit_layout1,truncate)6129 TEST_F(audit_layout1, truncate)
6130 {
6131 	struct audit_records records;
6132 
6133 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
6134 					      .handled_access_fs = access_fs_16,
6135 				      });
6136 
6137 	EXPECT_EQ(-1, truncate(file1_s1d3, 0));
6138 	EXPECT_EQ(EACCES, errno);
6139 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.truncate",
6140 				    file1_s1d3));
6141 
6142 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6143 	EXPECT_EQ(0, records.access);
6144 	EXPECT_EQ(1, records.domain);
6145 }
6146 
TEST_F(audit_layout1,ioctl_dev)6147 TEST_F(audit_layout1, ioctl_dev)
6148 {
6149 	struct audit_records records;
6150 	int fd;
6151 
6152 	drop_access_rights(_metadata,
6153 			   &(struct landlock_ruleset_attr){
6154 				   .handled_access_fs =
6155 					   access_fs_16 &
6156 					   ~LANDLOCK_ACCESS_FS_READ_FILE,
6157 			   });
6158 
6159 	fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
6160 	ASSERT_LE(0, fd);
6161 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
6162 	EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd,
6163 					  "fs\\.ioctl_dev", "/dev/null",
6164 					  " ioctlcmd=0x541b"));
6165 
6166 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6167 	EXPECT_EQ(0, records.access);
6168 	EXPECT_EQ(1, records.domain);
6169 }
6170 
TEST_F(audit_layout1,mount)6171 TEST_F(audit_layout1, mount)
6172 {
6173 	struct audit_records records;
6174 
6175 	drop_access_rights(_metadata,
6176 			   &(struct landlock_ruleset_attr){
6177 				   .handled_access_fs =
6178 					   LANDLOCK_ACCESS_FS_EXECUTE,
6179 			   });
6180 
6181 	set_cap(_metadata, CAP_SYS_ADMIN);
6182 	EXPECT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
6183 	EXPECT_EQ(EPERM, errno);
6184 	clear_cap(_metadata, CAP_SYS_ADMIN);
6185 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
6186 				    "fs\\.change_topology", dir_s3d2));
6187 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
6188 	EXPECT_EQ(0, records.access);
6189 	EXPECT_EQ(1, records.domain);
6190 }
6191 
6192 TEST_HARNESS_MAIN
6193