xref: /linux/tools/testing/selftests/landlock/fs_test.c (revision eee654ca9a55fd1e8632afb119975cba6af7d4ad)
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_renameat(int olddirfd,const char * oldpath,int newdirfd,const char * newpath)2270 static int test_renameat(int olddirfd, const char *oldpath, int newdirfd,
2271 			 const char *newpath)
2272 {
2273 	if (renameat2(olddirfd, oldpath, newdirfd, newpath, 0))
2274 		return errno;
2275 	return 0;
2276 }
2277 
test_exchangeat(int olddirfd,const char * oldpath,int newdirfd,const char * newpath)2278 static int test_exchangeat(int olddirfd, const char *oldpath, int newdirfd,
2279 			   const char *newpath)
2280 {
2281 	if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_EXCHANGE))
2282 		return errno;
2283 	return 0;
2284 }
2285 
TEST_F_FORK(layout1,rename_file)2286 TEST_F_FORK(layout1, rename_file)
2287 {
2288 	const struct rule rules[] = {
2289 		{
2290 			.path = dir_s1d3,
2291 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2292 		},
2293 		{
2294 			.path = dir_s2d2,
2295 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2296 		},
2297 		{},
2298 	};
2299 	const int ruleset_fd =
2300 		create_ruleset(_metadata, rules[0].access, rules);
2301 
2302 	ASSERT_LE(0, ruleset_fd);
2303 
2304 	ASSERT_EQ(0, unlink(file1_s1d2));
2305 
2306 	enforce_ruleset(_metadata, ruleset_fd);
2307 	ASSERT_EQ(0, close(ruleset_fd));
2308 
2309 	/*
2310 	 * Tries to replace a file, from a directory that allows file removal,
2311 	 * but to a different directory (which also allows file removal).
2312 	 */
2313 	ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3));
2314 	ASSERT_EQ(EXDEV, errno);
2315 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3,
2316 				RENAME_EXCHANGE));
2317 	ASSERT_EQ(EXDEV, errno);
2318 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2319 				RENAME_EXCHANGE));
2320 	ASSERT_EQ(EXDEV, errno);
2321 
2322 	/*
2323 	 * Tries to replace a file, from a directory that denies file removal,
2324 	 * to a different directory (which allows file removal).
2325 	 */
2326 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2327 	ASSERT_EQ(EACCES, errno);
2328 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3,
2329 				RENAME_EXCHANGE));
2330 	ASSERT_EQ(EACCES, errno);
2331 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3,
2332 				RENAME_EXCHANGE));
2333 	ASSERT_EQ(EXDEV, errno);
2334 
2335 	/* Exchanges files and directories that partially allow removal. */
2336 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1,
2337 				RENAME_EXCHANGE));
2338 	ASSERT_EQ(EACCES, errno);
2339 	/* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */
2340 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1));
2341 	ASSERT_EQ(EACCES, errno);
2342 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2,
2343 				RENAME_EXCHANGE));
2344 	ASSERT_EQ(EACCES, errno);
2345 	/* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */
2346 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2347 	ASSERT_EQ(EACCES, errno);
2348 
2349 	/* Renames files with different parents. */
2350 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2351 	ASSERT_EQ(EXDEV, errno);
2352 	ASSERT_EQ(0, unlink(file1_s1d3));
2353 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2354 	ASSERT_EQ(EACCES, errno);
2355 
2356 	/* Exchanges and renames files with same parent. */
2357 	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3,
2358 			       RENAME_EXCHANGE));
2359 	ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3));
2360 
2361 	/* Exchanges files and directories with same parent, twice. */
2362 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2363 			       RENAME_EXCHANGE));
2364 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2365 			       RENAME_EXCHANGE));
2366 }
2367 
TEST_F_FORK(layout1,rename_dir)2368 TEST_F_FORK(layout1, rename_dir)
2369 {
2370 	const struct rule rules[] = {
2371 		{
2372 			.path = dir_s1d2,
2373 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2374 		},
2375 		{
2376 			.path = dir_s2d1,
2377 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2378 		},
2379 		{},
2380 	};
2381 	const int ruleset_fd =
2382 		create_ruleset(_metadata, rules[0].access, rules);
2383 
2384 	ASSERT_LE(0, ruleset_fd);
2385 
2386 	/* Empties dir_s1d3 to allow renaming. */
2387 	ASSERT_EQ(0, unlink(file1_s1d3));
2388 	ASSERT_EQ(0, unlink(file2_s1d3));
2389 
2390 	enforce_ruleset(_metadata, ruleset_fd);
2391 	ASSERT_EQ(0, close(ruleset_fd));
2392 
2393 	/* Exchanges and renames directory to a different parent. */
2394 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
2395 				RENAME_EXCHANGE));
2396 	ASSERT_EQ(EXDEV, errno);
2397 	ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3));
2398 	ASSERT_EQ(EXDEV, errno);
2399 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
2400 				RENAME_EXCHANGE));
2401 	ASSERT_EQ(EXDEV, errno);
2402 
2403 	/*
2404 	 * Exchanges directory to the same parent, which doesn't allow
2405 	 * directory removal.
2406 	 */
2407 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1,
2408 				RENAME_EXCHANGE));
2409 	ASSERT_EQ(EACCES, errno);
2410 	/* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */
2411 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1));
2412 	ASSERT_EQ(EACCES, errno);
2413 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2,
2414 				RENAME_EXCHANGE));
2415 	ASSERT_EQ(EACCES, errno);
2416 	/* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */
2417 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2418 	ASSERT_EQ(EACCES, errno);
2419 
2420 	/*
2421 	 * Exchanges and renames directory to the same parent, which allows
2422 	 * directory removal.
2423 	 */
2424 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2,
2425 			       RENAME_EXCHANGE));
2426 	ASSERT_EQ(0, unlink(dir_s1d3));
2427 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
2428 	ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3));
2429 	ASSERT_EQ(0, rmdir(dir_s1d3));
2430 }
2431 
TEST_F_FORK(layout1,reparent_refer)2432 TEST_F_FORK(layout1, reparent_refer)
2433 {
2434 	const struct rule layer1[] = {
2435 		{
2436 			.path = dir_s1d2,
2437 			.access = LANDLOCK_ACCESS_FS_REFER,
2438 		},
2439 		{
2440 			.path = dir_s2d2,
2441 			.access = LANDLOCK_ACCESS_FS_REFER,
2442 		},
2443 		{},
2444 	};
2445 	int ruleset_fd =
2446 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
2447 
2448 	ASSERT_LE(0, ruleset_fd);
2449 	enforce_ruleset(_metadata, ruleset_fd);
2450 	ASSERT_EQ(0, close(ruleset_fd));
2451 
2452 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d1));
2453 	ASSERT_EQ(EXDEV, errno);
2454 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d2));
2455 	ASSERT_EQ(EXDEV, errno);
2456 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
2457 	ASSERT_EQ(EXDEV, errno);
2458 
2459 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d1));
2460 	ASSERT_EQ(EXDEV, errno);
2461 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d2));
2462 	ASSERT_EQ(EXDEV, errno);
2463 	/*
2464 	 * Moving should only be allowed when the source and the destination
2465 	 * parent directory have REFER.
2466 	 */
2467 	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d3));
2468 	ASSERT_EQ(ENOTEMPTY, errno);
2469 	ASSERT_EQ(0, unlink(file1_s2d3));
2470 	ASSERT_EQ(0, unlink(file2_s2d3));
2471 	ASSERT_EQ(0, rename(dir_s1d3, dir_s2d3));
2472 }
2473 
2474 /* 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[])2475 static void refer_denied_by_default(struct __test_metadata *const _metadata,
2476 				    const struct rule layer1[],
2477 				    const int layer1_err,
2478 				    const struct rule layer2[])
2479 {
2480 	int ruleset_fd;
2481 
2482 	ASSERT_EQ(0, unlink(file1_s1d2));
2483 
2484 	ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
2485 	ASSERT_LE(0, ruleset_fd);
2486 	enforce_ruleset(_metadata, ruleset_fd);
2487 	ASSERT_EQ(0, close(ruleset_fd));
2488 
2489 	/*
2490 	 * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to
2491 	 * layer1_err), then it allows some different-parent renames and links.
2492 	 */
2493 	ASSERT_EQ(layer1_err, test_rename(file1_s1d1, file1_s1d2));
2494 	if (layer1_err == 0)
2495 		ASSERT_EQ(layer1_err, test_rename(file1_s1d2, file1_s1d1));
2496 	ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2));
2497 	ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1));
2498 
2499 	ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
2500 	ASSERT_LE(0, ruleset_fd);
2501 	enforce_ruleset(_metadata, ruleset_fd);
2502 	ASSERT_EQ(0, close(ruleset_fd));
2503 
2504 	/*
2505 	 * Now, either the first or the second layer does not handle
2506 	 * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent
2507 	 * renames and links are denied, thus making the layer handling
2508 	 * LANDLOCK_ACCESS_FS_REFER null and void.
2509 	 */
2510 	ASSERT_EQ(EXDEV, test_rename(file1_s1d1, file1_s1d2));
2511 	ASSERT_EQ(EXDEV, test_exchange(file2_s1d1, file2_s1d2));
2512 	ASSERT_EQ(EXDEV, test_exchange(file2_s1d2, file2_s1d1));
2513 }
2514 
2515 const struct rule layer_dir_s1d1_refer[] = {
2516 	{
2517 		.path = dir_s1d1,
2518 		.access = LANDLOCK_ACCESS_FS_REFER,
2519 	},
2520 	{},
2521 };
2522 
2523 const struct rule layer_dir_s1d1_execute[] = {
2524 	{
2525 		/* Matches a parent directory. */
2526 		.path = dir_s1d1,
2527 		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2528 	},
2529 	{},
2530 };
2531 
2532 const struct rule layer_dir_s2d1_execute[] = {
2533 	{
2534 		/* Does not match a parent directory. */
2535 		.path = dir_s2d1,
2536 		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2537 	},
2538 	{},
2539 };
2540 
2541 /*
2542  * Tests precedence over renames: denied by default for different parent
2543  * directories, *with* a rule matching a parent directory, but not directly
2544  * denying access (with MAKE_REG nor REMOVE).
2545  */
TEST_F_FORK(layout1,refer_denied_by_default1)2546 TEST_F_FORK(layout1, refer_denied_by_default1)
2547 {
2548 	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2549 				layer_dir_s1d1_execute);
2550 }
2551 
2552 /*
2553  * Same test but this time turning around the ABI version order: the first
2554  * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2555  */
TEST_F_FORK(layout1,refer_denied_by_default2)2556 TEST_F_FORK(layout1, refer_denied_by_default2)
2557 {
2558 	refer_denied_by_default(_metadata, layer_dir_s1d1_execute, EXDEV,
2559 				layer_dir_s1d1_refer);
2560 }
2561 
2562 /*
2563  * Tests precedence over renames: denied by default for different parent
2564  * directories, *without* a rule matching a parent directory, but not directly
2565  * denying access (with MAKE_REG nor REMOVE).
2566  */
TEST_F_FORK(layout1,refer_denied_by_default3)2567 TEST_F_FORK(layout1, refer_denied_by_default3)
2568 {
2569 	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2570 				layer_dir_s2d1_execute);
2571 }
2572 
2573 /*
2574  * Same test but this time turning around the ABI version order: the first
2575  * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2576  */
TEST_F_FORK(layout1,refer_denied_by_default4)2577 TEST_F_FORK(layout1, refer_denied_by_default4)
2578 {
2579 	refer_denied_by_default(_metadata, layer_dir_s2d1_execute, EXDEV,
2580 				layer_dir_s1d1_refer);
2581 }
2582 
2583 /*
2584  * Tests walking through a denied root mount.
2585  */
TEST_F_FORK(layout1,refer_mount_root_deny)2586 TEST_F_FORK(layout1, refer_mount_root_deny)
2587 {
2588 	const struct landlock_ruleset_attr ruleset_attr = {
2589 		.handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_DIR,
2590 	};
2591 	int root_fd, ruleset_fd;
2592 
2593 	/* Creates a mount object from a non-mount point. */
2594 	set_cap(_metadata, CAP_SYS_ADMIN);
2595 	root_fd =
2596 		open_tree(AT_FDCWD, dir_s1d1,
2597 			  AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
2598 	clear_cap(_metadata, CAP_SYS_ADMIN);
2599 	ASSERT_LE(0, root_fd);
2600 
2601 	ruleset_fd =
2602 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
2603 	ASSERT_LE(0, ruleset_fd);
2604 
2605 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
2606 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
2607 	EXPECT_EQ(0, close(ruleset_fd));
2608 
2609 	/* Link denied by Landlock: EACCES. */
2610 	EXPECT_EQ(-1, linkat(root_fd, ".", root_fd, "does_not_exist", 0));
2611 	EXPECT_EQ(EACCES, errno);
2612 
2613 	/* renameat2() always returns EBUSY. */
2614 	EXPECT_EQ(-1, renameat2(root_fd, ".", root_fd, "does_not_exist", 0));
2615 	EXPECT_EQ(EBUSY, errno);
2616 
2617 	EXPECT_EQ(0, close(root_fd));
2618 }
2619 
TEST_F_FORK(layout1,refer_part_mount_tree_is_allowed)2620 TEST_F_FORK(layout1, refer_part_mount_tree_is_allowed)
2621 {
2622 	const struct rule layer1[] = {
2623 		{
2624 			/* Parent mount point. */
2625 			.path = dir_s3d1,
2626 			.access = LANDLOCK_ACCESS_FS_REFER |
2627 				  LANDLOCK_ACCESS_FS_MAKE_REG,
2628 		},
2629 		{
2630 			/*
2631 			 * Removing the source file is allowed because its
2632 			 * access rights are already a superset of the
2633 			 * destination.
2634 			 */
2635 			.path = dir_s3d4,
2636 			.access = LANDLOCK_ACCESS_FS_REFER |
2637 				  LANDLOCK_ACCESS_FS_MAKE_REG |
2638 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
2639 		},
2640 		{},
2641 	};
2642 	int ruleset_fd;
2643 
2644 	ASSERT_EQ(0, unlink(file1_s3d3));
2645 	ruleset_fd = create_ruleset(_metadata,
2646 				    LANDLOCK_ACCESS_FS_REFER |
2647 					    LANDLOCK_ACCESS_FS_MAKE_REG |
2648 					    LANDLOCK_ACCESS_FS_REMOVE_FILE,
2649 				    layer1);
2650 
2651 	ASSERT_LE(0, ruleset_fd);
2652 	enforce_ruleset(_metadata, ruleset_fd);
2653 	ASSERT_EQ(0, close(ruleset_fd));
2654 
2655 	ASSERT_EQ(0, rename(file1_s3d4, file1_s3d3));
2656 }
2657 
TEST_F_FORK(layout1,reparent_link)2658 TEST_F_FORK(layout1, reparent_link)
2659 {
2660 	const struct rule layer1[] = {
2661 		{
2662 			.path = dir_s1d2,
2663 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2664 		},
2665 		{
2666 			.path = dir_s1d3,
2667 			.access = LANDLOCK_ACCESS_FS_REFER,
2668 		},
2669 		{
2670 			.path = dir_s2d2,
2671 			.access = LANDLOCK_ACCESS_FS_REFER,
2672 		},
2673 		{
2674 			.path = dir_s2d3,
2675 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2676 		},
2677 		{},
2678 	};
2679 	const int ruleset_fd = create_ruleset(
2680 		_metadata,
2681 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2682 
2683 	ASSERT_LE(0, ruleset_fd);
2684 	enforce_ruleset(_metadata, ruleset_fd);
2685 	ASSERT_EQ(0, close(ruleset_fd));
2686 
2687 	ASSERT_EQ(0, unlink(file1_s1d1));
2688 	ASSERT_EQ(0, unlink(file1_s1d2));
2689 	ASSERT_EQ(0, unlink(file1_s1d3));
2690 
2691 	/* Denies linking because of missing MAKE_REG. */
2692 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
2693 	ASSERT_EQ(EACCES, errno);
2694 	/* Denies linking because of missing source and destination REFER. */
2695 	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
2696 	ASSERT_EQ(EXDEV, errno);
2697 	/* Denies linking because of missing source REFER. */
2698 	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d3));
2699 	ASSERT_EQ(EXDEV, errno);
2700 
2701 	/* Denies linking because of missing MAKE_REG. */
2702 	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d1));
2703 	ASSERT_EQ(EACCES, errno);
2704 	/* Denies linking because of missing destination REFER. */
2705 	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d2));
2706 	ASSERT_EQ(EXDEV, errno);
2707 
2708 	/* Allows linking because of REFER and MAKE_REG. */
2709 	ASSERT_EQ(0, link(file1_s2d2, file1_s1d3));
2710 	ASSERT_EQ(0, unlink(file1_s2d2));
2711 	/* Reverse linking denied because of missing MAKE_REG. */
2712 	ASSERT_EQ(-1, link(file1_s1d3, file1_s2d2));
2713 	ASSERT_EQ(EACCES, errno);
2714 	ASSERT_EQ(0, unlink(file1_s2d3));
2715 	/* Checks reverse linking. */
2716 	ASSERT_EQ(0, link(file1_s1d3, file1_s2d3));
2717 	ASSERT_EQ(0, unlink(file1_s1d3));
2718 
2719 	/*
2720 	 * This is OK for a file link, but it should not be allowed for a
2721 	 * directory rename (because of the superset of access rights.
2722 	 */
2723 	ASSERT_EQ(0, link(file1_s2d3, file1_s1d3));
2724 	ASSERT_EQ(0, unlink(file1_s1d3));
2725 
2726 	ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
2727 	ASSERT_EQ(EXDEV, errno);
2728 	ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
2729 	ASSERT_EQ(EXDEV, errno);
2730 
2731 	ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
2732 	ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
2733 }
2734 
TEST_F_FORK(layout1,reparent_rename)2735 TEST_F_FORK(layout1, reparent_rename)
2736 {
2737 	/* Same rules as for reparent_link. */
2738 	const struct rule layer1[] = {
2739 		{
2740 			.path = dir_s1d2,
2741 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2742 		},
2743 		{
2744 			.path = dir_s1d3,
2745 			.access = LANDLOCK_ACCESS_FS_REFER,
2746 		},
2747 		{
2748 			.path = dir_s2d2,
2749 			.access = LANDLOCK_ACCESS_FS_REFER,
2750 		},
2751 		{
2752 			.path = dir_s2d3,
2753 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2754 		},
2755 		{},
2756 	};
2757 	const int ruleset_fd = create_ruleset(
2758 		_metadata,
2759 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2760 
2761 	ASSERT_LE(0, ruleset_fd);
2762 	enforce_ruleset(_metadata, ruleset_fd);
2763 	ASSERT_EQ(0, close(ruleset_fd));
2764 
2765 	ASSERT_EQ(0, unlink(file1_s1d2));
2766 	ASSERT_EQ(0, unlink(file1_s1d3));
2767 
2768 	/* Denies renaming because of missing MAKE_REG. */
2769 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s1d1,
2770 				RENAME_EXCHANGE));
2771 	ASSERT_EQ(EACCES, errno);
2772 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file2_s1d1,
2773 				RENAME_EXCHANGE));
2774 	ASSERT_EQ(EACCES, errno);
2775 	ASSERT_EQ(0, unlink(file1_s1d1));
2776 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
2777 	ASSERT_EQ(EACCES, errno);
2778 	/* Even denies same file exchange. */
2779 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file2_s1d1,
2780 				RENAME_EXCHANGE));
2781 	ASSERT_EQ(EACCES, errno);
2782 
2783 	/* Denies renaming because of missing source and destination REFER. */
2784 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d2));
2785 	ASSERT_EQ(EXDEV, errno);
2786 	/*
2787 	 * Denies renaming because of missing MAKE_REG, source and destination
2788 	 * REFER.
2789 	 */
2790 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d1,
2791 				RENAME_EXCHANGE));
2792 	ASSERT_EQ(EACCES, errno);
2793 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s2d1,
2794 				RENAME_EXCHANGE));
2795 	ASSERT_EQ(EACCES, errno);
2796 
2797 	/* Denies renaming because of missing source REFER. */
2798 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2799 	ASSERT_EQ(EXDEV, errno);
2800 	/* Denies renaming because of missing MAKE_REG. */
2801 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d3,
2802 				RENAME_EXCHANGE));
2803 	ASSERT_EQ(EACCES, errno);
2804 
2805 	/* Denies renaming because of missing MAKE_REG. */
2806 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d1));
2807 	ASSERT_EQ(EACCES, errno);
2808 	/* Denies renaming because of missing destination REFER*/
2809 	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2810 	ASSERT_EQ(EXDEV, errno);
2811 
2812 	/* Denies exchange because of one missing MAKE_REG. */
2813 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, file2_s1d3,
2814 				RENAME_EXCHANGE));
2815 	ASSERT_EQ(EACCES, errno);
2816 	/* Allows renaming because of REFER and MAKE_REG. */
2817 	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d3));
2818 
2819 	/* Reverse renaming denied because of missing MAKE_REG. */
2820 	ASSERT_EQ(-1, rename(file1_s1d3, file1_s2d2));
2821 	ASSERT_EQ(EACCES, errno);
2822 	ASSERT_EQ(0, unlink(file1_s2d3));
2823 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2824 
2825 	/* Tests reverse renaming. */
2826 	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2827 	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s1d3,
2828 			       RENAME_EXCHANGE));
2829 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2830 
2831 	/*
2832 	 * This is OK for a file rename, but it should not be allowed for a
2833 	 * directory rename (because of the superset of access rights).
2834 	 */
2835 	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2836 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2837 
2838 	/*
2839 	 * Tests superset restrictions applied to directories.  Not only the
2840 	 * dir_s2d3's parent (dir_s2d2) should be taken into account but also
2841 	 * access rights tied to dir_s2d3. dir_s2d2 is missing one access right
2842 	 * compared to dir_s1d3/file1_s1d3 (MAKE_REG) but it is provided
2843 	 * directly by the moved dir_s2d3.
2844 	 */
2845 	ASSERT_EQ(0, rename(dir_s2d3, file1_s1d3));
2846 	ASSERT_EQ(0, rename(file1_s1d3, dir_s2d3));
2847 	/*
2848 	 * The first rename is allowed but not the exchange because dir_s1d3's
2849 	 * parent (dir_s1d2) doesn't have REFER.
2850 	 */
2851 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2852 				RENAME_EXCHANGE));
2853 	ASSERT_EQ(EXDEV, errno);
2854 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s2d3,
2855 				RENAME_EXCHANGE));
2856 	ASSERT_EQ(EXDEV, errno);
2857 	ASSERT_EQ(-1, rename(file1_s2d3, dir_s1d3));
2858 	ASSERT_EQ(EXDEV, errno);
2859 
2860 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s1d3));
2861 	ASSERT_EQ(EXDEV, errno);
2862 	ASSERT_EQ(-1, rename(file2_s1d3, file1_s1d2));
2863 	ASSERT_EQ(EXDEV, errno);
2864 
2865 	/* Renaming in the same directory is always allowed. */
2866 	ASSERT_EQ(0, rename(file2_s1d2, file1_s1d2));
2867 	ASSERT_EQ(0, rename(file2_s1d3, file1_s1d3));
2868 
2869 	ASSERT_EQ(0, unlink(file1_s1d2));
2870 	/* Denies because of missing source MAKE_REG and destination REFER. */
2871 	ASSERT_EQ(-1, rename(dir_s2d3, file1_s1d2));
2872 	ASSERT_EQ(EXDEV, errno);
2873 
2874 	ASSERT_EQ(0, unlink(file1_s1d3));
2875 	/* Denies because of missing source MAKE_REG and REFER. */
2876 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d3));
2877 	ASSERT_EQ(EXDEV, errno);
2878 }
2879 
2880 static void
reparent_exdev_layers_enforce1(struct __test_metadata * const _metadata)2881 reparent_exdev_layers_enforce1(struct __test_metadata *const _metadata)
2882 {
2883 	const struct rule layer1[] = {
2884 		{
2885 			.path = dir_s1d2,
2886 			.access = LANDLOCK_ACCESS_FS_REFER,
2887 		},
2888 		{
2889 			/* Interesting for the layer2 tests. */
2890 			.path = dir_s1d3,
2891 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2892 		},
2893 		{
2894 			.path = dir_s2d2,
2895 			.access = LANDLOCK_ACCESS_FS_REFER,
2896 		},
2897 		{
2898 			.path = dir_s2d3,
2899 			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2900 		},
2901 		{},
2902 	};
2903 	const int ruleset_fd = create_ruleset(
2904 		_metadata,
2905 		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2906 
2907 	ASSERT_LE(0, ruleset_fd);
2908 	enforce_ruleset(_metadata, ruleset_fd);
2909 	ASSERT_EQ(0, close(ruleset_fd));
2910 }
2911 
2912 static void
reparent_exdev_layers_enforce2(struct __test_metadata * const _metadata)2913 reparent_exdev_layers_enforce2(struct __test_metadata *const _metadata)
2914 {
2915 	const struct rule layer2[] = {
2916 		{
2917 			.path = dir_s2d3,
2918 			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
2919 		},
2920 		{},
2921 	};
2922 	/*
2923 	 * Same checks as before but with a second layer and a new MAKE_DIR
2924 	 * rule (and no explicit handling of REFER).
2925 	 */
2926 	const int ruleset_fd =
2927 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2);
2928 
2929 	ASSERT_LE(0, ruleset_fd);
2930 	enforce_ruleset(_metadata, ruleset_fd);
2931 	ASSERT_EQ(0, close(ruleset_fd));
2932 }
2933 
TEST_F_FORK(layout1,reparent_exdev_layers_rename1)2934 TEST_F_FORK(layout1, reparent_exdev_layers_rename1)
2935 {
2936 	ASSERT_EQ(0, unlink(file1_s2d2));
2937 	ASSERT_EQ(0, unlink(file1_s2d3));
2938 
2939 	reparent_exdev_layers_enforce1(_metadata);
2940 
2941 	/*
2942 	 * Moving the dir_s1d3 directory below dir_s2d2 is allowed by Landlock
2943 	 * because it doesn't inherit new access rights.
2944 	 */
2945 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
2946 	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
2947 
2948 	/*
2949 	 * Moving the dir_s1d3 directory below dir_s2d3 is allowed, even if it
2950 	 * gets a new inherited access rights (MAKE_REG), because MAKE_REG is
2951 	 * already allowed for dir_s1d3.
2952 	 */
2953 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d3));
2954 	ASSERT_EQ(0, rename(file1_s2d3, dir_s1d3));
2955 
2956 	/*
2957 	 * However, moving the file1_s1d3 file below dir_s2d3 is allowed
2958 	 * because it cannot inherit MAKE_REG right (which is dedicated to
2959 	 * directories).
2960 	 */
2961 	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2962 
2963 	reparent_exdev_layers_enforce2(_metadata);
2964 
2965 	/*
2966 	 * Moving the dir_s1d3 directory below dir_s2d2 is now denied because
2967 	 * MAKE_DIR is not tied to dir_s2d2.
2968 	 */
2969 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d2));
2970 	ASSERT_EQ(EACCES, errno);
2971 
2972 	/*
2973 	 * Moving the dir_s1d3 directory below dir_s2d3 is forbidden because it
2974 	 * would grants MAKE_REG and MAKE_DIR rights to it.
2975 	 */
2976 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
2977 	ASSERT_EQ(EXDEV, errno);
2978 
2979 	/*
2980 	 * Moving the file2_s1d3 file below dir_s2d3 is denied because the
2981 	 * second layer does not handle REFER, which is always denied by
2982 	 * default.
2983 	 */
2984 	ASSERT_EQ(-1, rename(file2_s1d3, file1_s2d3));
2985 	ASSERT_EQ(EXDEV, errno);
2986 }
2987 
TEST_F_FORK(layout1,reparent_exdev_layers_rename2)2988 TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
2989 {
2990 	reparent_exdev_layers_enforce1(_metadata);
2991 
2992 	/* Checks EACCES predominance over EXDEV. */
2993 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
2994 	ASSERT_EQ(EACCES, errno);
2995 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d2));
2996 	ASSERT_EQ(EACCES, errno);
2997 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
2998 	ASSERT_EQ(EXDEV, errno);
2999 	/* Modify layout! */
3000 	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d3));
3001 
3002 	/* Without REFER source. */
3003 	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
3004 	ASSERT_EQ(EXDEV, errno);
3005 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
3006 	ASSERT_EQ(EXDEV, errno);
3007 
3008 	reparent_exdev_layers_enforce2(_metadata);
3009 
3010 	/* Checks EACCES predominance over EXDEV. */
3011 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
3012 	ASSERT_EQ(EACCES, errno);
3013 	/* Checks with actual file2_s1d2. */
3014 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d2));
3015 	ASSERT_EQ(EACCES, errno);
3016 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
3017 	ASSERT_EQ(EXDEV, errno);
3018 	/*
3019 	 * Modifying the layout is now denied because the second layer does not
3020 	 * handle REFER, which is always denied by default.
3021 	 */
3022 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
3023 	ASSERT_EQ(EXDEV, errno);
3024 
3025 	/* Without REFER source, EACCES wins over EXDEV. */
3026 	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
3027 	ASSERT_EQ(EACCES, errno);
3028 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
3029 	ASSERT_EQ(EACCES, errno);
3030 }
3031 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange1)3032 TEST_F_FORK(layout1, reparent_exdev_layers_exchange1)
3033 {
3034 	const char *const dir_file1_s1d2 = file1_s1d2, *const dir_file2_s2d3 =
3035 							       file2_s2d3;
3036 
3037 	ASSERT_EQ(0, unlink(file1_s1d2));
3038 	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
3039 	ASSERT_EQ(0, unlink(file2_s2d3));
3040 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3041 
3042 	reparent_exdev_layers_enforce1(_metadata);
3043 
3044 	/* Error predominance with file exchange: returns EXDEV and EACCES. */
3045 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
3046 				RENAME_EXCHANGE));
3047 	ASSERT_EQ(EACCES, errno);
3048 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
3049 				RENAME_EXCHANGE));
3050 	ASSERT_EQ(EACCES, errno);
3051 
3052 	/*
3053 	 * Checks with directories which creation could be allowed, but denied
3054 	 * because of access rights that would be inherited.
3055 	 */
3056 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
3057 				dir_file2_s2d3, RENAME_EXCHANGE));
3058 	ASSERT_EQ(EXDEV, errno);
3059 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
3060 				dir_file1_s1d2, RENAME_EXCHANGE));
3061 	ASSERT_EQ(EXDEV, errno);
3062 
3063 	/* Checks with same access rights. */
3064 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
3065 			       RENAME_EXCHANGE));
3066 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
3067 			       RENAME_EXCHANGE));
3068 
3069 	/* Checks with different (child-only) access rights. */
3070 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
3071 			       RENAME_EXCHANGE));
3072 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
3073 			       RENAME_EXCHANGE));
3074 
3075 	/*
3076 	 * Checks that exchange between file and directory are consistent.
3077 	 *
3078 	 * Moving a file (file1_s2d2) to a directory which only grants more
3079 	 * directory-related access rights is allowed, and at the same time
3080 	 * moving a directory (dir_file2_s2d3) to another directory which
3081 	 * grants less access rights is allowed too.
3082 	 *
3083 	 * See layout1.reparent_exdev_layers_exchange3 for inverted arguments.
3084 	 */
3085 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3086 			       RENAME_EXCHANGE));
3087 	/*
3088 	 * However, moving back the directory is denied because it would get
3089 	 * more access rights than the current state and because file creation
3090 	 * is forbidden (in dir_s2d2).
3091 	 */
3092 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3093 				RENAME_EXCHANGE));
3094 	ASSERT_EQ(EACCES, errno);
3095 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3096 				RENAME_EXCHANGE));
3097 	ASSERT_EQ(EACCES, errno);
3098 
3099 	reparent_exdev_layers_enforce2(_metadata);
3100 
3101 	/* Error predominance with file exchange: returns EXDEV and EACCES. */
3102 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
3103 				RENAME_EXCHANGE));
3104 	ASSERT_EQ(EACCES, errno);
3105 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
3106 				RENAME_EXCHANGE));
3107 	ASSERT_EQ(EACCES, errno);
3108 
3109 	/* Checks with directories which creation is now denied. */
3110 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
3111 				dir_file2_s2d3, RENAME_EXCHANGE));
3112 	ASSERT_EQ(EACCES, errno);
3113 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
3114 				dir_file1_s1d2, RENAME_EXCHANGE));
3115 	ASSERT_EQ(EACCES, errno);
3116 
3117 	/* Checks with different (child-only) access rights. */
3118 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
3119 				RENAME_EXCHANGE));
3120 	/* Denied because of MAKE_DIR. */
3121 	ASSERT_EQ(EACCES, errno);
3122 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
3123 				RENAME_EXCHANGE));
3124 	ASSERT_EQ(EACCES, errno);
3125 
3126 	/* Checks with different (child-only) access rights. */
3127 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
3128 				RENAME_EXCHANGE));
3129 	/* Denied because of MAKE_DIR. */
3130 	ASSERT_EQ(EACCES, errno);
3131 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
3132 				RENAME_EXCHANGE));
3133 	ASSERT_EQ(EACCES, errno);
3134 
3135 	/* See layout1.reparent_exdev_layers_exchange2 for complement. */
3136 }
3137 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange2)3138 TEST_F_FORK(layout1, reparent_exdev_layers_exchange2)
3139 {
3140 	const char *const dir_file2_s2d3 = file2_s2d3;
3141 
3142 	ASSERT_EQ(0, unlink(file2_s2d3));
3143 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3144 
3145 	reparent_exdev_layers_enforce1(_metadata);
3146 	reparent_exdev_layers_enforce2(_metadata);
3147 
3148 	/* Checks that exchange between file and directory are consistent. */
3149 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3150 				RENAME_EXCHANGE));
3151 	ASSERT_EQ(EACCES, errno);
3152 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3153 				RENAME_EXCHANGE));
3154 	ASSERT_EQ(EACCES, errno);
3155 }
3156 
TEST_F_FORK(layout1,reparent_exdev_layers_exchange3)3157 TEST_F_FORK(layout1, reparent_exdev_layers_exchange3)
3158 {
3159 	const char *const dir_file2_s2d3 = file2_s2d3;
3160 
3161 	ASSERT_EQ(0, unlink(file2_s2d3));
3162 	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
3163 
3164 	reparent_exdev_layers_enforce1(_metadata);
3165 
3166 	/*
3167 	 * Checks that exchange between file and directory are consistent,
3168 	 * including with inverted arguments (see
3169 	 * layout1.reparent_exdev_layers_exchange1).
3170 	 */
3171 	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3172 			       RENAME_EXCHANGE));
3173 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
3174 				RENAME_EXCHANGE));
3175 	ASSERT_EQ(EACCES, errno);
3176 	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
3177 				RENAME_EXCHANGE));
3178 	ASSERT_EQ(EACCES, errno);
3179 }
3180 
TEST_F_FORK(layout1,reparent_remove)3181 TEST_F_FORK(layout1, reparent_remove)
3182 {
3183 	const struct rule layer1[] = {
3184 		{
3185 			.path = dir_s1d1,
3186 			.access = LANDLOCK_ACCESS_FS_REFER |
3187 				  LANDLOCK_ACCESS_FS_REMOVE_DIR,
3188 		},
3189 		{
3190 			.path = dir_s1d2,
3191 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
3192 		},
3193 		{
3194 			.path = dir_s2d1,
3195 			.access = LANDLOCK_ACCESS_FS_REFER |
3196 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
3197 		},
3198 		{},
3199 	};
3200 	const int ruleset_fd = create_ruleset(
3201 		_metadata,
3202 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR |
3203 			LANDLOCK_ACCESS_FS_REMOVE_FILE,
3204 		layer1);
3205 
3206 	ASSERT_LE(0, ruleset_fd);
3207 	enforce_ruleset(_metadata, ruleset_fd);
3208 	ASSERT_EQ(0, close(ruleset_fd));
3209 
3210 	/* Access denied because of wrong/swapped remove file/dir. */
3211 	ASSERT_EQ(-1, rename(file1_s1d1, dir_s2d2));
3212 	ASSERT_EQ(EACCES, errno);
3213 	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d1));
3214 	ASSERT_EQ(EACCES, errno);
3215 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d2,
3216 				RENAME_EXCHANGE));
3217 	ASSERT_EQ(EACCES, errno);
3218 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d3,
3219 				RENAME_EXCHANGE));
3220 	ASSERT_EQ(EACCES, errno);
3221 
3222 	/* Access allowed thanks to the matching rights. */
3223 	ASSERT_EQ(-1, rename(file1_s2d1, dir_s1d2));
3224 	ASSERT_EQ(EISDIR, errno);
3225 	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d1));
3226 	ASSERT_EQ(ENOTDIR, errno);
3227 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
3228 	ASSERT_EQ(ENOTDIR, errno);
3229 	ASSERT_EQ(0, unlink(file1_s2d1));
3230 	ASSERT_EQ(0, unlink(file1_s1d3));
3231 	ASSERT_EQ(0, unlink(file2_s1d3));
3232 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d1));
3233 
3234 	/* Effectively removes a file and a directory by exchanging them. */
3235 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
3236 	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
3237 			       RENAME_EXCHANGE));
3238 	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
3239 				RENAME_EXCHANGE));
3240 	ASSERT_EQ(EACCES, errno);
3241 }
3242 
TEST_F_FORK(layout1,reparent_dom_superset)3243 TEST_F_FORK(layout1, reparent_dom_superset)
3244 {
3245 	const struct rule layer1[] = {
3246 		{
3247 			.path = dir_s1d2,
3248 			.access = LANDLOCK_ACCESS_FS_REFER,
3249 		},
3250 		{
3251 			.path = file1_s1d2,
3252 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
3253 		},
3254 		{
3255 			.path = dir_s1d3,
3256 			.access = LANDLOCK_ACCESS_FS_MAKE_SOCK |
3257 				  LANDLOCK_ACCESS_FS_EXECUTE,
3258 		},
3259 		{
3260 			.path = dir_s2d2,
3261 			.access = LANDLOCK_ACCESS_FS_REFER |
3262 				  LANDLOCK_ACCESS_FS_EXECUTE |
3263 				  LANDLOCK_ACCESS_FS_MAKE_SOCK,
3264 		},
3265 		{
3266 			.path = dir_s2d3,
3267 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3268 				  LANDLOCK_ACCESS_FS_MAKE_FIFO,
3269 		},
3270 		{},
3271 	};
3272 	int ruleset_fd = create_ruleset(_metadata,
3273 					LANDLOCK_ACCESS_FS_REFER |
3274 						LANDLOCK_ACCESS_FS_EXECUTE |
3275 						LANDLOCK_ACCESS_FS_MAKE_SOCK |
3276 						LANDLOCK_ACCESS_FS_READ_FILE |
3277 						LANDLOCK_ACCESS_FS_MAKE_FIFO,
3278 					layer1);
3279 
3280 	ASSERT_LE(0, ruleset_fd);
3281 	enforce_ruleset(_metadata, ruleset_fd);
3282 	ASSERT_EQ(0, close(ruleset_fd));
3283 
3284 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d1));
3285 	ASSERT_EQ(EXDEV, errno);
3286 	/*
3287 	 * Moving file1_s1d2 beneath dir_s2d3 would grant it the READ_FILE
3288 	 * access right.
3289 	 */
3290 	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d3));
3291 	ASSERT_EQ(EXDEV, errno);
3292 	/*
3293 	 * Moving file1_s1d2 should be allowed even if dir_s2d2 grants a
3294 	 * superset of access rights compared to dir_s1d2, because file1_s1d2
3295 	 * already has these access rights anyway.
3296 	 */
3297 	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d2));
3298 	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d2));
3299 
3300 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
3301 	ASSERT_EQ(EXDEV, errno);
3302 	/*
3303 	 * Moving dir_s1d3 beneath dir_s2d3 would grant it the MAKE_FIFO access
3304 	 * right.
3305 	 */
3306 	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
3307 	ASSERT_EQ(EXDEV, errno);
3308 	/*
3309 	 * Moving dir_s1d3 should be allowed even if dir_s2d2 grants a superset
3310 	 * of access rights compared to dir_s1d2, because dir_s1d3 already has
3311 	 * these access rights anyway.
3312 	 */
3313 	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
3314 	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
3315 
3316 	/*
3317 	 * Moving file1_s2d3 beneath dir_s1d2 is allowed, but moving it back
3318 	 * will be denied because the new inherited access rights from dir_s1d2
3319 	 * will be less than the destination (original) dir_s2d3.  This is a
3320 	 * sinkhole scenario where we cannot move back files or directories.
3321 	 */
3322 	ASSERT_EQ(0, rename(file1_s2d3, file2_s1d2));
3323 	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
3324 	ASSERT_EQ(EXDEV, errno);
3325 	ASSERT_EQ(0, unlink(file2_s1d2));
3326 	ASSERT_EQ(0, unlink(file2_s2d3));
3327 	/*
3328 	 * Checks similar directory one-way move: dir_s2d3 loses EXECUTE and
3329 	 * MAKE_SOCK which were inherited from dir_s1d3.
3330 	 */
3331 	ASSERT_EQ(0, rename(dir_s2d3, file2_s1d2));
3332 	ASSERT_EQ(-1, rename(file2_s1d2, dir_s2d3));
3333 	ASSERT_EQ(EXDEV, errno);
3334 }
3335 
TEST_F_FORK(layout1,remove_dir)3336 TEST_F_FORK(layout1, remove_dir)
3337 {
3338 	const struct rule rules[] = {
3339 		{
3340 			.path = dir_s1d2,
3341 			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
3342 		},
3343 		{},
3344 	};
3345 	const int ruleset_fd =
3346 		create_ruleset(_metadata, rules[0].access, rules);
3347 
3348 	ASSERT_LE(0, ruleset_fd);
3349 
3350 	ASSERT_EQ(0, unlink(file1_s1d1));
3351 	ASSERT_EQ(0, unlink(file1_s1d2));
3352 	ASSERT_EQ(0, unlink(file1_s1d3));
3353 	ASSERT_EQ(0, unlink(file2_s1d3));
3354 
3355 	enforce_ruleset(_metadata, ruleset_fd);
3356 	ASSERT_EQ(0, close(ruleset_fd));
3357 
3358 	ASSERT_EQ(0, rmdir(dir_s1d3));
3359 	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
3360 	ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
3361 
3362 	/* dir_s1d2 itself cannot be removed. */
3363 	ASSERT_EQ(-1, rmdir(dir_s1d2));
3364 	ASSERT_EQ(EACCES, errno);
3365 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR));
3366 	ASSERT_EQ(EACCES, errno);
3367 	ASSERT_EQ(-1, rmdir(dir_s1d1));
3368 	ASSERT_EQ(EACCES, errno);
3369 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR));
3370 	ASSERT_EQ(EACCES, errno);
3371 }
3372 
TEST_F_FORK(layout1,remove_file)3373 TEST_F_FORK(layout1, remove_file)
3374 {
3375 	const struct rule rules[] = {
3376 		{
3377 			.path = dir_s1d2,
3378 			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
3379 		},
3380 		{},
3381 	};
3382 	const int ruleset_fd =
3383 		create_ruleset(_metadata, rules[0].access, rules);
3384 
3385 	ASSERT_LE(0, ruleset_fd);
3386 	enforce_ruleset(_metadata, ruleset_fd);
3387 	ASSERT_EQ(0, close(ruleset_fd));
3388 
3389 	ASSERT_EQ(-1, unlink(file1_s1d1));
3390 	ASSERT_EQ(EACCES, errno);
3391 	ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0));
3392 	ASSERT_EQ(EACCES, errno);
3393 	ASSERT_EQ(0, unlink(file1_s1d2));
3394 	ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0));
3395 }
3396 
test_make_file(struct __test_metadata * const _metadata,const __u64 access,const mode_t mode,const dev_t dev)3397 static void test_make_file(struct __test_metadata *const _metadata,
3398 			   const __u64 access, const mode_t mode,
3399 			   const dev_t dev)
3400 {
3401 	const struct rule rules[] = {
3402 		{
3403 			.path = dir_s1d2,
3404 			.access = access,
3405 		},
3406 		{},
3407 	};
3408 	const int ruleset_fd = create_ruleset(_metadata, access, rules);
3409 
3410 	ASSERT_LE(0, ruleset_fd);
3411 
3412 	ASSERT_EQ(0, unlink(file1_s1d1));
3413 	ASSERT_EQ(0, unlink(file2_s1d1));
3414 	ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev))
3415 	{
3416 		TH_LOG("Failed to make file \"%s\": %s", file2_s1d1,
3417 		       strerror(errno));
3418 	};
3419 
3420 	ASSERT_EQ(0, unlink(file1_s1d2));
3421 	ASSERT_EQ(0, unlink(file2_s1d2));
3422 
3423 	ASSERT_EQ(0, unlink(file1_s1d3));
3424 	ASSERT_EQ(0, unlink(file2_s1d3));
3425 
3426 	enforce_ruleset(_metadata, ruleset_fd);
3427 	ASSERT_EQ(0, close(ruleset_fd));
3428 
3429 	ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev));
3430 	ASSERT_EQ(EACCES, errno);
3431 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3432 	ASSERT_EQ(EACCES, errno);
3433 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3434 	ASSERT_EQ(EACCES, errno);
3435 
3436 	ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev))
3437 	{
3438 		TH_LOG("Failed to make file \"%s\": %s", file1_s1d2,
3439 		       strerror(errno));
3440 	};
3441 	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3442 	ASSERT_EQ(0, unlink(file2_s1d2));
3443 	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3444 
3445 	ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev));
3446 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3447 	ASSERT_EQ(0, unlink(file2_s1d3));
3448 	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3449 }
3450 
TEST_F_FORK(layout1,make_char)3451 TEST_F_FORK(layout1, make_char)
3452 {
3453 	/* Creates a /dev/null device. */
3454 	set_cap(_metadata, CAP_MKNOD);
3455 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR,
3456 		       makedev(1, 3));
3457 }
3458 
TEST_F_FORK(layout1,make_block)3459 TEST_F_FORK(layout1, make_block)
3460 {
3461 	/* Creates a /dev/loop0 device. */
3462 	set_cap(_metadata, CAP_MKNOD);
3463 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK,
3464 		       makedev(7, 0));
3465 }
3466 
TEST_F_FORK(layout1,make_reg_1)3467 TEST_F_FORK(layout1, make_reg_1)
3468 {
3469 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
3470 }
3471 
TEST_F_FORK(layout1,make_reg_2)3472 TEST_F_FORK(layout1, make_reg_2)
3473 {
3474 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
3475 }
3476 
TEST_F_FORK(layout1,make_sock)3477 TEST_F_FORK(layout1, make_sock)
3478 {
3479 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
3480 }
3481 
TEST_F_FORK(layout1,make_fifo)3482 TEST_F_FORK(layout1, make_fifo)
3483 {
3484 	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
3485 }
3486 
TEST_F_FORK(layout1,make_sym)3487 TEST_F_FORK(layout1, make_sym)
3488 {
3489 	const struct rule rules[] = {
3490 		{
3491 			.path = dir_s1d2,
3492 			.access = LANDLOCK_ACCESS_FS_MAKE_SYM,
3493 		},
3494 		{},
3495 	};
3496 	const int ruleset_fd =
3497 		create_ruleset(_metadata, rules[0].access, rules);
3498 
3499 	ASSERT_LE(0, ruleset_fd);
3500 
3501 	ASSERT_EQ(0, unlink(file1_s1d1));
3502 	ASSERT_EQ(0, unlink(file2_s1d1));
3503 	ASSERT_EQ(0, symlink("none", file2_s1d1));
3504 
3505 	ASSERT_EQ(0, unlink(file1_s1d2));
3506 	ASSERT_EQ(0, unlink(file2_s1d2));
3507 
3508 	ASSERT_EQ(0, unlink(file1_s1d3));
3509 	ASSERT_EQ(0, unlink(file2_s1d3));
3510 
3511 	enforce_ruleset(_metadata, ruleset_fd);
3512 	ASSERT_EQ(0, close(ruleset_fd));
3513 
3514 	ASSERT_EQ(-1, symlink("none", file1_s1d1));
3515 	ASSERT_EQ(EACCES, errno);
3516 	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3517 	ASSERT_EQ(EACCES, errno);
3518 	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3519 	ASSERT_EQ(EACCES, errno);
3520 
3521 	ASSERT_EQ(0, symlink("none", file1_s1d2));
3522 	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3523 	ASSERT_EQ(0, unlink(file2_s1d2));
3524 	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3525 
3526 	ASSERT_EQ(0, symlink("none", file1_s1d3));
3527 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3528 	ASSERT_EQ(0, unlink(file2_s1d3));
3529 	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3530 }
3531 
TEST_F_FORK(layout1,make_dir)3532 TEST_F_FORK(layout1, make_dir)
3533 {
3534 	const struct rule rules[] = {
3535 		{
3536 			.path = dir_s1d2,
3537 			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
3538 		},
3539 		{},
3540 	};
3541 	const int ruleset_fd =
3542 		create_ruleset(_metadata, rules[0].access, rules);
3543 
3544 	ASSERT_LE(0, ruleset_fd);
3545 
3546 	ASSERT_EQ(0, unlink(file1_s1d1));
3547 	ASSERT_EQ(0, unlink(file1_s1d2));
3548 	ASSERT_EQ(0, unlink(file1_s1d3));
3549 
3550 	enforce_ruleset(_metadata, ruleset_fd);
3551 	ASSERT_EQ(0, close(ruleset_fd));
3552 
3553 	/* Uses file_* as directory names. */
3554 	ASSERT_EQ(-1, mkdir(file1_s1d1, 0700));
3555 	ASSERT_EQ(EACCES, errno);
3556 	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
3557 	ASSERT_EQ(0, mkdir(file1_s1d3, 0700));
3558 }
3559 
open_proc_fd(struct __test_metadata * const _metadata,const int fd,const int open_flags)3560 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd,
3561 			const int open_flags)
3562 {
3563 	static const char path_template[] = "/proc/self/fd/%d";
3564 	char procfd_path[sizeof(path_template) + 10];
3565 	const int procfd_path_size =
3566 		snprintf(procfd_path, sizeof(procfd_path), path_template, fd);
3567 
3568 	ASSERT_LT(procfd_path_size, sizeof(procfd_path));
3569 	return open(procfd_path, open_flags);
3570 }
3571 
TEST_F_FORK(layout1,proc_unlinked_file)3572 TEST_F_FORK(layout1, proc_unlinked_file)
3573 {
3574 	const struct rule rules[] = {
3575 		{
3576 			.path = file1_s1d2,
3577 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3578 		},
3579 		{},
3580 	};
3581 	int reg_fd, proc_fd;
3582 	const int ruleset_fd = create_ruleset(
3583 		_metadata,
3584 		LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE,
3585 		rules);
3586 
3587 	ASSERT_LE(0, ruleset_fd);
3588 	enforce_ruleset(_metadata, ruleset_fd);
3589 	ASSERT_EQ(0, close(ruleset_fd));
3590 
3591 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
3592 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
3593 	reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC);
3594 	ASSERT_LE(0, reg_fd);
3595 	ASSERT_EQ(0, unlink(file1_s1d2));
3596 
3597 	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC);
3598 	ASSERT_LE(0, proc_fd);
3599 	ASSERT_EQ(0, close(proc_fd));
3600 
3601 	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC);
3602 	ASSERT_EQ(-1, proc_fd)
3603 	{
3604 		TH_LOG("Successfully opened /proc/self/fd/%d: %s", reg_fd,
3605 		       strerror(errno));
3606 	}
3607 	ASSERT_EQ(EACCES, errno);
3608 
3609 	ASSERT_EQ(0, close(reg_fd));
3610 }
3611 
TEST_F_FORK(layout1,proc_pipe)3612 TEST_F_FORK(layout1, proc_pipe)
3613 {
3614 	int proc_fd;
3615 	int pipe_fds[2];
3616 	char buf = '\0';
3617 	const struct rule rules[] = {
3618 		{
3619 			.path = dir_s1d2,
3620 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3621 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3622 		},
3623 		{},
3624 	};
3625 	/* Limits read and write access to files tied to the filesystem. */
3626 	const int ruleset_fd =
3627 		create_ruleset(_metadata, rules[0].access, rules);
3628 
3629 	ASSERT_LE(0, ruleset_fd);
3630 	enforce_ruleset(_metadata, ruleset_fd);
3631 	ASSERT_EQ(0, close(ruleset_fd));
3632 
3633 	/* Checks enforcement for normal files. */
3634 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
3635 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
3636 
3637 	/* Checks access to pipes through FD. */
3638 	ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC));
3639 	ASSERT_EQ(1, write(pipe_fds[1], ".", 1))
3640 	{
3641 		TH_LOG("Failed to write in pipe: %s", strerror(errno));
3642 	}
3643 	ASSERT_EQ(1, read(pipe_fds[0], &buf, 1));
3644 	ASSERT_EQ('.', buf);
3645 
3646 	/* Checks write access to pipe through /proc/self/fd . */
3647 	proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC);
3648 	ASSERT_LE(0, proc_fd);
3649 	ASSERT_EQ(1, write(proc_fd, ".", 1))
3650 	{
3651 		TH_LOG("Failed to write through /proc/self/fd/%d: %s",
3652 		       pipe_fds[1], strerror(errno));
3653 	}
3654 	ASSERT_EQ(0, close(proc_fd));
3655 
3656 	/* Checks read access to pipe through /proc/self/fd . */
3657 	proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC);
3658 	ASSERT_LE(0, proc_fd);
3659 	buf = '\0';
3660 	ASSERT_EQ(1, read(proc_fd, &buf, 1))
3661 	{
3662 		TH_LOG("Failed to read through /proc/self/fd/%d: %s",
3663 		       pipe_fds[1], strerror(errno));
3664 	}
3665 	ASSERT_EQ(0, close(proc_fd));
3666 
3667 	ASSERT_EQ(0, close(pipe_fds[0]));
3668 	ASSERT_EQ(0, close(pipe_fds[1]));
3669 }
3670 
3671 /* Invokes truncate(2) and returns its errno or 0. */
test_truncate(const char * const path)3672 static int test_truncate(const char *const path)
3673 {
3674 	if (truncate(path, 10) < 0)
3675 		return errno;
3676 	return 0;
3677 }
3678 
3679 /*
3680  * Invokes creat(2) and returns its errno or 0.
3681  * Closes the opened file descriptor on success.
3682  */
test_creat(const char * const path)3683 static int test_creat(const char *const path)
3684 {
3685 	int fd = creat(path, 0600);
3686 
3687 	if (fd < 0)
3688 		return errno;
3689 
3690 	/*
3691 	 * Mixing error codes from close(2) and creat(2) should not lead to any
3692 	 * (access type) confusion for this test.
3693 	 */
3694 	if (close(fd) < 0)
3695 		return errno;
3696 	return 0;
3697 }
3698 
3699 /*
3700  * Exercises file truncation when it's not restricted,
3701  * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed.
3702  */
TEST_F_FORK(layout1,truncate_unhandled)3703 TEST_F_FORK(layout1, truncate_unhandled)
3704 {
3705 	const char *const file_r = file1_s1d1;
3706 	const char *const file_w = file2_s1d1;
3707 	const char *const file_none = file1_s1d2;
3708 	const struct rule rules[] = {
3709 		{
3710 			.path = file_r,
3711 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3712 		},
3713 		{
3714 			.path = file_w,
3715 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3716 		},
3717 		/* Implicitly: No rights for file_none. */
3718 		{},
3719 	};
3720 
3721 	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3722 			      LANDLOCK_ACCESS_FS_WRITE_FILE;
3723 	int ruleset_fd;
3724 
3725 	/* Enables Landlock. */
3726 	ruleset_fd = create_ruleset(_metadata, handled, rules);
3727 
3728 	ASSERT_LE(0, ruleset_fd);
3729 	enforce_ruleset(_metadata, ruleset_fd);
3730 	ASSERT_EQ(0, close(ruleset_fd));
3731 
3732 	/*
3733 	 * Checks read right: truncate and open with O_TRUNC work, unless the
3734 	 * file is attempted to be opened for writing.
3735 	 */
3736 	EXPECT_EQ(0, test_truncate(file_r));
3737 	EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC));
3738 	EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC));
3739 	EXPECT_EQ(EACCES, test_creat(file_r));
3740 
3741 	/*
3742 	 * Checks write right: truncate and open with O_TRUNC work, unless the
3743 	 * file is attempted to be opened for reading.
3744 	 */
3745 	EXPECT_EQ(0, test_truncate(file_w));
3746 	EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC));
3747 	EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC));
3748 	EXPECT_EQ(0, test_creat(file_w));
3749 
3750 	/*
3751 	 * Checks "no rights" case: truncate works but all open attempts fail,
3752 	 * including creat.
3753 	 */
3754 	EXPECT_EQ(0, test_truncate(file_none));
3755 	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3756 	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3757 	EXPECT_EQ(EACCES, test_creat(file_none));
3758 }
3759 
TEST_F_FORK(layout1,truncate)3760 TEST_F_FORK(layout1, truncate)
3761 {
3762 	const char *const file_rwt = file1_s1d1;
3763 	const char *const file_rw = file2_s1d1;
3764 	const char *const file_rt = file1_s1d2;
3765 	const char *const file_t = file2_s1d2;
3766 	const char *const file_none = file1_s1d3;
3767 	const char *const dir_t = dir_s2d1;
3768 	const char *const file_in_dir_t = file1_s2d1;
3769 	const char *const dir_w = dir_s3d1;
3770 	const char *const file_in_dir_w = file1_s3d1;
3771 	const struct rule rules[] = {
3772 		{
3773 			.path = file_rwt,
3774 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3775 				  LANDLOCK_ACCESS_FS_WRITE_FILE |
3776 				  LANDLOCK_ACCESS_FS_TRUNCATE,
3777 		},
3778 		{
3779 			.path = file_rw,
3780 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3781 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3782 		},
3783 		{
3784 			.path = file_rt,
3785 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3786 				  LANDLOCK_ACCESS_FS_TRUNCATE,
3787 		},
3788 		{
3789 			.path = file_t,
3790 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3791 		},
3792 		/* Implicitly: No access rights for file_none. */
3793 		{
3794 			.path = dir_t,
3795 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3796 		},
3797 		{
3798 			.path = dir_w,
3799 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3800 		},
3801 		{},
3802 	};
3803 	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3804 			      LANDLOCK_ACCESS_FS_WRITE_FILE |
3805 			      LANDLOCK_ACCESS_FS_TRUNCATE;
3806 	int ruleset_fd;
3807 
3808 	/* Enables Landlock. */
3809 	ruleset_fd = create_ruleset(_metadata, handled, rules);
3810 
3811 	ASSERT_LE(0, ruleset_fd);
3812 	enforce_ruleset(_metadata, ruleset_fd);
3813 	ASSERT_EQ(0, close(ruleset_fd));
3814 
3815 	/* Checks read, write and truncate rights: truncation works. */
3816 	EXPECT_EQ(0, test_truncate(file_rwt));
3817 	EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC));
3818 	EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC));
3819 
3820 	/* Checks read and write rights: no truncate variant works. */
3821 	EXPECT_EQ(EACCES, test_truncate(file_rw));
3822 	EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC));
3823 	EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC));
3824 
3825 	/*
3826 	 * Checks read and truncate rights: truncation works.
3827 	 *
3828 	 * Note: Files can get truncated using open() even with O_RDONLY.
3829 	 */
3830 	EXPECT_EQ(0, test_truncate(file_rt));
3831 	EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC));
3832 	EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC));
3833 
3834 	/* Checks truncate right: truncate works, but can't open file. */
3835 	EXPECT_EQ(0, test_truncate(file_t));
3836 	EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC));
3837 	EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC));
3838 
3839 	/* Checks "no rights" case: No form of truncation works. */
3840 	EXPECT_EQ(EACCES, test_truncate(file_none));
3841 	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3842 	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3843 
3844 	/*
3845 	 * Checks truncate right on directory: truncate works on contained
3846 	 * files.
3847 	 */
3848 	EXPECT_EQ(0, test_truncate(file_in_dir_t));
3849 	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC));
3850 	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC));
3851 
3852 	/*
3853 	 * Checks creat in dir_w: This requires the truncate right when
3854 	 * overwriting an existing file, but does not require it when the file
3855 	 * is new.
3856 	 */
3857 	EXPECT_EQ(EACCES, test_creat(file_in_dir_w));
3858 
3859 	ASSERT_EQ(0, unlink(file_in_dir_w));
3860 	EXPECT_EQ(0, test_creat(file_in_dir_w));
3861 }
3862 
3863 /* Invokes ftruncate(2) and returns its errno or 0. */
test_ftruncate(int fd)3864 static int test_ftruncate(int fd)
3865 {
3866 	if (ftruncate(fd, 10) < 0)
3867 		return errno;
3868 	return 0;
3869 }
3870 
TEST_F_FORK(layout1,ftruncate)3871 TEST_F_FORK(layout1, ftruncate)
3872 {
3873 	/*
3874 	 * This test opens a new file descriptor at different stages of
3875 	 * Landlock restriction:
3876 	 *
3877 	 * without restriction:                    ftruncate works
3878 	 * something else but truncate restricted: ftruncate works
3879 	 * truncate restricted and permitted:      ftruncate works
3880 	 * truncate restricted and not permitted:  ftruncate fails
3881 	 *
3882 	 * Whether this works or not is expected to depend on the time when the
3883 	 * FD was opened, not to depend on the time when ftruncate() was
3884 	 * called.
3885 	 */
3886 	const char *const path = file1_s1d1;
3887 	const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE |
3888 			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3889 	const struct rule layer1[] = {
3890 		{
3891 			.path = path,
3892 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3893 		},
3894 		{},
3895 	};
3896 	const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE;
3897 	const struct rule layer2[] = {
3898 		{
3899 			.path = path,
3900 			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3901 		},
3902 		{},
3903 	};
3904 	const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE |
3905 			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3906 	const struct rule layer3[] = {
3907 		{
3908 			.path = path,
3909 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3910 		},
3911 		{},
3912 	};
3913 	int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd;
3914 
3915 	fd_layer0 = open(path, O_WRONLY);
3916 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3917 
3918 	ruleset_fd = create_ruleset(_metadata, handled1, layer1);
3919 	ASSERT_LE(0, ruleset_fd);
3920 	enforce_ruleset(_metadata, ruleset_fd);
3921 	ASSERT_EQ(0, close(ruleset_fd));
3922 
3923 	fd_layer1 = open(path, O_WRONLY);
3924 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3925 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3926 
3927 	ruleset_fd = create_ruleset(_metadata, handled2, layer2);
3928 	ASSERT_LE(0, ruleset_fd);
3929 	enforce_ruleset(_metadata, ruleset_fd);
3930 	ASSERT_EQ(0, close(ruleset_fd));
3931 
3932 	fd_layer2 = open(path, O_WRONLY);
3933 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3934 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3935 	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3936 
3937 	ruleset_fd = create_ruleset(_metadata, handled3, layer3);
3938 	ASSERT_LE(0, ruleset_fd);
3939 	enforce_ruleset(_metadata, ruleset_fd);
3940 	ASSERT_EQ(0, close(ruleset_fd));
3941 
3942 	fd_layer3 = open(path, O_WRONLY);
3943 	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3944 	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3945 	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3946 	EXPECT_EQ(EACCES, test_ftruncate(fd_layer3));
3947 
3948 	ASSERT_EQ(0, close(fd_layer0));
3949 	ASSERT_EQ(0, close(fd_layer1));
3950 	ASSERT_EQ(0, close(fd_layer2));
3951 	ASSERT_EQ(0, close(fd_layer3));
3952 }
3953 
3954 /* clang-format off */
FIXTURE(ftruncate)3955 FIXTURE(ftruncate) {};
3956 /* clang-format on */
3957 
FIXTURE_SETUP(ftruncate)3958 FIXTURE_SETUP(ftruncate)
3959 {
3960 	prepare_layout(_metadata);
3961 	create_file(_metadata, file1_s1d1);
3962 }
3963 
FIXTURE_TEARDOWN_PARENT(ftruncate)3964 FIXTURE_TEARDOWN_PARENT(ftruncate)
3965 {
3966 	EXPECT_EQ(0, remove_path(file1_s1d1));
3967 	cleanup_layout(_metadata);
3968 }
3969 
FIXTURE_VARIANT(ftruncate)3970 FIXTURE_VARIANT(ftruncate)
3971 {
3972 	const __u64 handled;
3973 	const __u64 allowed;
3974 	const int expected_open_result;
3975 	const int expected_ftruncate_result;
3976 };
3977 
3978 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,w_w)3979 FIXTURE_VARIANT_ADD(ftruncate, w_w) {
3980 	/* clang-format on */
3981 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE,
3982 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
3983 	.expected_open_result = 0,
3984 	.expected_ftruncate_result = 0,
3985 };
3986 
3987 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,t_t)3988 FIXTURE_VARIANT_ADD(ftruncate, t_t) {
3989 	/* clang-format on */
3990 	.handled = LANDLOCK_ACCESS_FS_TRUNCATE,
3991 	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
3992 	.expected_open_result = 0,
3993 	.expected_ftruncate_result = 0,
3994 };
3995 
3996 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_w)3997 FIXTURE_VARIANT_ADD(ftruncate, wt_w) {
3998 	/* clang-format on */
3999 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
4000 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
4001 	.expected_open_result = 0,
4002 	.expected_ftruncate_result = EACCES,
4003 };
4004 
4005 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_wt)4006 FIXTURE_VARIANT_ADD(ftruncate, wt_wt) {
4007 	/* clang-format on */
4008 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
4009 	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
4010 	.expected_open_result = 0,
4011 	.expected_ftruncate_result = 0,
4012 };
4013 
4014 /* clang-format off */
FIXTURE_VARIANT_ADD(ftruncate,wt_t)4015 FIXTURE_VARIANT_ADD(ftruncate, wt_t) {
4016 	/* clang-format on */
4017 	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
4018 	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
4019 	.expected_open_result = EACCES,
4020 };
4021 
TEST_F_FORK(ftruncate,open_and_ftruncate)4022 TEST_F_FORK(ftruncate, open_and_ftruncate)
4023 {
4024 	const char *const path = file1_s1d1;
4025 	const struct rule rules[] = {
4026 		{
4027 			.path = path,
4028 			.access = variant->allowed,
4029 		},
4030 		{},
4031 	};
4032 	int fd, ruleset_fd;
4033 
4034 	/* Enables Landlock. */
4035 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4036 	ASSERT_LE(0, ruleset_fd);
4037 	enforce_ruleset(_metadata, ruleset_fd);
4038 	ASSERT_EQ(0, close(ruleset_fd));
4039 
4040 	fd = open(path, O_WRONLY);
4041 	EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
4042 	if (fd >= 0) {
4043 		EXPECT_EQ(variant->expected_ftruncate_result,
4044 			  test_ftruncate(fd));
4045 		ASSERT_EQ(0, close(fd));
4046 	}
4047 }
4048 
TEST_F_FORK(ftruncate,open_and_ftruncate_in_different_processes)4049 TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
4050 {
4051 	int child, fd, status;
4052 	int socket_fds[2];
4053 
4054 	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
4055 				socket_fds));
4056 
4057 	child = fork();
4058 	ASSERT_LE(0, child);
4059 	if (child == 0) {
4060 		/*
4061 		 * Enables Landlock in the child process, open a file descriptor
4062 		 * where truncation is forbidden and send it to the
4063 		 * non-landlocked parent process.
4064 		 */
4065 		const char *const path = file1_s1d1;
4066 		const struct rule rules[] = {
4067 			{
4068 				.path = path,
4069 				.access = variant->allowed,
4070 			},
4071 			{},
4072 		};
4073 		int fd, ruleset_fd;
4074 
4075 		ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4076 		ASSERT_LE(0, ruleset_fd);
4077 		enforce_ruleset(_metadata, ruleset_fd);
4078 		ASSERT_EQ(0, close(ruleset_fd));
4079 
4080 		fd = open(path, O_WRONLY);
4081 		ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
4082 
4083 		if (fd >= 0) {
4084 			ASSERT_EQ(0, send_fd(socket_fds[0], fd));
4085 			ASSERT_EQ(0, close(fd));
4086 		}
4087 
4088 		ASSERT_EQ(0, close(socket_fds[0]));
4089 
4090 		_exit(_metadata->exit_code);
4091 		return;
4092 	}
4093 
4094 	if (variant->expected_open_result == 0) {
4095 		fd = recv_fd(socket_fds[1]);
4096 		ASSERT_LE(0, fd);
4097 
4098 		EXPECT_EQ(variant->expected_ftruncate_result,
4099 			  test_ftruncate(fd));
4100 		ASSERT_EQ(0, close(fd));
4101 	}
4102 
4103 	ASSERT_EQ(child, waitpid(child, &status, 0));
4104 	ASSERT_EQ(1, WIFEXITED(status));
4105 	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
4106 
4107 	ASSERT_EQ(0, close(socket_fds[0]));
4108 	ASSERT_EQ(0, close(socket_fds[1]));
4109 }
4110 
4111 /* Invokes the FS_IOC_GETFLAGS IOCTL and returns its errno or 0. */
test_fs_ioc_getflags_ioctl(int fd)4112 static int test_fs_ioc_getflags_ioctl(int fd)
4113 {
4114 	uint32_t flags;
4115 
4116 	if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0)
4117 		return errno;
4118 	return 0;
4119 }
4120 
TEST(memfd_ftruncate_and_ioctl)4121 TEST(memfd_ftruncate_and_ioctl)
4122 {
4123 	const struct landlock_ruleset_attr attr = {
4124 		.handled_access_fs = ACCESS_ALL,
4125 	};
4126 	int ruleset_fd, fd, i;
4127 
4128 	/*
4129 	 * We exercise the same test both with and without Landlock enabled, to
4130 	 * ensure that it behaves the same in both cases.
4131 	 */
4132 	for (i = 0; i < 2; i++) {
4133 		/* Creates a new memfd. */
4134 		fd = memfd_create("name", MFD_CLOEXEC);
4135 		ASSERT_LE(0, fd);
4136 
4137 		/*
4138 		 * Checks that operations associated with the opened file
4139 		 * (ftruncate, ioctl) are permitted on file descriptors that are
4140 		 * created in ways other than open(2).
4141 		 */
4142 		EXPECT_EQ(0, test_ftruncate(fd));
4143 		EXPECT_EQ(0, test_fs_ioc_getflags_ioctl(fd));
4144 
4145 		ASSERT_EQ(0, close(fd));
4146 
4147 		/* Enables Landlock. */
4148 		ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4149 		ASSERT_LE(0, ruleset_fd);
4150 		enforce_ruleset(_metadata, ruleset_fd);
4151 		ASSERT_EQ(0, close(ruleset_fd));
4152 	}
4153 }
4154 
test_fionread_ioctl(int fd)4155 static int test_fionread_ioctl(int fd)
4156 {
4157 	size_t sz = 0;
4158 
4159 	if (ioctl(fd, FIONREAD, &sz) < 0 && errno == EACCES)
4160 		return errno;
4161 	return 0;
4162 }
4163 
TEST_F_FORK(layout1,o_path_ftruncate_and_ioctl)4164 TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl)
4165 {
4166 	const struct landlock_ruleset_attr attr = {
4167 		.handled_access_fs = ACCESS_ALL,
4168 	};
4169 	int ruleset_fd, fd;
4170 
4171 	/*
4172 	 * Checks that for files opened with O_PATH, both ioctl(2) and
4173 	 * ftruncate(2) yield EBADF, as it is documented in open(2) for the
4174 	 * O_PATH flag.
4175 	 */
4176 	fd = open(dir_s1d1, O_PATH | O_CLOEXEC);
4177 	ASSERT_LE(0, fd);
4178 
4179 	EXPECT_EQ(EBADF, test_ftruncate(fd));
4180 	EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd));
4181 
4182 	ASSERT_EQ(0, close(fd));
4183 
4184 	/* Enables Landlock. */
4185 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4186 	ASSERT_LE(0, ruleset_fd);
4187 	enforce_ruleset(_metadata, ruleset_fd);
4188 	ASSERT_EQ(0, close(ruleset_fd));
4189 
4190 	/*
4191 	 * Checks that after enabling Landlock,
4192 	 * - the file can still be opened with O_PATH
4193 	 * - both ioctl and truncate still yield EBADF (not EACCES).
4194 	 */
4195 	fd = open(dir_s1d1, O_PATH | O_CLOEXEC);
4196 	ASSERT_LE(0, fd);
4197 
4198 	EXPECT_EQ(EBADF, test_ftruncate(fd));
4199 	EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd));
4200 
4201 	ASSERT_EQ(0, close(fd));
4202 }
4203 
4204 /*
4205  * ioctl_error - generically call the given ioctl with a pointer to a
4206  * sufficiently large zeroed-out memory region.
4207  *
4208  * Returns the IOCTLs error, or 0.
4209  */
ioctl_error(struct __test_metadata * const _metadata,int fd,unsigned int cmd)4210 static int ioctl_error(struct __test_metadata *const _metadata, int fd,
4211 		       unsigned int cmd)
4212 {
4213 	char buf[128]; /* sufficiently large */
4214 	int res, stdinbak_fd;
4215 
4216 	/*
4217 	 * Depending on the IOCTL command, parts of the zeroed-out buffer might
4218 	 * be interpreted as file descriptor numbers.  We do not want to
4219 	 * accidentally operate on file descriptor 0 (stdin), so we temporarily
4220 	 * move stdin to a different FD and close FD 0 for the IOCTL call.
4221 	 */
4222 	stdinbak_fd = dup(0);
4223 	ASSERT_LT(0, stdinbak_fd);
4224 	ASSERT_EQ(0, close(0));
4225 
4226 	/* Invokes the IOCTL with a zeroed-out buffer. */
4227 	bzero(&buf, sizeof(buf));
4228 	res = ioctl(fd, cmd, &buf);
4229 
4230 	/* Restores the old FD 0 and closes the backup FD. */
4231 	ASSERT_EQ(0, dup2(stdinbak_fd, 0));
4232 	ASSERT_EQ(0, close(stdinbak_fd));
4233 
4234 	if (res < 0)
4235 		return errno;
4236 
4237 	return 0;
4238 }
4239 
4240 /* Define some linux/falloc.h IOCTL commands which are not available in uapi headers. */
4241 struct space_resv {
4242 	__s16 l_type;
4243 	__s16 l_whence;
4244 	__s64 l_start;
4245 	__s64 l_len; /* len == 0 means until end of file */
4246 	__s32 l_sysid;
4247 	__u32 l_pid;
4248 	__s32 l_pad[4]; /* reserved area */
4249 };
4250 
4251 #define FS_IOC_RESVSP _IOW('X', 40, struct space_resv)
4252 #define FS_IOC_UNRESVSP _IOW('X', 41, struct space_resv)
4253 #define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv)
4254 #define FS_IOC_UNRESVSP64 _IOW('X', 43, struct space_resv)
4255 #define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv)
4256 
4257 /*
4258  * Tests a series of blanket-permitted and denied IOCTLs.
4259  */
TEST_F_FORK(layout1,blanket_permitted_ioctls)4260 TEST_F_FORK(layout1, blanket_permitted_ioctls)
4261 {
4262 	const struct landlock_ruleset_attr attr = {
4263 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4264 	};
4265 	int ruleset_fd, fd;
4266 
4267 	/* Enables Landlock. */
4268 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4269 	ASSERT_LE(0, ruleset_fd);
4270 	enforce_ruleset(_metadata, ruleset_fd);
4271 	ASSERT_EQ(0, close(ruleset_fd));
4272 
4273 	fd = open("/dev/null", O_RDWR | O_CLOEXEC);
4274 	ASSERT_LE(0, fd);
4275 
4276 	/*
4277 	 * Checks permitted commands.
4278 	 * These ones may return errors, but should not be blocked by Landlock.
4279 	 */
4280 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOCLEX));
4281 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONCLEX));
4282 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONBIO));
4283 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOASYNC));
4284 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOQSIZE));
4285 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIFREEZE));
4286 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FITHAW));
4287 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_FIEMAP));
4288 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIGETBSZ));
4289 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONE));
4290 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONERANGE));
4291 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIDEDUPERANGE));
4292 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSUUID));
4293 	EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSSYSFSPATH));
4294 
4295 	/*
4296 	 * Checks blocked commands.
4297 	 * A call to a blocked IOCTL command always returns EACCES.
4298 	 */
4299 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
4300 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFLAGS));
4301 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_SETFLAGS));
4302 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSGETXATTR));
4303 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSSETXATTR));
4304 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIBMAP));
4305 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP));
4306 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP64));
4307 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP));
4308 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP64));
4309 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_ZERO_RANGE));
4310 
4311 	/* Default case is also blocked. */
4312 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, 0xc00ffeee));
4313 
4314 	ASSERT_EQ(0, close(fd));
4315 }
4316 
4317 /*
4318  * Named pipes are not governed by the LANDLOCK_ACCESS_FS_IOCTL_DEV right,
4319  * because they are not character or block devices.
4320  */
TEST_F_FORK(layout1,named_pipe_ioctl)4321 TEST_F_FORK(layout1, named_pipe_ioctl)
4322 {
4323 	pid_t child_pid;
4324 	int fd, ruleset_fd;
4325 	const char *const path = file1_s1d1;
4326 	const struct landlock_ruleset_attr attr = {
4327 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4328 	};
4329 
4330 	ASSERT_EQ(0, unlink(path));
4331 	ASSERT_EQ(0, mkfifo(path, 0600));
4332 
4333 	/* Enables Landlock. */
4334 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4335 	ASSERT_LE(0, ruleset_fd);
4336 	enforce_ruleset(_metadata, ruleset_fd);
4337 	ASSERT_EQ(0, close(ruleset_fd));
4338 
4339 	/* The child process opens the pipe for writing. */
4340 	child_pid = fork();
4341 	ASSERT_NE(-1, child_pid);
4342 	if (child_pid == 0) {
4343 		fd = open(path, O_WRONLY);
4344 		close(fd);
4345 		exit(0);
4346 	}
4347 
4348 	fd = open(path, O_RDONLY);
4349 	ASSERT_LE(0, fd);
4350 
4351 	/* FIONREAD is implemented by pipefifo_fops. */
4352 	EXPECT_EQ(0, test_fionread_ioctl(fd));
4353 
4354 	ASSERT_EQ(0, close(fd));
4355 	ASSERT_EQ(0, unlink(path));
4356 
4357 	ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
4358 }
4359 
4360 /* For named UNIX domain sockets, no IOCTL restrictions apply. */
TEST_F_FORK(layout1,named_unix_domain_socket_ioctl)4361 TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
4362 {
4363 	const char *const path = file1_s1d1;
4364 	int srv_fd, cli_fd, ruleset_fd;
4365 	socklen_t size;
4366 	struct sockaddr_un srv_un, cli_un;
4367 	const struct landlock_ruleset_attr attr = {
4368 		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4369 	};
4370 
4371 	/* Sets up a server */
4372 	srv_un.sun_family = AF_UNIX;
4373 	strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path));
4374 
4375 	ASSERT_EQ(0, unlink(path));
4376 	srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4377 	ASSERT_LE(0, srv_fd);
4378 
4379 	size = offsetof(struct sockaddr_un, sun_path) + strlen(srv_un.sun_path);
4380 	ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, size));
4381 	ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */));
4382 
4383 	/* Enables Landlock. */
4384 	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4385 	ASSERT_LE(0, ruleset_fd);
4386 	enforce_ruleset(_metadata, ruleset_fd);
4387 	ASSERT_EQ(0, close(ruleset_fd));
4388 
4389 	/* Sets up a client connection to it */
4390 	cli_un.sun_family = AF_UNIX;
4391 	cli_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4392 	ASSERT_LE(0, cli_fd);
4393 
4394 	size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path);
4395 	ASSERT_EQ(0, bind(cli_fd, (struct sockaddr *)&cli_un, size));
4396 
4397 	bzero(&cli_un, sizeof(cli_un));
4398 	cli_un.sun_family = AF_UNIX;
4399 	strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path));
4400 	size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path);
4401 
4402 	ASSERT_EQ(0, connect(cli_fd, (struct sockaddr *)&cli_un, size));
4403 
4404 	/* FIONREAD and other IOCTLs should not be forbidden. */
4405 	EXPECT_EQ(0, test_fionread_ioctl(cli_fd));
4406 
4407 	ASSERT_EQ(0, close(cli_fd));
4408 }
4409 
4410 /* clang-format off */
FIXTURE(ioctl)4411 FIXTURE(ioctl) {};
4412 
FIXTURE_SETUP(ioctl)4413 FIXTURE_SETUP(ioctl) {};
4414 
FIXTURE_TEARDOWN(ioctl)4415 FIXTURE_TEARDOWN(ioctl) {};
4416 /* clang-format on */
4417 
FIXTURE_VARIANT(ioctl)4418 FIXTURE_VARIANT(ioctl)
4419 {
4420 	const __u64 handled;
4421 	const __u64 allowed;
4422 	const mode_t open_mode;
4423 	/*
4424 	 * FIONREAD is used as a characteristic device-specific IOCTL command.
4425 	 * It is implemented in fs/ioctl.c for regular files,
4426 	 * but we do not blanket-permit it for devices.
4427 	 */
4428 	const int expected_fionread_result;
4429 };
4430 
4431 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,handled_i_allowed_none)4432 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_none) {
4433 	/* clang-format on */
4434 	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4435 	.allowed = 0,
4436 	.open_mode = O_RDWR,
4437 	.expected_fionread_result = EACCES,
4438 };
4439 
4440 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,handled_i_allowed_i)4441 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_i) {
4442 	/* clang-format on */
4443 	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4444 	.allowed = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4445 	.open_mode = O_RDWR,
4446 	.expected_fionread_result = 0,
4447 };
4448 
4449 /* clang-format off */
FIXTURE_VARIANT_ADD(ioctl,unhandled)4450 FIXTURE_VARIANT_ADD(ioctl, unhandled) {
4451 	/* clang-format on */
4452 	.handled = LANDLOCK_ACCESS_FS_EXECUTE,
4453 	.allowed = LANDLOCK_ACCESS_FS_EXECUTE,
4454 	.open_mode = O_RDWR,
4455 	.expected_fionread_result = 0,
4456 };
4457 
TEST_F_FORK(ioctl,handle_dir_access_file)4458 TEST_F_FORK(ioctl, handle_dir_access_file)
4459 {
4460 	const int flag = 0;
4461 	const struct rule rules[] = {
4462 		{
4463 			.path = "/dev",
4464 			.access = variant->allowed,
4465 		},
4466 		{},
4467 	};
4468 	int file_fd, ruleset_fd;
4469 
4470 	/* Enables Landlock. */
4471 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4472 	ASSERT_LE(0, ruleset_fd);
4473 	enforce_ruleset(_metadata, ruleset_fd);
4474 	ASSERT_EQ(0, close(ruleset_fd));
4475 
4476 	file_fd = open("/dev/zero", variant->open_mode);
4477 	ASSERT_LE(0, file_fd);
4478 
4479 	/* Checks that IOCTL commands return the expected errors. */
4480 	EXPECT_EQ(variant->expected_fionread_result,
4481 		  test_fionread_ioctl(file_fd));
4482 
4483 	/* Checks that unrestrictable commands are unrestricted. */
4484 	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4485 	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4486 	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4487 	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4488 	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4489 
4490 	ASSERT_EQ(0, close(file_fd));
4491 }
4492 
TEST_F_FORK(ioctl,handle_dir_access_dir)4493 TEST_F_FORK(ioctl, handle_dir_access_dir)
4494 {
4495 	const int flag = 0;
4496 	const struct rule rules[] = {
4497 		{
4498 			.path = "/dev",
4499 			.access = variant->allowed,
4500 		},
4501 		{},
4502 	};
4503 	int dir_fd, ruleset_fd;
4504 
4505 	/* Enables Landlock. */
4506 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4507 	ASSERT_LE(0, ruleset_fd);
4508 	enforce_ruleset(_metadata, ruleset_fd);
4509 	ASSERT_EQ(0, close(ruleset_fd));
4510 
4511 	/*
4512 	 * Ignore variant->open_mode for this test, as we intend to open a
4513 	 * directory.  If the directory can not be opened, the variant is
4514 	 * infeasible to test with an opened directory.
4515 	 */
4516 	dir_fd = open("/dev", O_RDONLY);
4517 	if (dir_fd < 0)
4518 		return;
4519 
4520 	/*
4521 	 * Checks that IOCTL commands return the expected errors.
4522 	 * We do not use the expected values from the fixture here.
4523 	 *
4524 	 * When using IOCTL on a directory, no Landlock restrictions apply.
4525 	 */
4526 	EXPECT_EQ(0, test_fionread_ioctl(dir_fd));
4527 
4528 	/* Checks that unrestrictable commands are unrestricted. */
4529 	EXPECT_EQ(0, ioctl(dir_fd, FIOCLEX));
4530 	EXPECT_EQ(0, ioctl(dir_fd, FIONCLEX));
4531 	EXPECT_EQ(0, ioctl(dir_fd, FIONBIO, &flag));
4532 	EXPECT_EQ(0, ioctl(dir_fd, FIOASYNC, &flag));
4533 	EXPECT_EQ(0, ioctl(dir_fd, FIGETBSZ, &flag));
4534 
4535 	ASSERT_EQ(0, close(dir_fd));
4536 }
4537 
TEST_F_FORK(ioctl,handle_file_access_file)4538 TEST_F_FORK(ioctl, handle_file_access_file)
4539 {
4540 	const int flag = 0;
4541 	const struct rule rules[] = {
4542 		{
4543 			.path = "/dev/zero",
4544 			.access = variant->allowed,
4545 		},
4546 		{},
4547 	};
4548 	int file_fd, ruleset_fd;
4549 
4550 	/* Enables Landlock. */
4551 	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4552 	ASSERT_LE(0, ruleset_fd);
4553 	enforce_ruleset(_metadata, ruleset_fd);
4554 	ASSERT_EQ(0, close(ruleset_fd));
4555 
4556 	file_fd = open("/dev/zero", variant->open_mode);
4557 	ASSERT_LE(0, file_fd)
4558 	{
4559 		TH_LOG("Failed to open /dev/zero: %s", strerror(errno));
4560 	}
4561 
4562 	/* Checks that IOCTL commands return the expected errors. */
4563 	EXPECT_EQ(variant->expected_fionread_result,
4564 		  test_fionread_ioctl(file_fd));
4565 
4566 	/* Checks that unrestrictable commands are unrestricted. */
4567 	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4568 	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4569 	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4570 	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4571 	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4572 
4573 	ASSERT_EQ(0, close(file_fd));
4574 }
4575 
4576 /* clang-format off */
FIXTURE(layout1_bind)4577 FIXTURE(layout1_bind) {};
4578 /* clang-format on */
4579 
4580 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
4581 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
4582 
4583 /* Move targets for disconnected path tests. */
4584 static const char dir_s4d1[] = TMP_DIR "/s4d1";
4585 static const char file1_s4d1[] = TMP_DIR "/s4d1/f1";
4586 static const char file2_s4d1[] = TMP_DIR "/s4d1/f2";
4587 static const char dir_s4d2[] = TMP_DIR "/s4d1/s4d2";
4588 static const char file1_s4d2[] = TMP_DIR "/s4d1/s4d2/f1";
4589 static const char file1_name[] = "f1";
4590 static const char file2_name[] = "f2";
4591 
FIXTURE_SETUP(layout1_bind)4592 FIXTURE_SETUP(layout1_bind)
4593 {
4594 	prepare_layout(_metadata);
4595 
4596 	create_layout1(_metadata);
4597 
4598 	set_cap(_metadata, CAP_SYS_ADMIN);
4599 	ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL));
4600 	clear_cap(_metadata, CAP_SYS_ADMIN);
4601 }
4602 
FIXTURE_TEARDOWN_PARENT(layout1_bind)4603 FIXTURE_TEARDOWN_PARENT(layout1_bind)
4604 {
4605 	/* umount(dir_s2d2)) is handled by namespace lifetime. */
4606 
4607 	remove_path(file1_s4d1);
4608 	remove_path(file2_s4d1);
4609 
4610 	remove_layout1(_metadata);
4611 
4612 	cleanup_layout(_metadata);
4613 }
4614 
4615 /*
4616  * layout1_bind hierarchy:
4617  *
4618  * tmp
4619  * ├── s1d1
4620  * │   ├── f1
4621  * │   ├── f2
4622  * │   └── s1d2
4623  * │       ├── f1
4624  * │       ├── f2
4625  * │       └── s1d3 [disconnected by path_disconnected]
4626  * │           ├── f1
4627  * │           └── f2
4628  * ├── s2d1
4629  * │   ├── f1
4630  * │   └── s2d2 [bind mount from s1d2]
4631  * │       ├── f1
4632  * │       ├── f2
4633  * │       └── s1d3
4634  * │           ├── f1
4635  * │           └── f2
4636  * ├── s3d1
4637  * │   └── s3d2
4638  * │       └── s3d3
4639  * └── s4d1 [renamed from s1d3 by path_disconnected]
4640  *     ├── f1
4641  *     ├── f2
4642  *     └── s4d2
4643  *         └── f1
4644  */
4645 
TEST_F_FORK(layout1_bind,no_restriction)4646 TEST_F_FORK(layout1_bind, no_restriction)
4647 {
4648 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
4649 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4650 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
4651 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4652 	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
4653 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4654 
4655 	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
4656 	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
4657 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
4658 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
4659 	ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY));
4660 	ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY));
4661 
4662 	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY));
4663 	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4664 
4665 	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
4666 }
4667 
TEST_F_FORK(layout1_bind,same_content_same_file)4668 TEST_F_FORK(layout1_bind, same_content_same_file)
4669 {
4670 	/*
4671 	 * Sets access right on parent directories of both source and
4672 	 * destination mount points.
4673 	 */
4674 	const struct rule layer1_parent[] = {
4675 		{
4676 			.path = dir_s1d1,
4677 			.access = ACCESS_RO,
4678 		},
4679 		{
4680 			.path = dir_s2d1,
4681 			.access = ACCESS_RW,
4682 		},
4683 		{},
4684 	};
4685 	/*
4686 	 * Sets access rights on the same bind-mounted directories.  The result
4687 	 * should be ACCESS_RW for both directories, but not both hierarchies
4688 	 * because of the first layer.
4689 	 */
4690 	const struct rule layer2_mount_point[] = {
4691 		{
4692 			.path = dir_s1d2,
4693 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4694 		},
4695 		{
4696 			.path = dir_s2d2,
4697 			.access = ACCESS_RW,
4698 		},
4699 		{},
4700 	};
4701 	/* Only allow read-access to the s1d3 hierarchies. */
4702 	const struct rule layer3_source[] = {
4703 		{
4704 			.path = dir_s1d3,
4705 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4706 		},
4707 		{},
4708 	};
4709 	/* Removes all access rights. */
4710 	const struct rule layer4_destination[] = {
4711 		{
4712 			.path = bind_file1_s1d3,
4713 			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
4714 		},
4715 		{},
4716 	};
4717 	int ruleset_fd;
4718 
4719 	/* Sets rules for the parent directories. */
4720 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent);
4721 	ASSERT_LE(0, ruleset_fd);
4722 	enforce_ruleset(_metadata, ruleset_fd);
4723 	ASSERT_EQ(0, close(ruleset_fd));
4724 
4725 	/* Checks source hierarchy. */
4726 	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4727 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4728 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4729 
4730 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4731 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4732 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4733 
4734 	/* Checks destination hierarchy. */
4735 	ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR));
4736 	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4737 
4738 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4739 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4740 
4741 	/* Sets rules for the mount points. */
4742 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point);
4743 	ASSERT_LE(0, ruleset_fd);
4744 	enforce_ruleset(_metadata, ruleset_fd);
4745 	ASSERT_EQ(0, close(ruleset_fd));
4746 
4747 	/* Checks source hierarchy. */
4748 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
4749 	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4750 	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4751 
4752 	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4753 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4754 	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4755 
4756 	/* Checks destination hierarchy. */
4757 	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY));
4758 	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY));
4759 	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4760 
4761 	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4762 	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4763 	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4764 
4765 	/* Sets a (shared) rule only on the source. */
4766 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source);
4767 	ASSERT_LE(0, ruleset_fd);
4768 	enforce_ruleset(_metadata, ruleset_fd);
4769 	ASSERT_EQ(0, close(ruleset_fd));
4770 
4771 	/* Checks source hierarchy. */
4772 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
4773 	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4774 	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4775 
4776 	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4777 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4778 	ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
4779 
4780 	/* Checks destination hierarchy. */
4781 	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY));
4782 	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY));
4783 	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4784 
4785 	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4786 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4787 	ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4788 
4789 	/* Sets a (shared) rule only on the destination. */
4790 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination);
4791 	ASSERT_LE(0, ruleset_fd);
4792 	enforce_ruleset(_metadata, ruleset_fd);
4793 	ASSERT_EQ(0, close(ruleset_fd));
4794 
4795 	/* Checks source hierarchy. */
4796 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
4797 	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4798 
4799 	/* Checks destination hierarchy. */
4800 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY));
4801 	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4802 }
4803 
TEST_F_FORK(layout1_bind,reparent_cross_mount)4804 TEST_F_FORK(layout1_bind, reparent_cross_mount)
4805 {
4806 	const struct rule layer1[] = {
4807 		{
4808 			/* dir_s2d1 is beneath the dir_s2d2 mount point. */
4809 			.path = dir_s2d1,
4810 			.access = LANDLOCK_ACCESS_FS_REFER,
4811 		},
4812 		{
4813 			.path = bind_dir_s1d3,
4814 			.access = LANDLOCK_ACCESS_FS_EXECUTE,
4815 		},
4816 		{},
4817 	};
4818 	int ruleset_fd = create_ruleset(
4819 		_metadata,
4820 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1);
4821 
4822 	ASSERT_LE(0, ruleset_fd);
4823 	enforce_ruleset(_metadata, ruleset_fd);
4824 	ASSERT_EQ(0, close(ruleset_fd));
4825 
4826 	/* Checks basic denied move. */
4827 	ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2));
4828 	ASSERT_EQ(EXDEV, errno);
4829 
4830 	/* Checks real cross-mount move (Landlock is not involved). */
4831 	ASSERT_EQ(-1, rename(file1_s2d1, file1_s2d2));
4832 	ASSERT_EQ(EXDEV, errno);
4833 
4834 	/* Checks move that will give more accesses. */
4835 	ASSERT_EQ(-1, rename(file1_s2d2, bind_file1_s1d3));
4836 	ASSERT_EQ(EXDEV, errno);
4837 
4838 	/* Checks legitimate downgrade move. */
4839 	ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2));
4840 }
4841 
4842 /*
4843  * Make sure access to file through a disconnected path works as expected.
4844  * This test moves s1d3 to s4d1.
4845  */
TEST_F_FORK(layout1_bind,path_disconnected)4846 TEST_F_FORK(layout1_bind, path_disconnected)
4847 {
4848 	const struct rule layer1_allow_all[] = {
4849 		{
4850 			.path = TMP_DIR,
4851 			.access = ACCESS_ALL,
4852 		},
4853 		{},
4854 	};
4855 	const struct rule layer2_allow_just_f1[] = {
4856 		{
4857 			.path = file1_s1d3,
4858 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4859 		},
4860 		{},
4861 	};
4862 	const struct rule layer3_only_s1d2[] = {
4863 		{
4864 			.path = dir_s1d2,
4865 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4866 		},
4867 		{},
4868 	};
4869 
4870 	/* Landlock should not deny access just because it is disconnected. */
4871 	int ruleset_fd_l1 =
4872 		create_ruleset(_metadata, ACCESS_ALL, layer1_allow_all);
4873 
4874 	/* Creates the new ruleset now before we move the dir containing the file. */
4875 	int ruleset_fd_l2 =
4876 		create_ruleset(_metadata, ACCESS_RW, layer2_allow_just_f1);
4877 	int ruleset_fd_l3 =
4878 		create_ruleset(_metadata, ACCESS_RW, layer3_only_s1d2);
4879 	int bind_s1d3_fd;
4880 
4881 	ASSERT_LE(0, ruleset_fd_l1);
4882 	ASSERT_LE(0, ruleset_fd_l2);
4883 	ASSERT_LE(0, ruleset_fd_l3);
4884 
4885 	enforce_ruleset(_metadata, ruleset_fd_l1);
4886 	EXPECT_EQ(0, close(ruleset_fd_l1));
4887 
4888 	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
4889 	ASSERT_LE(0, bind_s1d3_fd);
4890 
4891 	/* Tests access is possible before we move. */
4892 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4893 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4894 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY));
4895 
4896 	/* Makes it disconnected. */
4897 	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1))
4898 	{
4899 		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1,
4900 		       strerror(errno));
4901 	}
4902 
4903 	/* Tests that access is still possible. */
4904 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4905 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4906 
4907 	/*
4908 	 * Tests that ".." is not possible (not because of Landlock, but just
4909 	 * because it's disconnected).
4910 	 */
4911 	EXPECT_EQ(ENOENT,
4912 		  test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY));
4913 
4914 	/* This should still work with a narrower rule. */
4915 	enforce_ruleset(_metadata, ruleset_fd_l2);
4916 	EXPECT_EQ(0, close(ruleset_fd_l2));
4917 
4918 	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY));
4919 	/*
4920 	 * Accessing a file through a disconnected file descriptor can still be
4921 	 * allowed by a rule tied to this file, even if it is no longer visible in
4922 	 * its mount point.
4923 	 */
4924 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4925 	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4926 
4927 	enforce_ruleset(_metadata, ruleset_fd_l3);
4928 	EXPECT_EQ(0, close(ruleset_fd_l3));
4929 
4930 	EXPECT_EQ(EACCES, test_open(file1_s4d1, O_RDONLY));
4931 	/*
4932 	 * Accessing a file through a disconnected file descriptor can still be
4933 	 * allowed by a rule tied to the original mount point, even if it is no
4934 	 * longer visible in its mount point.
4935 	 */
4936 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4937 	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4938 }
4939 
4940 /*
4941  * Test that renameat with disconnected paths works under Landlock.  This test
4942  * moves s1d3 to s4d2, so that we can have a rule allowing refers on the move
4943  * target's immediate parent.
4944  */
TEST_F_FORK(layout1_bind,path_disconnected_rename)4945 TEST_F_FORK(layout1_bind, path_disconnected_rename)
4946 {
4947 	const struct rule layer1[] = {
4948 		{
4949 			.path = dir_s1d2,
4950 			.access = LANDLOCK_ACCESS_FS_REFER |
4951 				  LANDLOCK_ACCESS_FS_MAKE_DIR |
4952 				  LANDLOCK_ACCESS_FS_REMOVE_DIR |
4953 				  LANDLOCK_ACCESS_FS_MAKE_REG |
4954 				  LANDLOCK_ACCESS_FS_REMOVE_FILE |
4955 				  LANDLOCK_ACCESS_FS_READ_FILE,
4956 		},
4957 		{
4958 			.path = dir_s4d1,
4959 			.access = LANDLOCK_ACCESS_FS_REFER |
4960 				  LANDLOCK_ACCESS_FS_MAKE_DIR |
4961 				  LANDLOCK_ACCESS_FS_REMOVE_DIR |
4962 				  LANDLOCK_ACCESS_FS_MAKE_REG |
4963 				  LANDLOCK_ACCESS_FS_REMOVE_FILE |
4964 				  LANDLOCK_ACCESS_FS_READ_FILE,
4965 		},
4966 		{}
4967 	};
4968 
4969 	/* This layer only handles LANDLOCK_ACCESS_FS_READ_FILE. */
4970 	const struct rule layer2_only_s1d2[] = {
4971 		{
4972 			.path = dir_s1d2,
4973 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4974 		},
4975 		{},
4976 	};
4977 	int ruleset_fd_l1, ruleset_fd_l2;
4978 	pid_t child_pid;
4979 	int bind_s1d3_fd, status;
4980 
4981 	ASSERT_EQ(0, mkdir(dir_s4d1, 0755))
4982 	{
4983 		TH_LOG("Failed to create %s: %s", dir_s4d1, strerror(errno));
4984 	}
4985 	ruleset_fd_l1 = create_ruleset(_metadata, ACCESS_ALL, layer1);
4986 	ruleset_fd_l2 = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
4987 				       layer2_only_s1d2);
4988 	ASSERT_LE(0, ruleset_fd_l1);
4989 	ASSERT_LE(0, ruleset_fd_l2);
4990 
4991 	enforce_ruleset(_metadata, ruleset_fd_l1);
4992 	EXPECT_EQ(0, close(ruleset_fd_l1));
4993 
4994 	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
4995 	ASSERT_LE(0, bind_s1d3_fd);
4996 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4997 
4998 	/* Tests ENOENT priority over EACCES for disconnected directory. */
4999 	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY));
5000 	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2))
5001 	{
5002 		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2,
5003 		       strerror(errno));
5004 	}
5005 	EXPECT_EQ(ENOENT, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY));
5006 
5007 	/*
5008 	 * The file is no longer under s1d2 but we should still be able to access it
5009 	 * with layer 2 because its mount point is evaluated as the first valid
5010 	 * directory because it was initially a parent.  Do a fork to test this so
5011 	 * we don't prevent ourselves from renaming it back later.
5012 	 */
5013 	child_pid = fork();
5014 	ASSERT_LE(0, child_pid);
5015 	if (child_pid == 0) {
5016 		enforce_ruleset(_metadata, ruleset_fd_l2);
5017 		EXPECT_EQ(0, close(ruleset_fd_l2));
5018 		EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5019 		EXPECT_EQ(EACCES, test_open(file1_s4d2, O_RDONLY));
5020 
5021 		/*
5022 		 * Tests that access widening checks indeed prevents us from renaming it
5023 		 * back.
5024 		 */
5025 		EXPECT_EQ(-1, rename(dir_s4d2, dir_s1d3));
5026 		EXPECT_EQ(EXDEV, errno);
5027 
5028 		/*
5029 		 * Including through the now disconnected fd (but it should return
5030 		 * EXDEV).
5031 		 */
5032 		EXPECT_EQ(-1, renameat(bind_s1d3_fd, file1_name, AT_FDCWD,
5033 				       file1_s2d2));
5034 		EXPECT_EQ(EXDEV, errno);
5035 		_exit(_metadata->exit_code);
5036 		return;
5037 	}
5038 
5039 	EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0));
5040 	EXPECT_EQ(1, WIFEXITED(status));
5041 	EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
5042 
5043 	ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3))
5044 	{
5045 		TH_LOG("Failed to rename %s back to %s: %s", dir_s4d1, dir_s1d3,
5046 		       strerror(errno));
5047 	}
5048 
5049 	/* Now checks that we can access it under l2. */
5050 	child_pid = fork();
5051 	ASSERT_LE(0, child_pid);
5052 	if (child_pid == 0) {
5053 		enforce_ruleset(_metadata, ruleset_fd_l2);
5054 		EXPECT_EQ(0, close(ruleset_fd_l2));
5055 		EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5056 		EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY));
5057 		_exit(_metadata->exit_code);
5058 		return;
5059 	}
5060 
5061 	EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0));
5062 	EXPECT_EQ(1, WIFEXITED(status));
5063 	EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
5064 
5065 	/*
5066 	 * Also test that we can rename via a disconnected path.  We move the
5067 	 * dir back to the disconnected place first, then we rename file1 to
5068 	 * file2 through our dir fd.
5069 	 */
5070 	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2))
5071 	{
5072 		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2,
5073 		       strerror(errno));
5074 	}
5075 	ASSERT_EQ(0,
5076 		  renameat(bind_s1d3_fd, file1_name, bind_s1d3_fd, file2_name))
5077 	{
5078 		TH_LOG("Failed to rename %s to %s within disconnected %s: %s",
5079 		       file1_name, file2_name, bind_dir_s1d3, strerror(errno));
5080 	}
5081 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
5082 	ASSERT_EQ(0, renameat(bind_s1d3_fd, file2_name, AT_FDCWD, file1_s2d2))
5083 	{
5084 		TH_LOG("Failed to rename %s to %s through disconnected %s: %s",
5085 		       file2_name, file1_s2d2, bind_dir_s1d3, strerror(errno));
5086 	}
5087 	EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY));
5088 	EXPECT_EQ(0, test_open(file1_s1d2, O_RDONLY));
5089 
5090 	/* Move it back using the disconnected path as the target. */
5091 	ASSERT_EQ(0, renameat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file1_name))
5092 	{
5093 		TH_LOG("Failed to rename %s to %s through disconnected %s: %s",
5094 		       file1_s1d2, file1_name, bind_dir_s1d3, strerror(errno));
5095 	}
5096 
5097 	/* Now make it connected again. */
5098 	ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3))
5099 	{
5100 		TH_LOG("Failed to rename %s back to %s: %s", dir_s4d2, dir_s1d3,
5101 		       strerror(errno));
5102 	}
5103 
5104 	/* Checks again that we can access it under l2. */
5105 	enforce_ruleset(_metadata, ruleset_fd_l2);
5106 	EXPECT_EQ(0, close(ruleset_fd_l2));
5107 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5108 	EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY));
5109 }
5110 
5111 /*
5112  * Test that linkat(2) with disconnected paths works under Landlock. This
5113  * test moves s1d3 to s4d1.
5114  */
TEST_F_FORK(layout1_bind,path_disconnected_link)5115 TEST_F_FORK(layout1_bind, path_disconnected_link)
5116 {
5117 	/* Ruleset to be applied after renaming s1d3 to s4d1. */
5118 	const struct rule layer1[] = {
5119 		{
5120 			.path = dir_s4d1,
5121 			.access = LANDLOCK_ACCESS_FS_REFER |
5122 				  LANDLOCK_ACCESS_FS_READ_FILE |
5123 				  LANDLOCK_ACCESS_FS_MAKE_REG |
5124 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
5125 		},
5126 		{
5127 			.path = dir_s2d2,
5128 			.access = LANDLOCK_ACCESS_FS_REFER |
5129 				  LANDLOCK_ACCESS_FS_READ_FILE |
5130 				  LANDLOCK_ACCESS_FS_MAKE_REG |
5131 				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
5132 		},
5133 		{}
5134 	};
5135 	int ruleset_fd, bind_s1d3_fd;
5136 
5137 	/* Removes unneeded files created by layout1, otherwise it will EEXIST. */
5138 	ASSERT_EQ(0, unlink(file1_s1d2));
5139 	ASSERT_EQ(0, unlink(file2_s1d3));
5140 
5141 	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
5142 	ASSERT_LE(0, bind_s1d3_fd);
5143 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5144 
5145 	/* Disconnects bind_s1d3_fd. */
5146 	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1))
5147 	{
5148 		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1,
5149 		       strerror(errno));
5150 	}
5151 
5152 	/* Need this later to test different parent link. */
5153 	ASSERT_EQ(0, mkdir(dir_s4d2, 0755))
5154 	{
5155 		TH_LOG("Failed to create %s: %s", dir_s4d2, strerror(errno));
5156 	}
5157 
5158 	ruleset_fd = create_ruleset(_metadata, ACCESS_ALL, layer1);
5159 	ASSERT_LE(0, ruleset_fd);
5160 	enforce_ruleset(_metadata, ruleset_fd);
5161 	EXPECT_EQ(0, close(ruleset_fd));
5162 
5163 	/* From disconnected to connected. */
5164 	ASSERT_EQ(0, linkat(bind_s1d3_fd, file1_name, AT_FDCWD, file1_s2d2, 0))
5165 	{
5166 		TH_LOG("Failed to link %s to %s via disconnected %s: %s",
5167 		       file1_name, file1_s2d2, bind_dir_s1d3, strerror(errno));
5168 	}
5169 
5170 	/* Tests that we can access via the new link... */
5171 	EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY))
5172 	{
5173 		TH_LOG("Failed to open newly linked %s: %s", file1_s2d2,
5174 		       strerror(errno));
5175 	}
5176 
5177 	/* ...as well as the old one. */
5178 	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY))
5179 	{
5180 		TH_LOG("Failed to open original %s: %s", file1_s4d1,
5181 		       strerror(errno));
5182 	}
5183 
5184 	/* From connected to disconnected. */
5185 	ASSERT_EQ(0, unlink(file1_s4d1));
5186 	ASSERT_EQ(0, linkat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file2_name, 0))
5187 	{
5188 		TH_LOG("Failed to link %s to %s via disconnected %s: %s",
5189 		       file1_s2d2, file2_name, bind_dir_s1d3, strerror(errno));
5190 	}
5191 	EXPECT_EQ(0, test_open(file2_s4d1, O_RDONLY));
5192 	ASSERT_EQ(0, unlink(file1_s2d2));
5193 
5194 	/* From disconnected to disconnected (same parent). */
5195 	ASSERT_EQ(0,
5196 		  linkat(bind_s1d3_fd, file2_name, bind_s1d3_fd, file1_name, 0))
5197 	{
5198 		TH_LOG("Failed to link %s to %s within disconnected %s: %s",
5199 		       file2_name, file1_name, bind_dir_s1d3, strerror(errno));
5200 	}
5201 	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY))
5202 	{
5203 		TH_LOG("Failed to open newly linked %s: %s", file1_s4d1,
5204 		       strerror(errno));
5205 	}
5206 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY))
5207 	{
5208 		TH_LOG("Failed to open %s through newly created link under disconnected path: %s",
5209 		       file1_name, strerror(errno));
5210 	}
5211 	ASSERT_EQ(0, unlink(file2_s4d1));
5212 
5213 	/* From disconnected to disconnected (different parent). */
5214 	ASSERT_EQ(0,
5215 		  linkat(bind_s1d3_fd, file1_name, bind_s1d3_fd, "s4d2/f1", 0))
5216 	{
5217 		TH_LOG("Failed to link %s to %s within disconnected %s: %s",
5218 		       file1_name, "s4d2/f1", bind_dir_s1d3, strerror(errno));
5219 	}
5220 	EXPECT_EQ(0, test_open(file1_s4d2, O_RDONLY))
5221 	{
5222 		TH_LOG("Failed to open %s after link: %s", file1_s4d2,
5223 		       strerror(errno));
5224 	}
5225 	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "s4d2/f1", O_RDONLY))
5226 	{
5227 		TH_LOG("Failed to open %s through disconnected path after link: %s",
5228 		       "s4d2/f1", strerror(errno));
5229 	}
5230 }
5231 
5232 /*
5233  * layout4_disconnected_leafs with bind mount and renames:
5234  *
5235  * tmp
5236  * ├── s1d1
5237  * │   └── s1d2 [source of the bind mount]
5238  * │       ├── s1d31
5239  * │       │   └── s1d41 [now renamed beneath s3d1]
5240  * │       │       ├── f1
5241  * │       │       └── f2
5242  * │       └── s1d32
5243  * │           └── s1d42 [now renamed beneath s4d1]
5244  * │               ├── f3
5245  * │               └── f4
5246  * ├── s2d1
5247  * │   └── s2d2 [bind mount of s1d2]
5248  * │       ├── s1d31
5249  * │       │   └── s1d41 [opened FD, now renamed beneath s3d1]
5250  * │       │       ├── f1
5251  * │       │       └── f2
5252  * │       └── s1d32
5253  * │           └── s1d42 [opened FD, now renamed beneath s4d1]
5254  * │               ├── f3
5255  * │               └── f4
5256  * ├── s3d1
5257  * │   └── s1d41 [renamed here]
5258  * │       ├── f1
5259  * │       └── f2
5260  * └── s4d1
5261  *     └── s1d42 [renamed here]
5262  *         ├── f3
5263  *         └── f4
5264  */
5265 /* clang-format off */
FIXTURE(layout4_disconnected_leafs)5266 FIXTURE(layout4_disconnected_leafs) {
5267 	int s2d2_fd;
5268 };
5269 /* clang-format on */
5270 
FIXTURE_SETUP(layout4_disconnected_leafs)5271 FIXTURE_SETUP(layout4_disconnected_leafs)
5272 {
5273 	prepare_layout(_metadata);
5274 
5275 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1");
5276 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2");
5277 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3");
5278 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f4");
5279 	create_directory(_metadata, TMP_DIR "/s2d1/s2d2");
5280 	create_directory(_metadata, TMP_DIR "/s3d1");
5281 	create_directory(_metadata, TMP_DIR "/s4d1");
5282 
5283 	self->s2d2_fd =
5284 		open(TMP_DIR "/s2d1/s2d2", O_DIRECTORY | O_PATH | O_CLOEXEC);
5285 	ASSERT_LE(0, self->s2d2_fd);
5286 
5287 	set_cap(_metadata, CAP_SYS_ADMIN);
5288 	ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2", NULL,
5289 			   MS_BIND, NULL));
5290 	clear_cap(_metadata, CAP_SYS_ADMIN);
5291 }
5292 
FIXTURE_TEARDOWN_PARENT(layout4_disconnected_leafs)5293 FIXTURE_TEARDOWN_PARENT(layout4_disconnected_leafs)
5294 {
5295 	/* umount(TMP_DIR "/s2d1") is handled by namespace lifetime. */
5296 
5297 	/* Removes files after renames. */
5298 	remove_path(TMP_DIR "/s3d1/s1d41/f1");
5299 	remove_path(TMP_DIR "/s3d1/s1d41/f2");
5300 	remove_path(TMP_DIR "/s4d1/s1d42/f1");
5301 	remove_path(TMP_DIR "/s4d1/s1d42/f3");
5302 	remove_path(TMP_DIR "/s4d1/s1d42/f4");
5303 	remove_path(TMP_DIR "/s4d1/s1d42/f5");
5304 
5305 	cleanup_layout(_metadata);
5306 }
5307 
FIXTURE_VARIANT(layout4_disconnected_leafs)5308 FIXTURE_VARIANT(layout4_disconnected_leafs)
5309 {
5310 	/*
5311 	 * Parent of the bind mount source.  It should always be ignored when
5312 	 * testing against files under the s1d41 or s1d42 disconnected directories.
5313 	 */
5314 	const __u64 allowed_s1d1;
5315 	/*
5316 	 * Source of bind mount (to s2d2).  It should always be enforced when
5317 	 * testing against files under the s1d41 or s1d42 disconnected directories.
5318 	 */
5319 	const __u64 allowed_s1d2;
5320 	/*
5321 	 * Original parent of s1d41.  It should always be ignored when testing
5322 	 * against files under the s1d41 disconnected directory.
5323 	 */
5324 	const __u64 allowed_s1d31;
5325 	/*
5326 	 * Original parent of s1d42.  It should always be ignored when testing
5327 	 * against files under the s1d42 disconnected directory.
5328 	 */
5329 	const __u64 allowed_s1d32;
5330 	/*
5331 	 * Opened and disconnected source directory.  It should always be enforced
5332 	 * when testing against files under the s1d41 disconnected directory.
5333 	 */
5334 	const __u64 allowed_s1d41;
5335 	/*
5336 	 * Opened and disconnected source directory.  It should always be enforced
5337 	 * when testing against files under the s1d42 disconnected directory.
5338 	 */
5339 	const __u64 allowed_s1d42;
5340 	/*
5341 	 * File in the s1d41 disconnected directory.  It should always be enforced
5342 	 * when testing against itself under the s1d41 disconnected directory.
5343 	 */
5344 	const __u64 allowed_f1;
5345 	/*
5346 	 * File in the s1d41 disconnected directory.  It should always be enforced
5347 	 * when testing against itself under the s1d41 disconnected directory.
5348 	 */
5349 	const __u64 allowed_f2;
5350 	/*
5351 	 * File in the s1d42 disconnected directory.  It should always be enforced
5352 	 * when testing against itself under the s1d42 disconnected directory.
5353 	 */
5354 	const __u64 allowed_f3;
5355 	/*
5356 	 * Parent of the bind mount destination.  It should always be enforced when
5357 	 * testing against files under the s1d41 or s1d42 disconnected directories.
5358 	 */
5359 	const __u64 allowed_s2d1;
5360 	/*
5361 	 * Directory covered by the bind mount.  It should always be ignored when
5362 	 * testing against files under the s1d41 or s1d42 disconnected directories.
5363 	 */
5364 	const __u64 allowed_s2d2;
5365 	/*
5366 	 * New parent of the renamed s1d41.  It should always be ignored when
5367 	 * testing against files under the s1d41 disconnected directory.
5368 	 */
5369 	const __u64 allowed_s3d1;
5370 	/*
5371 	 * New parent of the renamed s1d42.  It should always be ignored when
5372 	 * testing against files under the s1d42 disconnected directory.
5373 	 */
5374 	const __u64 allowed_s4d1;
5375 
5376 	/* Expected result of the call to open([fd:s1d41]/f1, O_RDONLY). */
5377 	const int expected_read_result;
5378 	/* Expected result of the call to renameat([fd:s1d41]/f1, [fd:s1d42]/f1). */
5379 	const int expected_rename_result;
5380 	/*
5381 	 * Expected result of the call to renameat([fd:s1d41]/f2, [fd:s1d42]/f3,
5382 	 * RENAME_EXCHANGE).
5383 	 */
5384 	const int expected_exchange_result;
5385 	/* Expected result of the call to renameat([fd:s1d42]/f4, [fd:s1d42]/f5). */
5386 	const int expected_same_dir_rename_result;
5387 };
5388 
5389 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d1_mount_src_parent)5390 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d1_mount_src_parent) {
5391 	/* clang-format on */
5392 	.allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER |
5393 			LANDLOCK_ACCESS_FS_READ_FILE |
5394 			LANDLOCK_ACCESS_FS_EXECUTE |
5395 			LANDLOCK_ACCESS_FS_MAKE_REG,
5396 	.expected_read_result = EACCES,
5397 	.expected_same_dir_rename_result = EACCES,
5398 	.expected_rename_result = EACCES,
5399 	.expected_exchange_result = EACCES,
5400 };
5401 
5402 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d2_mount_src_refer)5403 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_refer) {
5404 	/* clang-format on */
5405 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5406 	.expected_read_result = 0,
5407 	.expected_same_dir_rename_result = EACCES,
5408 	.expected_rename_result = EACCES,
5409 	.expected_exchange_result = EACCES,
5410 };
5411 
5412 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d2_mount_src_create)5413 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_create) {
5414 	/* clang-format on */
5415 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE |
5416 			LANDLOCK_ACCESS_FS_MAKE_REG,
5417 	.expected_read_result = 0,
5418 	.expected_same_dir_rename_result = 0,
5419 	.expected_rename_result = EXDEV,
5420 	.expected_exchange_result = EXDEV,
5421 };
5422 
5423 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d2_mount_src_rename)5424 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_rename) {
5425 	/* clang-format on */
5426 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5427 	.expected_read_result = EACCES,
5428 	.expected_same_dir_rename_result = 0,
5429 	.expected_rename_result = 0,
5430 	.expected_exchange_result = 0,
5431 };
5432 
5433 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d31_s1d32_old_parent)5434 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d31_s1d32_old_parent) {
5435 	/* clang-format on */
5436 	.allowed_s1d31 = LANDLOCK_ACCESS_FS_REFER |
5437 			 LANDLOCK_ACCESS_FS_READ_FILE |
5438 			 LANDLOCK_ACCESS_FS_EXECUTE |
5439 			 LANDLOCK_ACCESS_FS_MAKE_REG,
5440 	.allowed_s1d32 = LANDLOCK_ACCESS_FS_REFER |
5441 			 LANDLOCK_ACCESS_FS_READ_FILE |
5442 			 LANDLOCK_ACCESS_FS_EXECUTE |
5443 			 LANDLOCK_ACCESS_FS_MAKE_REG,
5444 	.expected_read_result = EACCES,
5445 	.expected_same_dir_rename_result = EACCES,
5446 	.expected_rename_result = EACCES,
5447 	.expected_exchange_result = EACCES,
5448 };
5449 
5450 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d41_s1d42_disconnected_refer)5451 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_refer) {
5452 	/* clang-format on */
5453 	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER |
5454 			 LANDLOCK_ACCESS_FS_READ_FILE,
5455 	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER |
5456 			 LANDLOCK_ACCESS_FS_READ_FILE,
5457 	.expected_read_result = 0,
5458 	.expected_same_dir_rename_result = EACCES,
5459 	.expected_rename_result = EACCES,
5460 	.expected_exchange_result = EACCES,
5461 };
5462 
5463 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d41_s1d42_disconnected_create)5464 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_create) {
5465 	/* clang-format on */
5466 	.allowed_s1d41 = LANDLOCK_ACCESS_FS_READ_FILE |
5467 			 LANDLOCK_ACCESS_FS_MAKE_REG,
5468 	.allowed_s1d42 = LANDLOCK_ACCESS_FS_READ_FILE |
5469 			 LANDLOCK_ACCESS_FS_MAKE_REG,
5470 	.expected_read_result = 0,
5471 	.expected_same_dir_rename_result = 0,
5472 	.expected_rename_result = EXDEV,
5473 	.expected_exchange_result = EXDEV,
5474 };
5475 
5476 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d41_s1d42_disconnected_rename_even)5477 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_even) {
5478 	/* clang-format on */
5479 	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5480 	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5481 	.expected_read_result = EACCES,
5482 	.expected_same_dir_rename_result = 0,
5483 	.expected_rename_result = 0,
5484 	.expected_exchange_result = 0,
5485 };
5486 
5487 /* The destination directory has more access right. */
5488 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d41_s1d42_disconnected_rename_more)5489 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_more) {
5490 	/* clang-format on */
5491 	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5492 	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER |
5493 			 LANDLOCK_ACCESS_FS_MAKE_REG |
5494 			 LANDLOCK_ACCESS_FS_EXECUTE,
5495 	.expected_read_result = EACCES,
5496 	.expected_same_dir_rename_result = 0,
5497 	/* Access denied. */
5498 	.expected_rename_result = EXDEV,
5499 	.expected_exchange_result = EXDEV,
5500 };
5501 
5502 /* The destination directory has less access right. */
5503 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s1d41_s1d42_disconnected_rename_less)5504 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_less) {
5505 	/* clang-format on */
5506 	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER |
5507 			 LANDLOCK_ACCESS_FS_MAKE_REG |
5508 			 LANDLOCK_ACCESS_FS_EXECUTE,
5509 	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5510 	.expected_read_result = EACCES,
5511 	.expected_same_dir_rename_result = 0,
5512 	/* Access allowed. */
5513 	.expected_rename_result = 0,
5514 	.expected_exchange_result = EXDEV,
5515 };
5516 
5517 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s2d1_mount_dst_parent_create)5518 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_create) {
5519 	/* clang-format on */
5520 	.allowed_s2d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5521 			LANDLOCK_ACCESS_FS_MAKE_REG,
5522 	.expected_read_result = 0,
5523 	.expected_same_dir_rename_result = 0,
5524 	.expected_rename_result = EXDEV,
5525 	.expected_exchange_result = EXDEV,
5526 };
5527 
5528 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s2d1_mount_dst_parent_refer)5529 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_refer) {
5530 	/* clang-format on */
5531 	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5532 	.expected_read_result = 0,
5533 	.expected_same_dir_rename_result = EACCES,
5534 	.expected_rename_result = EACCES,
5535 	.expected_exchange_result = EACCES,
5536 };
5537 
5538 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s2d1_mount_dst_parent_mini)5539 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_mini) {
5540 	/* clang-format on */
5541 	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER |
5542 			LANDLOCK_ACCESS_FS_READ_FILE |
5543 			LANDLOCK_ACCESS_FS_MAKE_REG,
5544 	.expected_read_result = 0,
5545 	.expected_same_dir_rename_result = 0,
5546 	.expected_rename_result = 0,
5547 	.expected_exchange_result = 0,
5548 };
5549 
5550 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s2d2_covered_by_mount)5551 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d2_covered_by_mount) {
5552 	/* clang-format on */
5553 	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER |
5554 			LANDLOCK_ACCESS_FS_READ_FILE |
5555 			LANDLOCK_ACCESS_FS_EXECUTE |
5556 			LANDLOCK_ACCESS_FS_MAKE_REG,
5557 	.expected_read_result = EACCES,
5558 	.expected_same_dir_rename_result = EACCES,
5559 	.expected_rename_result = EACCES,
5560 	.expected_exchange_result = EACCES,
5561 };
5562 
5563 /* Tests collect_domain_accesses(). */
5564 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s3d1_s4d1_new_parent_refer)5565 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_refer) {
5566 	/* clang-format on */
5567 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5568 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5569 	.expected_read_result = 0,
5570 	.expected_same_dir_rename_result = EACCES,
5571 	.expected_rename_result = EACCES,
5572 	.expected_exchange_result = EACCES,
5573 };
5574 
5575 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s3d1_s4d1_new_parent_create)5576 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_create) {
5577 	/* clang-format on */
5578 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5579 			LANDLOCK_ACCESS_FS_MAKE_REG,
5580 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5581 			LANDLOCK_ACCESS_FS_MAKE_REG,
5582 	.expected_read_result = 0,
5583 	.expected_same_dir_rename_result = 0,
5584 	.expected_rename_result = EXDEV,
5585 	.expected_exchange_result = EXDEV,
5586 };
5587 
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s3d1_s4d1_disconnected_rename_even)5588 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,
5589 		    s3d1_s4d1_disconnected_rename_even){
5590 	/* clang-format on */
5591 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5592 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5593 	.expected_read_result = EACCES,
5594 	.expected_same_dir_rename_result = 0,
5595 	.expected_rename_result = 0,
5596 	.expected_exchange_result = 0,
5597 };
5598 
5599 /* The destination directory has more access right. */
5600 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s3d1_s4d1_disconnected_rename_more)5601 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_more) {
5602 	/* clang-format on */
5603 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5604 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG |
5605 			LANDLOCK_ACCESS_FS_EXECUTE,
5606 	.expected_read_result = EACCES,
5607 	.expected_same_dir_rename_result = 0,
5608 	/* Access denied. */
5609 	.expected_rename_result = EXDEV,
5610 	.expected_exchange_result = EXDEV,
5611 };
5612 
5613 /* The destination directory has less access right. */
5614 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,s3d1_s4d1_disconnected_rename_less)5615 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_less) {
5616 	/* clang-format on */
5617 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG |
5618 			LANDLOCK_ACCESS_FS_EXECUTE,
5619 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5620 	.expected_read_result = EACCES,
5621 	.expected_same_dir_rename_result = 0,
5622 	/* Access allowed. */
5623 	.expected_rename_result = 0,
5624 	.expected_exchange_result = EXDEV,
5625 };
5626 
5627 /* clang-format off */
FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,f1_f2_f3)5628 FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, f1_f2_f3) {
5629 	/* clang-format on */
5630 	.allowed_f1 = LANDLOCK_ACCESS_FS_READ_FILE,
5631 	.allowed_f2 = LANDLOCK_ACCESS_FS_READ_FILE,
5632 	.allowed_f3 = LANDLOCK_ACCESS_FS_READ_FILE,
5633 	.expected_read_result = 0,
5634 	.expected_same_dir_rename_result = EACCES,
5635 	.expected_rename_result = EACCES,
5636 	.expected_exchange_result = EACCES,
5637 };
5638 
TEST_F_FORK(layout4_disconnected_leafs,read_rename_exchange)5639 TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange)
5640 {
5641 	const __u64 handled_access =
5642 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE |
5643 		LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG;
5644 	const struct rule rules[] = {
5645 		{
5646 			.path = TMP_DIR "/s1d1",
5647 			.access = variant->allowed_s1d1,
5648 		},
5649 		{
5650 			.path = TMP_DIR "/s1d1/s1d2",
5651 			.access = variant->allowed_s1d2,
5652 		},
5653 		{
5654 			.path = TMP_DIR "/s1d1/s1d2/s1d31",
5655 			.access = variant->allowed_s1d31,
5656 		},
5657 		{
5658 			.path = TMP_DIR "/s1d1/s1d2/s1d32",
5659 			.access = variant->allowed_s1d32,
5660 		},
5661 		{
5662 			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41",
5663 			.access = variant->allowed_s1d41,
5664 		},
5665 		{
5666 			.path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42",
5667 			.access = variant->allowed_s1d42,
5668 		},
5669 		{
5670 			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1",
5671 			.access = variant->allowed_f1,
5672 		},
5673 		{
5674 			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2",
5675 			.access = variant->allowed_f2,
5676 		},
5677 		{
5678 			.path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3",
5679 			.access = variant->allowed_f3,
5680 		},
5681 		{
5682 			.path = TMP_DIR "/s2d1",
5683 			.access = variant->allowed_s2d1,
5684 		},
5685 		/* s2d2_fd */
5686 		{
5687 			.path = TMP_DIR "/s3d1",
5688 			.access = variant->allowed_s3d1,
5689 		},
5690 		{
5691 			.path = TMP_DIR "/s4d1",
5692 			.access = variant->allowed_s4d1,
5693 		},
5694 		{},
5695 	};
5696 	int ruleset_fd, s1d41_bind_fd, s1d42_bind_fd;
5697 
5698 	ruleset_fd = create_ruleset(_metadata, handled_access, rules);
5699 	ASSERT_LE(0, ruleset_fd);
5700 
5701 	/* Adds rule for the covered directory. */
5702 	if (variant->allowed_s2d2) {
5703 		ASSERT_EQ(0, landlock_add_rule(
5704 				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
5705 				     &(struct landlock_path_beneath_attr){
5706 					     .parent_fd = self->s2d2_fd,
5707 					     .allowed_access =
5708 						     variant->allowed_s2d2,
5709 				     },
5710 				     0));
5711 	}
5712 	EXPECT_EQ(0, close(self->s2d2_fd));
5713 
5714 	s1d41_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d31/s1d41",
5715 			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5716 	ASSERT_LE(0, s1d41_bind_fd);
5717 	s1d42_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d32/s1d42",
5718 			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5719 	ASSERT_LE(0, s1d42_bind_fd);
5720 
5721 	/* Disconnects and checks source and destination directories. */
5722 	EXPECT_EQ(0, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY));
5723 	EXPECT_EQ(0, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY));
5724 	/* Renames to make it accessible through s3d1/s1d41 */
5725 	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d31/s1d41",
5726 				   AT_FDCWD, TMP_DIR "/s3d1/s1d41"));
5727 	/* Renames to make it accessible through s4d1/s1d42 */
5728 	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d32/s1d42",
5729 				   AT_FDCWD, TMP_DIR "/s4d1/s1d42"));
5730 	EXPECT_EQ(ENOENT, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY));
5731 	EXPECT_EQ(ENOENT, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY));
5732 
5733 	enforce_ruleset(_metadata, ruleset_fd);
5734 	EXPECT_EQ(0, close(ruleset_fd));
5735 
5736 	EXPECT_EQ(variant->expected_read_result,
5737 		  test_open_rel(s1d41_bind_fd, "f1", O_RDONLY));
5738 
5739 	EXPECT_EQ(variant->expected_rename_result,
5740 		  test_renameat(s1d41_bind_fd, "f1", s1d42_bind_fd, "f1"));
5741 	EXPECT_EQ(variant->expected_exchange_result,
5742 		  test_exchangeat(s1d41_bind_fd, "f2", s1d42_bind_fd, "f3"));
5743 
5744 	EXPECT_EQ(variant->expected_same_dir_rename_result,
5745 		  test_renameat(s1d42_bind_fd, "f4", s1d42_bind_fd, "f5"));
5746 }
5747 
5748 /*
5749  * layout5_disconnected_branch before rename:
5750  *
5751  * tmp
5752  * ├── s1d1
5753  * │   └── s1d2 [source of the first bind mount]
5754  * │       └── s1d3
5755  * │           ├── s1d41
5756  * │           │   ├── f1
5757  * │           │   └── f2
5758  * │           └── s1d42
5759  * │               ├── f3
5760  * │               └── f4
5761  * ├── s2d1
5762  * │   └── s2d2 [source of the second bind mount]
5763  * │       └── s2d3
5764  * │           └── s2d4 [first s1d2 bind mount]
5765  * │               └── s1d3
5766  * │                   ├── s1d41
5767  * │                   │   ├── f1
5768  * │                   │   └── f2
5769  * │                   └── s1d42
5770  * │                       ├── f3
5771  * │                       └── f4
5772  * ├── s3d1
5773  * │   └── s3d2 [second s2d2 bind mount]
5774  * │       └── s2d3
5775  * │           └── s2d4 [first s1d2 bind mount]
5776  * │               └── s1d3
5777  * │                   ├── s1d41
5778  * │                   │   ├── f1
5779  * │                   │   └── f2
5780  * │                   └── s1d42
5781  * │                       ├── f3
5782  * │                       └── f4
5783  * └── s4d1
5784  *
5785  * After rename:
5786  *
5787  * tmp
5788  * ├── s1d1
5789  * │   └── s1d2 [source of the first bind mount]
5790  * │       └── s1d3
5791  * │           ├── s1d41
5792  * │           │   ├── f1
5793  * │           │   └── f2
5794  * │           └── s1d42
5795  * │               ├── f3
5796  * │               └── f4
5797  * ├── s2d1
5798  * │   └── s2d2 [source of the second bind mount]
5799  * ├── s3d1
5800  * │   └── s3d2 [second s2d2 bind mount]
5801  * └── s4d1
5802  *     └── s2d3 [renamed here]
5803  *         └── s2d4 [first s1d2 bind mount]
5804  *             └── s1d3
5805  *                 ├── s1d41
5806  *                 │   ├── f1
5807  *                 │   └── f2
5808  *                 └── s1d42
5809  *                     ├── f3
5810  *                     └── f4
5811  *
5812  * Decision path for access from the s3d1/s3d2/s2d3/s2d4/s1d3 file descriptor:
5813  *   1. first bind mount:   s1d3 -> s1d2
5814  *   2. second bind mount:    s2d3
5815  *   3. tmp mount:              s4d1 -> tmp [disconnected branch]
5816  *   4. second bind mount:        s2d2
5817  *   5. tmp mount:                  s3d1 -> tmp
5818  *   6. parent mounts:                [...] -> /
5819  *
5820  * The s4d1 directory is evaluated even if it is not in the s2d2 mount.
5821  */
5822 
5823 /* clang-format off */
FIXTURE(layout5_disconnected_branch)5824 FIXTURE(layout5_disconnected_branch) {
5825 	int s2d4_fd, s3d2_fd;
5826 };
5827 /* clang-format on */
5828 
FIXTURE_SETUP(layout5_disconnected_branch)5829 FIXTURE_SETUP(layout5_disconnected_branch)
5830 {
5831 	prepare_layout(_metadata);
5832 
5833 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1");
5834 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2");
5835 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3");
5836 	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4");
5837 	create_directory(_metadata, TMP_DIR "/s2d1/s2d2/s2d3/s2d4");
5838 	create_directory(_metadata, TMP_DIR "/s3d1/s3d2");
5839 	create_directory(_metadata, TMP_DIR "/s4d1");
5840 
5841 	self->s2d4_fd = open(TMP_DIR "/s2d1/s2d2/s2d3/s2d4",
5842 			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5843 	ASSERT_LE(0, self->s2d4_fd);
5844 
5845 	self->s3d2_fd =
5846 		open(TMP_DIR "/s3d1/s3d2", O_DIRECTORY | O_PATH | O_CLOEXEC);
5847 	ASSERT_LE(0, self->s3d2_fd);
5848 
5849 	set_cap(_metadata, CAP_SYS_ADMIN);
5850 	ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2/s2d3/s2d4",
5851 			   NULL, MS_BIND, NULL));
5852 	ASSERT_EQ(0, mount(TMP_DIR "/s2d1/s2d2", TMP_DIR "/s3d1/s3d2", NULL,
5853 			   MS_BIND | MS_REC, NULL));
5854 	clear_cap(_metadata, CAP_SYS_ADMIN);
5855 }
5856 
FIXTURE_TEARDOWN_PARENT(layout5_disconnected_branch)5857 FIXTURE_TEARDOWN_PARENT(layout5_disconnected_branch)
5858 {
5859 	/* Bind mounts are handled by namespace lifetime. */
5860 
5861 	/* Removes files after renames. */
5862 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1");
5863 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2");
5864 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f1");
5865 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3");
5866 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4");
5867 	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f5");
5868 
5869 	cleanup_layout(_metadata);
5870 }
5871 
FIXTURE_VARIANT(layout5_disconnected_branch)5872 FIXTURE_VARIANT(layout5_disconnected_branch)
5873 {
5874 	/*
5875 	 * Parent of all files.  It should always be enforced when testing against
5876 	 * files under the s1d41 or s1d42 disconnected directories.
5877 	 */
5878 	const __u64 allowed_base;
5879 	/*
5880 	 * Parent of the first bind mount source.  It should always be ignored when
5881 	 * testing against files under the s1d41 or s1d42 disconnected directories.
5882 	 */
5883 	const __u64 allowed_s1d1;
5884 	const __u64 allowed_s1d2;
5885 	const __u64 allowed_s1d3;
5886 	const __u64 allowed_s2d1;
5887 	const __u64 allowed_s2d2;
5888 	const __u64 allowed_s2d3;
5889 	const __u64 allowed_s2d4;
5890 	const __u64 allowed_s3d1;
5891 	const __u64 allowed_s3d2;
5892 	const __u64 allowed_s4d1;
5893 
5894 	/* Expected result of the call to open([fd:s1d3]/s1d41/f1, O_RDONLY). */
5895 	const int expected_read_result;
5896 	/*
5897 	 * Expected result of the call to renameat([fd:s1d3]/s1d41/f1,
5898 	 * [fd:s1d3]/s1d42/f1).
5899 	 */
5900 	const int expected_rename_result;
5901 	/*
5902 	 * Expected result of the call to renameat([fd:s1d3]/s1d41/f2,
5903 	 * [fd:s1d3]/s1d42/f3,  RENAME_EXCHANGE).
5904 	 */
5905 	const int expected_exchange_result;
5906 	/*
5907 	 * Expected result of the call to renameat([fd:s1d3]/s1d42/f4,
5908 	 * [fd:s1d3]/s1d42/f5).
5909 	 */
5910 	const int expected_same_dir_rename_result;
5911 };
5912 
5913 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d1_mount1_src_parent)5914 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d1_mount1_src_parent) {
5915 	/* clang-format on */
5916 	.allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER |
5917 			LANDLOCK_ACCESS_FS_READ_FILE |
5918 			LANDLOCK_ACCESS_FS_EXECUTE |
5919 			LANDLOCK_ACCESS_FS_MAKE_REG,
5920 	.expected_read_result = EACCES,
5921 	.expected_same_dir_rename_result = EACCES,
5922 	.expected_rename_result = EACCES,
5923 	.expected_exchange_result = EACCES,
5924 };
5925 
5926 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d2_mount1_src_refer)5927 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_refer) {
5928 	/* clang-format on */
5929 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5930 	.expected_read_result = 0,
5931 	.expected_same_dir_rename_result = EACCES,
5932 	.expected_rename_result = EACCES,
5933 	.expected_exchange_result = EACCES,
5934 };
5935 
5936 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d2_mount1_src_create)5937 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_create) {
5938 	/* clang-format on */
5939 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE |
5940 			LANDLOCK_ACCESS_FS_MAKE_REG,
5941 	.expected_read_result = 0,
5942 	.expected_same_dir_rename_result = 0,
5943 	.expected_rename_result = EXDEV,
5944 	.expected_exchange_result = EXDEV,
5945 };
5946 
5947 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d2_mount1_src_rename)5948 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_rename) {
5949 	/* clang-format on */
5950 	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5951 	.expected_read_result = EACCES,
5952 	.expected_same_dir_rename_result = 0,
5953 	.expected_rename_result = 0,
5954 	.expected_exchange_result = 0,
5955 };
5956 
5957 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d3_fd_refer)5958 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_refer) {
5959 	/* clang-format on */
5960 	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5961 	.expected_read_result = 0,
5962 	.expected_same_dir_rename_result = EACCES,
5963 	.expected_rename_result = EACCES,
5964 	.expected_exchange_result = EACCES,
5965 };
5966 
5967 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d3_fd_create)5968 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_create) {
5969 	/* clang-format on */
5970 	.allowed_s1d3 = LANDLOCK_ACCESS_FS_READ_FILE |
5971 			LANDLOCK_ACCESS_FS_MAKE_REG,
5972 	.expected_read_result = 0,
5973 	.expected_same_dir_rename_result = 0,
5974 	.expected_rename_result = EXDEV,
5975 	.expected_exchange_result = EXDEV,
5976 };
5977 
5978 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d3_fd_rename)5979 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_rename) {
5980 	/* clang-format on */
5981 	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5982 	.expected_read_result = EACCES,
5983 	.expected_same_dir_rename_result = 0,
5984 	.expected_rename_result = 0,
5985 	.expected_exchange_result = 0,
5986 };
5987 
5988 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s1d3_fd_full)5989 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_full) {
5990 	/* clang-format on */
5991 	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER |
5992 			LANDLOCK_ACCESS_FS_READ_FILE |
5993 			LANDLOCK_ACCESS_FS_EXECUTE |
5994 			LANDLOCK_ACCESS_FS_MAKE_REG,
5995 	.expected_read_result = 0,
5996 	.expected_same_dir_rename_result = 0,
5997 	.expected_rename_result = 0,
5998 	.expected_exchange_result = 0,
5999 };
6000 
6001 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d1_mount2_src_parent)6002 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d1_mount2_src_parent) {
6003 	/* clang-format on */
6004 	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER |
6005 			LANDLOCK_ACCESS_FS_READ_FILE |
6006 			LANDLOCK_ACCESS_FS_EXECUTE |
6007 			LANDLOCK_ACCESS_FS_MAKE_REG,
6008 	.expected_read_result = EACCES,
6009 	.expected_same_dir_rename_result = EACCES,
6010 	.expected_rename_result = EACCES,
6011 	.expected_exchange_result = EACCES,
6012 };
6013 
6014 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d2_mount2_src_refer)6015 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_refer) {
6016 	/* clang-format on */
6017 	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6018 	.expected_read_result = 0,
6019 	.expected_same_dir_rename_result = EACCES,
6020 	.expected_rename_result = EACCES,
6021 	.expected_exchange_result = EACCES,
6022 };
6023 
6024 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d2_mount2_src_create)6025 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_create) {
6026 	/* clang-format on */
6027 	.allowed_s2d2 = LANDLOCK_ACCESS_FS_READ_FILE |
6028 			LANDLOCK_ACCESS_FS_MAKE_REG,
6029 	.expected_read_result = 0,
6030 	.expected_same_dir_rename_result = 0,
6031 	.expected_rename_result = EXDEV,
6032 	.expected_exchange_result = EXDEV,
6033 };
6034 
6035 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d2_mount2_src_rename)6036 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_rename) {
6037 	/* clang-format on */
6038 	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6039 	.expected_read_result = EACCES,
6040 	.expected_same_dir_rename_result = 0,
6041 	.expected_rename_result = 0,
6042 	.expected_exchange_result = 0,
6043 };
6044 
6045 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d3_mount1_dst_parent_refer)6046 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_refer) {
6047 	/* clang-format on */
6048 	.allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6049 	.expected_read_result = 0,
6050 	.expected_same_dir_rename_result = EACCES,
6051 	.expected_rename_result = EACCES,
6052 	.expected_exchange_result = EACCES,
6053 };
6054 
6055 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d3_mount1_dst_parent_create)6056 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_create) {
6057 	/* clang-format on */
6058 	.allowed_s2d3 = LANDLOCK_ACCESS_FS_READ_FILE |
6059 			LANDLOCK_ACCESS_FS_MAKE_REG,
6060 	.expected_read_result = 0,
6061 	.expected_same_dir_rename_result = 0,
6062 	.expected_rename_result = EXDEV,
6063 	.expected_exchange_result = EXDEV,
6064 };
6065 
6066 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d3_mount1_dst_parent_rename)6067 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_rename) {
6068 	/* clang-format on */
6069 	.allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6070 	.expected_read_result = EACCES,
6071 	.expected_same_dir_rename_result = 0,
6072 	.expected_rename_result = 0,
6073 	.expected_exchange_result = 0,
6074 };
6075 
6076 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s2d4_mount1_dst)6077 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d4_mount1_dst) {
6078 	/* clang-format on */
6079 	.allowed_s2d4 = LANDLOCK_ACCESS_FS_REFER |
6080 			LANDLOCK_ACCESS_FS_READ_FILE |
6081 			LANDLOCK_ACCESS_FS_EXECUTE |
6082 			LANDLOCK_ACCESS_FS_MAKE_REG,
6083 	.expected_read_result = EACCES,
6084 	.expected_same_dir_rename_result = EACCES,
6085 	.expected_rename_result = EACCES,
6086 	.expected_exchange_result = EACCES,
6087 };
6088 
6089 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s3d1_mount2_dst_parent_refer)6090 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_refer) {
6091 	/* clang-format on */
6092 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6093 	.expected_read_result = 0,
6094 	.expected_same_dir_rename_result = EACCES,
6095 	.expected_rename_result = EACCES,
6096 	.expected_exchange_result = EACCES,
6097 };
6098 
6099 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s3d1_mount2_dst_parent_create)6100 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_create) {
6101 	/* clang-format on */
6102 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE |
6103 			LANDLOCK_ACCESS_FS_MAKE_REG,
6104 	.expected_read_result = 0,
6105 	.expected_same_dir_rename_result = 0,
6106 	.expected_rename_result = EXDEV,
6107 	.expected_exchange_result = EXDEV,
6108 };
6109 
6110 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s3d1_mount2_dst_parent_rename)6111 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_rename) {
6112 	/* clang-format on */
6113 	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6114 	.expected_read_result = EACCES,
6115 	.expected_same_dir_rename_result = 0,
6116 	.expected_rename_result = 0,
6117 	.expected_exchange_result = 0,
6118 };
6119 
6120 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s3d2_mount1_dst)6121 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d2_mount1_dst) {
6122 	/* clang-format on */
6123 	.allowed_s3d2 = LANDLOCK_ACCESS_FS_REFER |
6124 			LANDLOCK_ACCESS_FS_READ_FILE |
6125 			LANDLOCK_ACCESS_FS_EXECUTE |
6126 			LANDLOCK_ACCESS_FS_MAKE_REG,
6127 	.expected_read_result = EACCES,
6128 	.expected_same_dir_rename_result = EACCES,
6129 	.expected_rename_result = EACCES,
6130 	.expected_exchange_result = EACCES,
6131 };
6132 
6133 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s4d1_rename_parent_refer)6134 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_refer) {
6135 	/* clang-format on */
6136 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6137 	.expected_read_result = 0,
6138 	.expected_same_dir_rename_result = EACCES,
6139 	.expected_rename_result = EACCES,
6140 	.expected_exchange_result = EACCES,
6141 };
6142 
6143 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s4d1_rename_parent_create)6144 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_create) {
6145 	/* clang-format on */
6146 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE |
6147 			LANDLOCK_ACCESS_FS_MAKE_REG,
6148 	.expected_read_result = 0,
6149 	.expected_same_dir_rename_result = 0,
6150 	.expected_rename_result = EXDEV,
6151 	.expected_exchange_result = EXDEV,
6152 };
6153 
6154 /* clang-format off */
FIXTURE_VARIANT_ADD(layout5_disconnected_branch,s4d1_rename_parent_rename)6155 FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_rename) {
6156 	/* clang-format on */
6157 	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6158 	.expected_read_result = EACCES,
6159 	.expected_same_dir_rename_result = 0,
6160 	.expected_rename_result = 0,
6161 	.expected_exchange_result = 0,
6162 };
6163 
TEST_F_FORK(layout5_disconnected_branch,read_rename_exchange)6164 TEST_F_FORK(layout5_disconnected_branch, read_rename_exchange)
6165 {
6166 	const __u64 handled_access =
6167 		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE |
6168 		LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG;
6169 	const struct rule rules[] = {
6170 		{
6171 			.path = TMP_DIR "/s1d1",
6172 			.access = variant->allowed_s1d1,
6173 		},
6174 		{
6175 			.path = TMP_DIR "/s1d1/s1d2",
6176 			.access = variant->allowed_s1d2,
6177 		},
6178 		{
6179 			.path = TMP_DIR "/s1d1/s1d2/s1d3",
6180 			.access = variant->allowed_s1d3,
6181 		},
6182 		{
6183 			.path = TMP_DIR "/s2d1",
6184 			.access = variant->allowed_s2d1,
6185 		},
6186 		{
6187 			.path = TMP_DIR "/s2d1/s2d2",
6188 			.access = variant->allowed_s2d2,
6189 		},
6190 		{
6191 			.path = TMP_DIR "/s2d1/s2d2/s2d3",
6192 			.access = variant->allowed_s2d3,
6193 		},
6194 		/* s2d4_fd */
6195 		{
6196 			.path = TMP_DIR "/s3d1",
6197 			.access = variant->allowed_s3d1,
6198 		},
6199 		/* s3d2_fd */
6200 		{
6201 			.path = TMP_DIR "/s4d1",
6202 			.access = variant->allowed_s4d1,
6203 		},
6204 		{},
6205 	};
6206 	int ruleset_fd, s1d3_bind_fd;
6207 
6208 	ruleset_fd = create_ruleset(_metadata, handled_access, rules);
6209 	ASSERT_LE(0, ruleset_fd);
6210 
6211 	/* Adds rules for the covered directories. */
6212 	if (variant->allowed_s2d4) {
6213 		ASSERT_EQ(0, landlock_add_rule(
6214 				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
6215 				     &(struct landlock_path_beneath_attr){
6216 					     .parent_fd = self->s2d4_fd,
6217 					     .allowed_access =
6218 						     variant->allowed_s2d4,
6219 				     },
6220 				     0));
6221 	}
6222 	EXPECT_EQ(0, close(self->s2d4_fd));
6223 
6224 	if (variant->allowed_s3d2) {
6225 		ASSERT_EQ(0, landlock_add_rule(
6226 				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
6227 				     &(struct landlock_path_beneath_attr){
6228 					     .parent_fd = self->s3d2_fd,
6229 					     .allowed_access =
6230 						     variant->allowed_s3d2,
6231 				     },
6232 				     0));
6233 	}
6234 	EXPECT_EQ(0, close(self->s3d2_fd));
6235 
6236 	s1d3_bind_fd = open(TMP_DIR "/s3d1/s3d2/s2d3/s2d4/s1d3",
6237 			    O_DIRECTORY | O_PATH | O_CLOEXEC);
6238 	ASSERT_LE(0, s1d3_bind_fd);
6239 
6240 	/* Disconnects and checks source and destination directories. */
6241 	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY));
6242 	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY));
6243 	/* Renames to make it accessible through s3d1/s1d41 */
6244 	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s2d1/s2d2/s2d3",
6245 				   AT_FDCWD, TMP_DIR "/s4d1/s2d3"));
6246 	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY));
6247 	EXPECT_EQ(ENOENT, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY));
6248 
6249 	enforce_ruleset(_metadata, ruleset_fd);
6250 	EXPECT_EQ(0, close(ruleset_fd));
6251 
6252 	EXPECT_EQ(variant->expected_read_result,
6253 		  test_open_rel(s1d3_bind_fd, "s1d41/f1", O_RDONLY));
6254 
6255 	EXPECT_EQ(variant->expected_rename_result,
6256 		  test_renameat(s1d3_bind_fd, "s1d41/f1", s1d3_bind_fd,
6257 				"s1d42/f1"));
6258 	EXPECT_EQ(variant->expected_exchange_result,
6259 		  test_exchangeat(s1d3_bind_fd, "s1d41/f2", s1d3_bind_fd,
6260 				  "s1d42/f3"));
6261 
6262 	EXPECT_EQ(variant->expected_same_dir_rename_result,
6263 		  test_renameat(s1d3_bind_fd, "s1d42/f4", s1d3_bind_fd,
6264 				"s1d42/f5"));
6265 }
6266 
6267 #define LOWER_BASE TMP_DIR "/lower"
6268 #define LOWER_DATA LOWER_BASE "/data"
6269 static const char lower_fl1[] = LOWER_DATA "/fl1";
6270 static const char lower_dl1[] = LOWER_DATA "/dl1";
6271 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
6272 static const char lower_fo1[] = LOWER_DATA "/fo1";
6273 static const char lower_do1[] = LOWER_DATA "/do1";
6274 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
6275 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
6276 
6277 static const char (*lower_base_files[])[] = {
6278 	&lower_fl1,
6279 	&lower_fo1,
6280 	NULL,
6281 };
6282 static const char (*lower_base_directories[])[] = {
6283 	&lower_dl1,
6284 	&lower_do1,
6285 	NULL,
6286 };
6287 static const char (*lower_sub_files[])[] = {
6288 	&lower_dl1_fl2,
6289 	&lower_do1_fo2,
6290 	&lower_do1_fl3,
6291 	NULL,
6292 };
6293 
6294 #define UPPER_BASE TMP_DIR "/upper"
6295 #define UPPER_DATA UPPER_BASE "/data"
6296 #define UPPER_WORK UPPER_BASE "/work"
6297 static const char upper_fu1[] = UPPER_DATA "/fu1";
6298 static const char upper_du1[] = UPPER_DATA "/du1";
6299 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
6300 static const char upper_fo1[] = UPPER_DATA "/fo1";
6301 static const char upper_do1[] = UPPER_DATA "/do1";
6302 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
6303 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
6304 
6305 static const char (*upper_base_files[])[] = {
6306 	&upper_fu1,
6307 	&upper_fo1,
6308 	NULL,
6309 };
6310 static const char (*upper_base_directories[])[] = {
6311 	&upper_du1,
6312 	&upper_do1,
6313 	NULL,
6314 };
6315 static const char (*upper_sub_files[])[] = {
6316 	&upper_du1_fu2,
6317 	&upper_do1_fo2,
6318 	&upper_do1_fu3,
6319 	NULL,
6320 };
6321 
6322 #define MERGE_BASE TMP_DIR "/merge"
6323 #define MERGE_DATA MERGE_BASE "/data"
6324 static const char merge_fl1[] = MERGE_DATA "/fl1";
6325 static const char merge_dl1[] = MERGE_DATA "/dl1";
6326 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
6327 static const char merge_fu1[] = MERGE_DATA "/fu1";
6328 static const char merge_du1[] = MERGE_DATA "/du1";
6329 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
6330 static const char merge_fo1[] = MERGE_DATA "/fo1";
6331 static const char merge_do1[] = MERGE_DATA "/do1";
6332 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
6333 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
6334 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
6335 
6336 static const char (*merge_base_files[])[] = {
6337 	&merge_fl1,
6338 	&merge_fu1,
6339 	&merge_fo1,
6340 	NULL,
6341 };
6342 static const char (*merge_base_directories[])[] = {
6343 	&merge_dl1,
6344 	&merge_du1,
6345 	&merge_do1,
6346 	NULL,
6347 };
6348 static const char (*merge_sub_files[])[] = {
6349 	&merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2,
6350 	&merge_do1_fl3, &merge_do1_fu3, NULL,
6351 };
6352 
6353 /*
6354  * layout2_overlay hierarchy:
6355  *
6356  * tmp
6357  * ├── lower
6358  * │   └── data
6359  * │       ├── dl1
6360  * │       │   └── fl2
6361  * │       ├── do1
6362  * │       │   ├── fl3
6363  * │       │   └── fo2
6364  * │       ├── fl1
6365  * │       └── fo1
6366  * ├── merge
6367  * │   └── data
6368  * │       ├── dl1
6369  * │       │   └── fl2
6370  * │       ├── do1
6371  * │       │   ├── fl3
6372  * │       │   ├── fo2
6373  * │       │   └── fu3
6374  * │       ├── du1
6375  * │       │   └── fu2
6376  * │       ├── fl1
6377  * │       ├── fo1
6378  * │       └── fu1
6379  * └── upper
6380  *     ├── data
6381  *     │   ├── do1
6382  *     │   │   ├── fo2
6383  *     │   │   └── fu3
6384  *     │   ├── du1
6385  *     │   │   └── fu2
6386  *     │   ├── fo1
6387  *     │   └── fu1
6388  *     └── work
6389  *         └── work
6390  */
6391 
FIXTURE(layout2_overlay)6392 FIXTURE(layout2_overlay)
6393 {
6394 	bool skip_test;
6395 };
6396 
FIXTURE_SETUP(layout2_overlay)6397 FIXTURE_SETUP(layout2_overlay)
6398 {
6399 	if (!supports_filesystem("overlay")) {
6400 		self->skip_test = true;
6401 		SKIP(return, "overlayfs is not supported (setup)");
6402 	}
6403 
6404 	prepare_layout(_metadata);
6405 
6406 	create_directory(_metadata, LOWER_BASE);
6407 	set_cap(_metadata, CAP_SYS_ADMIN);
6408 	/* Creates tmpfs mount points to get deterministic overlayfs. */
6409 	ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE));
6410 	clear_cap(_metadata, CAP_SYS_ADMIN);
6411 	create_file(_metadata, lower_fl1);
6412 	create_file(_metadata, lower_dl1_fl2);
6413 	create_file(_metadata, lower_fo1);
6414 	create_file(_metadata, lower_do1_fo2);
6415 	create_file(_metadata, lower_do1_fl3);
6416 
6417 	create_directory(_metadata, UPPER_BASE);
6418 	set_cap(_metadata, CAP_SYS_ADMIN);
6419 	ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE));
6420 	clear_cap(_metadata, CAP_SYS_ADMIN);
6421 	create_file(_metadata, upper_fu1);
6422 	create_file(_metadata, upper_du1_fu2);
6423 	create_file(_metadata, upper_fo1);
6424 	create_file(_metadata, upper_do1_fo2);
6425 	create_file(_metadata, upper_do1_fu3);
6426 	ASSERT_EQ(0, mkdir(UPPER_WORK, 0700));
6427 
6428 	create_directory(_metadata, MERGE_DATA);
6429 	set_cap(_metadata, CAP_SYS_ADMIN);
6430 	set_cap(_metadata, CAP_DAC_OVERRIDE);
6431 	ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0,
6432 			   "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA
6433 			   ",workdir=" UPPER_WORK));
6434 	clear_cap(_metadata, CAP_DAC_OVERRIDE);
6435 	clear_cap(_metadata, CAP_SYS_ADMIN);
6436 }
6437 
FIXTURE_TEARDOWN_PARENT(layout2_overlay)6438 FIXTURE_TEARDOWN_PARENT(layout2_overlay)
6439 {
6440 	if (self->skip_test)
6441 		SKIP(return, "overlayfs is not supported (teardown)");
6442 
6443 	EXPECT_EQ(0, remove_path(lower_do1_fl3));
6444 	EXPECT_EQ(0, remove_path(lower_dl1_fl2));
6445 	EXPECT_EQ(0, remove_path(lower_fl1));
6446 	EXPECT_EQ(0, remove_path(lower_do1_fo2));
6447 	EXPECT_EQ(0, remove_path(lower_fo1));
6448 
6449 	/* umount(LOWER_BASE)) is handled by namespace lifetime. */
6450 	EXPECT_EQ(0, remove_path(LOWER_BASE));
6451 
6452 	EXPECT_EQ(0, remove_path(upper_do1_fu3));
6453 	EXPECT_EQ(0, remove_path(upper_du1_fu2));
6454 	EXPECT_EQ(0, remove_path(upper_fu1));
6455 	EXPECT_EQ(0, remove_path(upper_do1_fo2));
6456 	EXPECT_EQ(0, remove_path(upper_fo1));
6457 	EXPECT_EQ(0, remove_path(UPPER_WORK "/work"));
6458 
6459 	/* umount(UPPER_BASE)) is handled by namespace lifetime. */
6460 	EXPECT_EQ(0, remove_path(UPPER_BASE));
6461 
6462 	/* umount(MERGE_DATA)) is handled by namespace lifetime. */
6463 	EXPECT_EQ(0, remove_path(MERGE_DATA));
6464 
6465 	cleanup_layout(_metadata);
6466 }
6467 
TEST_F_FORK(layout2_overlay,no_restriction)6468 TEST_F_FORK(layout2_overlay, no_restriction)
6469 {
6470 	if (self->skip_test)
6471 		SKIP(return, "overlayfs is not supported (test)");
6472 
6473 	ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
6474 	ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
6475 	ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY));
6476 	ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY));
6477 	ASSERT_EQ(0, test_open(lower_do1, O_RDONLY));
6478 	ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY));
6479 	ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY));
6480 
6481 	ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY));
6482 	ASSERT_EQ(0, test_open(upper_du1, O_RDONLY));
6483 	ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY));
6484 	ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY));
6485 	ASSERT_EQ(0, test_open(upper_do1, O_RDONLY));
6486 	ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY));
6487 	ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY));
6488 
6489 	ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY));
6490 	ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY));
6491 	ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY));
6492 	ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY));
6493 	ASSERT_EQ(0, test_open(merge_du1, O_RDONLY));
6494 	ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY));
6495 	ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY));
6496 	ASSERT_EQ(0, test_open(merge_do1, O_RDONLY));
6497 	ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY));
6498 	ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY));
6499 	ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY));
6500 }
6501 
6502 #define for_each_path(path_list, path_entry, i)               \
6503 	for (i = 0, path_entry = *path_list[i]; path_list[i]; \
6504 	     path_entry = *path_list[++i])
6505 
TEST_F_FORK(layout2_overlay,same_content_different_file)6506 TEST_F_FORK(layout2_overlay, same_content_different_file)
6507 {
6508 	/* Sets access right on parent directories of both layers. */
6509 	const struct rule layer1_base[] = {
6510 		{
6511 			.path = LOWER_BASE,
6512 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6513 		},
6514 		{
6515 			.path = UPPER_BASE,
6516 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6517 		},
6518 		{
6519 			.path = MERGE_BASE,
6520 			.access = ACCESS_RW,
6521 		},
6522 		{},
6523 	};
6524 	const struct rule layer2_data[] = {
6525 		{
6526 			.path = LOWER_DATA,
6527 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6528 		},
6529 		{
6530 			.path = UPPER_DATA,
6531 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6532 		},
6533 		{
6534 			.path = MERGE_DATA,
6535 			.access = ACCESS_RW,
6536 		},
6537 		{},
6538 	};
6539 	/* Sets access right on directories inside both layers. */
6540 	const struct rule layer3_subdirs[] = {
6541 		{
6542 			.path = lower_dl1,
6543 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6544 		},
6545 		{
6546 			.path = lower_do1,
6547 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6548 		},
6549 		{
6550 			.path = upper_du1,
6551 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6552 		},
6553 		{
6554 			.path = upper_do1,
6555 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6556 		},
6557 		{
6558 			.path = merge_dl1,
6559 			.access = ACCESS_RW,
6560 		},
6561 		{
6562 			.path = merge_du1,
6563 			.access = ACCESS_RW,
6564 		},
6565 		{
6566 			.path = merge_do1,
6567 			.access = ACCESS_RW,
6568 		},
6569 		{},
6570 	};
6571 	/* Tighten access rights to the files. */
6572 	const struct rule layer4_files[] = {
6573 		{
6574 			.path = lower_dl1_fl2,
6575 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6576 		},
6577 		{
6578 			.path = lower_do1_fo2,
6579 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6580 		},
6581 		{
6582 			.path = lower_do1_fl3,
6583 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6584 		},
6585 		{
6586 			.path = upper_du1_fu2,
6587 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6588 		},
6589 		{
6590 			.path = upper_do1_fo2,
6591 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6592 		},
6593 		{
6594 			.path = upper_do1_fu3,
6595 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6596 		},
6597 		{
6598 			.path = merge_dl1_fl2,
6599 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6600 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6601 		},
6602 		{
6603 			.path = merge_du1_fu2,
6604 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6605 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6606 		},
6607 		{
6608 			.path = merge_do1_fo2,
6609 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6610 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6611 		},
6612 		{
6613 			.path = merge_do1_fl3,
6614 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6615 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6616 		},
6617 		{
6618 			.path = merge_do1_fu3,
6619 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6620 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6621 		},
6622 		{},
6623 	};
6624 	const struct rule layer5_merge_only[] = {
6625 		{
6626 			.path = MERGE_DATA,
6627 			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6628 				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6629 		},
6630 		{},
6631 	};
6632 	int ruleset_fd;
6633 	size_t i;
6634 	const char *path_entry;
6635 
6636 	if (self->skip_test)
6637 		SKIP(return, "overlayfs is not supported (test)");
6638 
6639 	/* Sets rules on base directories (i.e. outside overlay scope). */
6640 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
6641 	ASSERT_LE(0, ruleset_fd);
6642 	enforce_ruleset(_metadata, ruleset_fd);
6643 	ASSERT_EQ(0, close(ruleset_fd));
6644 
6645 	/* Checks lower layer. */
6646 	for_each_path(lower_base_files, path_entry, i) {
6647 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6648 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6649 	}
6650 	for_each_path(lower_base_directories, path_entry, i) {
6651 		ASSERT_EQ(EACCES,
6652 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6653 	}
6654 	for_each_path(lower_sub_files, path_entry, i) {
6655 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6656 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6657 	}
6658 	/* Checks upper layer. */
6659 	for_each_path(upper_base_files, path_entry, i) {
6660 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6661 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6662 	}
6663 	for_each_path(upper_base_directories, path_entry, i) {
6664 		ASSERT_EQ(EACCES,
6665 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6666 	}
6667 	for_each_path(upper_sub_files, path_entry, i) {
6668 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6669 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6670 	}
6671 	/*
6672 	 * Checks that access rights are independent from the lower and upper
6673 	 * layers: write access to upper files viewed through the merge point
6674 	 * is still allowed, and write access to lower file viewed (and copied)
6675 	 * through the merge point is still allowed.
6676 	 */
6677 	for_each_path(merge_base_files, path_entry, i) {
6678 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6679 	}
6680 	for_each_path(merge_base_directories, path_entry, i) {
6681 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6682 	}
6683 	for_each_path(merge_sub_files, path_entry, i) {
6684 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6685 	}
6686 
6687 	/* Sets rules on data directories (i.e. inside overlay scope). */
6688 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data);
6689 	ASSERT_LE(0, ruleset_fd);
6690 	enforce_ruleset(_metadata, ruleset_fd);
6691 	ASSERT_EQ(0, close(ruleset_fd));
6692 
6693 	/* Checks merge. */
6694 	for_each_path(merge_base_files, path_entry, i) {
6695 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6696 	}
6697 	for_each_path(merge_base_directories, path_entry, i) {
6698 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6699 	}
6700 	for_each_path(merge_sub_files, path_entry, i) {
6701 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6702 	}
6703 
6704 	/* Same checks with tighter rules. */
6705 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs);
6706 	ASSERT_LE(0, ruleset_fd);
6707 	enforce_ruleset(_metadata, ruleset_fd);
6708 	ASSERT_EQ(0, close(ruleset_fd));
6709 
6710 	/* Checks changes for lower layer. */
6711 	for_each_path(lower_base_files, path_entry, i) {
6712 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6713 	}
6714 	/* Checks changes for upper layer. */
6715 	for_each_path(upper_base_files, path_entry, i) {
6716 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6717 	}
6718 	/* Checks all merge accesses. */
6719 	for_each_path(merge_base_files, path_entry, i) {
6720 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6721 	}
6722 	for_each_path(merge_base_directories, path_entry, i) {
6723 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6724 	}
6725 	for_each_path(merge_sub_files, path_entry, i) {
6726 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6727 	}
6728 
6729 	/* Sets rules directly on overlayed files. */
6730 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files);
6731 	ASSERT_LE(0, ruleset_fd);
6732 	enforce_ruleset(_metadata, ruleset_fd);
6733 	ASSERT_EQ(0, close(ruleset_fd));
6734 
6735 	/* Checks unchanged accesses on lower layer. */
6736 	for_each_path(lower_sub_files, path_entry, i) {
6737 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6738 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6739 	}
6740 	/* Checks unchanged accesses on upper layer. */
6741 	for_each_path(upper_sub_files, path_entry, i) {
6742 		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6743 		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6744 	}
6745 	/* Checks all merge accesses. */
6746 	for_each_path(merge_base_files, path_entry, i) {
6747 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6748 	}
6749 	for_each_path(merge_base_directories, path_entry, i) {
6750 		ASSERT_EQ(EACCES,
6751 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6752 	}
6753 	for_each_path(merge_sub_files, path_entry, i) {
6754 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6755 	}
6756 
6757 	/* Only allowes access to the merge hierarchy. */
6758 	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only);
6759 	ASSERT_LE(0, ruleset_fd);
6760 	enforce_ruleset(_metadata, ruleset_fd);
6761 	ASSERT_EQ(0, close(ruleset_fd));
6762 
6763 	/* Checks new accesses on lower layer. */
6764 	for_each_path(lower_sub_files, path_entry, i) {
6765 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6766 	}
6767 	/* Checks new accesses on upper layer. */
6768 	for_each_path(upper_sub_files, path_entry, i) {
6769 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6770 	}
6771 	/* Checks all merge accesses. */
6772 	for_each_path(merge_base_files, path_entry, i) {
6773 		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6774 	}
6775 	for_each_path(merge_base_directories, path_entry, i) {
6776 		ASSERT_EQ(EACCES,
6777 			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6778 	}
6779 	for_each_path(merge_sub_files, path_entry, i) {
6780 		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6781 	}
6782 }
6783 
FIXTURE(layout3_fs)6784 FIXTURE(layout3_fs)
6785 {
6786 	bool has_created_dir;
6787 	bool has_created_file;
6788 	bool skip_test;
6789 };
6790 
FIXTURE_VARIANT(layout3_fs)6791 FIXTURE_VARIANT(layout3_fs)
6792 {
6793 	const struct mnt_opt mnt;
6794 	const char *const file_path;
6795 	unsigned int cwd_fs_magic;
6796 };
6797 
6798 /* clang-format off */
FIXTURE_VARIANT_ADD(layout3_fs,tmpfs)6799 FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
6800 	/* clang-format on */
6801 	.mnt = {
6802 		.type = "tmpfs",
6803 		.data = MNT_TMP_DATA,
6804 	},
6805 	.file_path = file1_s1d1,
6806 };
6807 
FIXTURE_VARIANT_ADD(layout3_fs,ramfs)6808 FIXTURE_VARIANT_ADD(layout3_fs, ramfs) {
6809 	.mnt = {
6810 		.type = "ramfs",
6811 		.data = "mode=700",
6812 	},
6813 	.file_path = TMP_DIR "/dir/file",
6814 };
6815 
FIXTURE_VARIANT_ADD(layout3_fs,cgroup2)6816 FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) {
6817 	.mnt = {
6818 		.type = "cgroup2",
6819 	},
6820 	.file_path = TMP_DIR "/test/cgroup.procs",
6821 };
6822 
FIXTURE_VARIANT_ADD(layout3_fs,proc)6823 FIXTURE_VARIANT_ADD(layout3_fs, proc) {
6824 	.mnt = {
6825 		.type = "proc",
6826 	},
6827 	.file_path = TMP_DIR "/self/status",
6828 };
6829 
FIXTURE_VARIANT_ADD(layout3_fs,sysfs)6830 FIXTURE_VARIANT_ADD(layout3_fs, sysfs) {
6831 	.mnt = {
6832 		.type = "sysfs",
6833 	},
6834 	.file_path = TMP_DIR "/kernel/notes",
6835 };
6836 
FIXTURE_VARIANT_ADD(layout3_fs,hostfs)6837 FIXTURE_VARIANT_ADD(layout3_fs, hostfs) {
6838 	.mnt = {
6839 		.source = TMP_DIR,
6840 		.flags = MS_BIND,
6841 	},
6842 	.file_path = TMP_DIR "/dir/file",
6843 	.cwd_fs_magic = HOSTFS_SUPER_MAGIC,
6844 };
6845 
dirname_alloc(const char * path)6846 static char *dirname_alloc(const char *path)
6847 {
6848 	char *dup;
6849 
6850 	if (!path)
6851 		return NULL;
6852 
6853 	dup = strdup(path);
6854 	if (!dup)
6855 		return NULL;
6856 
6857 	return dirname(dup);
6858 }
6859 
FIXTURE_SETUP(layout3_fs)6860 FIXTURE_SETUP(layout3_fs)
6861 {
6862 	struct stat statbuf;
6863 	char *dir_path = dirname_alloc(variant->file_path);
6864 
6865 	if (!supports_filesystem(variant->mnt.type) ||
6866 	    !cwd_matches_fs(variant->cwd_fs_magic)) {
6867 		self->skip_test = true;
6868 		SKIP(return, "this filesystem is not supported (setup)");
6869 	}
6870 
6871 	prepare_layout_opt(_metadata, &variant->mnt);
6872 
6873 	/* Creates directory when required. */
6874 	if (stat(dir_path, &statbuf)) {
6875 		set_cap(_metadata, CAP_DAC_OVERRIDE);
6876 		EXPECT_EQ(0, mkdir(dir_path, 0700))
6877 		{
6878 			TH_LOG("Failed to create directory \"%s\": %s",
6879 			       dir_path, strerror(errno));
6880 		}
6881 		self->has_created_dir = true;
6882 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6883 	}
6884 
6885 	/* Creates file when required. */
6886 	if (stat(variant->file_path, &statbuf)) {
6887 		int fd;
6888 
6889 		set_cap(_metadata, CAP_DAC_OVERRIDE);
6890 		fd = creat(variant->file_path, 0600);
6891 		EXPECT_LE(0, fd)
6892 		{
6893 			TH_LOG("Failed to create file \"%s\": %s",
6894 			       variant->file_path, strerror(errno));
6895 		}
6896 		EXPECT_EQ(0, close(fd));
6897 		self->has_created_file = true;
6898 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6899 	}
6900 
6901 	free(dir_path);
6902 }
6903 
FIXTURE_TEARDOWN_PARENT(layout3_fs)6904 FIXTURE_TEARDOWN_PARENT(layout3_fs)
6905 {
6906 	if (self->skip_test)
6907 		SKIP(return, "this filesystem is not supported (teardown)");
6908 
6909 	if (self->has_created_file) {
6910 		set_cap(_metadata, CAP_DAC_OVERRIDE);
6911 		/*
6912 		 * Don't check for error because the file might already
6913 		 * have been removed (cf. release_inode test).
6914 		 */
6915 		unlink(variant->file_path);
6916 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6917 	}
6918 
6919 	if (self->has_created_dir) {
6920 		char *dir_path = dirname_alloc(variant->file_path);
6921 
6922 		set_cap(_metadata, CAP_DAC_OVERRIDE);
6923 		/*
6924 		 * Don't check for error because the directory might already
6925 		 * have been removed (cf. release_inode test).
6926 		 */
6927 		rmdir(dir_path);
6928 		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6929 		free(dir_path);
6930 	}
6931 
6932 	cleanup_layout(_metadata);
6933 }
6934 
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)6935 static void layer3_fs_tag_inode(struct __test_metadata *const _metadata,
6936 				FIXTURE_DATA(layout3_fs) * self,
6937 				const FIXTURE_VARIANT(layout3_fs) * variant,
6938 				const char *const rule_path)
6939 {
6940 	const struct rule layer1_allow_read_file[] = {
6941 		{
6942 			.path = rule_path,
6943 			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6944 		},
6945 		{},
6946 	};
6947 	const struct landlock_ruleset_attr layer2_deny_everything_attr = {
6948 		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
6949 	};
6950 	const char *const dev_null_path = "/dev/null";
6951 	int ruleset_fd;
6952 
6953 	if (self->skip_test)
6954 		SKIP(return, "this filesystem is not supported (test)");
6955 
6956 	/* Checks without Landlock. */
6957 	EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6958 	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6959 
6960 	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
6961 				    layer1_allow_read_file);
6962 	EXPECT_LE(0, ruleset_fd);
6963 	enforce_ruleset(_metadata, ruleset_fd);
6964 	EXPECT_EQ(0, close(ruleset_fd));
6965 
6966 	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6967 	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6968 
6969 	/* Forbids directory reading. */
6970 	ruleset_fd =
6971 		landlock_create_ruleset(&layer2_deny_everything_attr,
6972 					sizeof(layer2_deny_everything_attr), 0);
6973 	EXPECT_LE(0, ruleset_fd);
6974 	enforce_ruleset(_metadata, ruleset_fd);
6975 	EXPECT_EQ(0, close(ruleset_fd));
6976 
6977 	/* Checks with Landlock and forbidden access. */
6978 	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6979 	EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6980 }
6981 
6982 /* Matrix of tests to check file hierarchy evaluation. */
6983 
TEST_F_FORK(layout3_fs,tag_inode_dir_parent)6984 TEST_F_FORK(layout3_fs, tag_inode_dir_parent)
6985 {
6986 	/* The current directory must not be the root for this test. */
6987 	layer3_fs_tag_inode(_metadata, self, variant, ".");
6988 }
6989 
TEST_F_FORK(layout3_fs,tag_inode_dir_mnt)6990 TEST_F_FORK(layout3_fs, tag_inode_dir_mnt)
6991 {
6992 	layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR);
6993 }
6994 
TEST_F_FORK(layout3_fs,tag_inode_dir_child)6995 TEST_F_FORK(layout3_fs, tag_inode_dir_child)
6996 {
6997 	char *dir_path = dirname_alloc(variant->file_path);
6998 
6999 	layer3_fs_tag_inode(_metadata, self, variant, dir_path);
7000 	free(dir_path);
7001 }
7002 
TEST_F_FORK(layout3_fs,tag_inode_file)7003 TEST_F_FORK(layout3_fs, tag_inode_file)
7004 {
7005 	layer3_fs_tag_inode(_metadata, self, variant, variant->file_path);
7006 }
7007 
7008 /* Light version of layout1.release_inodes */
TEST_F_FORK(layout3_fs,release_inodes)7009 TEST_F_FORK(layout3_fs, release_inodes)
7010 {
7011 	const struct rule layer1[] = {
7012 		{
7013 			.path = TMP_DIR,
7014 			.access = LANDLOCK_ACCESS_FS_READ_DIR,
7015 		},
7016 		{},
7017 	};
7018 	int ruleset_fd;
7019 
7020 	if (self->skip_test)
7021 		SKIP(return, "this filesystem is not supported (test)");
7022 
7023 	/* Clean up for the teardown to not fail. */
7024 	if (self->has_created_file)
7025 		EXPECT_EQ(0, remove_path(variant->file_path));
7026 
7027 	if (self->has_created_dir) {
7028 		char *dir_path = dirname_alloc(variant->file_path);
7029 
7030 		/* Don't check for error because of cgroup specificities. */
7031 		remove_path(dir_path);
7032 		free(dir_path);
7033 	}
7034 
7035 	ruleset_fd =
7036 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
7037 	ASSERT_LE(0, ruleset_fd);
7038 
7039 	/* Unmount the filesystem while it is being used by a ruleset. */
7040 	set_cap(_metadata, CAP_SYS_ADMIN);
7041 	ASSERT_EQ(0, umount(TMP_DIR));
7042 	clear_cap(_metadata, CAP_SYS_ADMIN);
7043 
7044 	/* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */
7045 	set_cap(_metadata, CAP_SYS_ADMIN);
7046 	ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR));
7047 	clear_cap(_metadata, CAP_SYS_ADMIN);
7048 
7049 	enforce_ruleset(_metadata, ruleset_fd);
7050 	ASSERT_EQ(0, close(ruleset_fd));
7051 
7052 	/* Checks that access to the new mount point is denied. */
7053 	ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY));
7054 }
7055 
matches_log_fs_extra(struct __test_metadata * const _metadata,int audit_fd,const char * const blockers,const char * const path,const char * const extra)7056 static int matches_log_fs_extra(struct __test_metadata *const _metadata,
7057 				int audit_fd, const char *const blockers,
7058 				const char *const path, const char *const extra)
7059 {
7060 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
7061 		" blockers=fs\\.%s path=\"%s\" dev=\"[^\"]\\+\" ino=[0-9]\\+$";
7062 	char *absolute_path = NULL;
7063 	size_t log_match_remaining = sizeof(log_template) + strlen(blockers) +
7064 				     PATH_MAX * 2 +
7065 				     (extra ? strlen(extra) : 0) + 1;
7066 	char log_match[log_match_remaining];
7067 	char *log_match_cursor = log_match;
7068 	size_t chunk_len;
7069 
7070 	chunk_len = snprintf(log_match_cursor, log_match_remaining,
7071 			     REGEX_LANDLOCK_PREFIX " blockers=%s path=\"",
7072 			     blockers);
7073 	if (chunk_len < 0 || chunk_len >= log_match_remaining)
7074 		return -E2BIG;
7075 
7076 	/*
7077 	 * It is assume that absolute_path does not contain control characters nor
7078 	 * spaces, see audit_string_contains_control().
7079 	 */
7080 	absolute_path = realpath(path, NULL);
7081 	if (!absolute_path)
7082 		return -errno;
7083 
7084 	log_match_remaining -= chunk_len;
7085 	log_match_cursor += chunk_len;
7086 	log_match_cursor = regex_escape(absolute_path, log_match_cursor,
7087 					log_match_remaining);
7088 	free(absolute_path);
7089 	if (log_match_cursor < 0)
7090 		return (long long)log_match_cursor;
7091 
7092 	log_match_remaining -= log_match_cursor - log_match;
7093 	chunk_len = snprintf(log_match_cursor, log_match_remaining,
7094 			     "\" dev=\"[^\"]\\+\" ino=[0-9]\\+%s$",
7095 			     extra ?: "");
7096 	if (chunk_len < 0 || chunk_len >= log_match_remaining)
7097 		return -E2BIG;
7098 
7099 	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
7100 				  NULL);
7101 }
7102 
matches_log_fs(struct __test_metadata * const _metadata,int audit_fd,const char * const blockers,const char * const path)7103 static int matches_log_fs(struct __test_metadata *const _metadata, int audit_fd,
7104 			  const char *const blockers, const char *const path)
7105 {
7106 	return matches_log_fs_extra(_metadata, audit_fd, blockers, path, NULL);
7107 }
7108 
FIXTURE(audit_layout1)7109 FIXTURE(audit_layout1)
7110 {
7111 	struct audit_filter audit_filter;
7112 	int audit_fd;
7113 };
7114 
FIXTURE_SETUP(audit_layout1)7115 FIXTURE_SETUP(audit_layout1)
7116 {
7117 	prepare_layout(_metadata);
7118 
7119 	create_layout1(_metadata);
7120 
7121 	set_cap(_metadata, CAP_AUDIT_CONTROL);
7122 	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
7123 	EXPECT_LE(0, self->audit_fd);
7124 	disable_caps(_metadata);
7125 }
7126 
FIXTURE_TEARDOWN_PARENT(audit_layout1)7127 FIXTURE_TEARDOWN_PARENT(audit_layout1)
7128 {
7129 	remove_layout1(_metadata);
7130 
7131 	cleanup_layout(_metadata);
7132 
7133 	EXPECT_EQ(0, audit_cleanup(-1, NULL));
7134 }
7135 
TEST_F(audit_layout1,execute_make)7136 TEST_F(audit_layout1, execute_make)
7137 {
7138 	struct audit_records records;
7139 
7140 	copy_file(_metadata, bin_true, file1_s1d1);
7141 	test_execute(_metadata, 0, file1_s1d1);
7142 	test_check_exec(_metadata, 0, file1_s1d1);
7143 
7144 	drop_access_rights(_metadata,
7145 			   &(struct landlock_ruleset_attr){
7146 				   .handled_access_fs =
7147 					   LANDLOCK_ACCESS_FS_EXECUTE,
7148 			   });
7149 
7150 	test_execute(_metadata, EACCES, file1_s1d1);
7151 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
7152 				    file1_s1d1));
7153 	test_check_exec(_metadata, EACCES, file1_s1d1);
7154 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
7155 				    file1_s1d1));
7156 
7157 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7158 	EXPECT_EQ(0, records.access);
7159 	EXPECT_EQ(0, records.domain);
7160 }
7161 
7162 /*
7163  * Using a set of handled/denied access rights make it possible to check that
7164  * only the blocked ones are logged.
7165  */
7166 
7167 /* clang-format off */
7168 static const __u64 access_fs_16 =
7169 	LANDLOCK_ACCESS_FS_EXECUTE |
7170 	LANDLOCK_ACCESS_FS_WRITE_FILE |
7171 	LANDLOCK_ACCESS_FS_READ_FILE |
7172 	LANDLOCK_ACCESS_FS_READ_DIR |
7173 	LANDLOCK_ACCESS_FS_REMOVE_DIR |
7174 	LANDLOCK_ACCESS_FS_REMOVE_FILE |
7175 	LANDLOCK_ACCESS_FS_MAKE_CHAR |
7176 	LANDLOCK_ACCESS_FS_MAKE_DIR |
7177 	LANDLOCK_ACCESS_FS_MAKE_REG |
7178 	LANDLOCK_ACCESS_FS_MAKE_SOCK |
7179 	LANDLOCK_ACCESS_FS_MAKE_FIFO |
7180 	LANDLOCK_ACCESS_FS_MAKE_BLOCK |
7181 	LANDLOCK_ACCESS_FS_MAKE_SYM |
7182 	LANDLOCK_ACCESS_FS_REFER |
7183 	LANDLOCK_ACCESS_FS_TRUNCATE |
7184 	LANDLOCK_ACCESS_FS_IOCTL_DEV;
7185 /* clang-format on */
7186 
TEST_F(audit_layout1,execute_read)7187 TEST_F(audit_layout1, execute_read)
7188 {
7189 	struct audit_records records;
7190 
7191 	copy_file(_metadata, bin_true, file1_s1d1);
7192 	test_execute(_metadata, 0, file1_s1d1);
7193 	test_check_exec(_metadata, 0, file1_s1d1);
7194 
7195 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7196 					      .handled_access_fs = access_fs_16,
7197 				      });
7198 
7199 	/*
7200 	 * The only difference with the previous audit_layout1.execute_read test is
7201 	 * the extra ",fs\\.read_file" blocked by the executable file.
7202 	 */
7203 	test_execute(_metadata, EACCES, file1_s1d1);
7204 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7205 				    "fs\\.execute,fs\\.read_file", file1_s1d1));
7206 	test_check_exec(_metadata, EACCES, file1_s1d1);
7207 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7208 				    "fs\\.execute,fs\\.read_file", file1_s1d1));
7209 
7210 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7211 	EXPECT_EQ(0, records.access);
7212 	EXPECT_EQ(0, records.domain);
7213 }
7214 
TEST_F(audit_layout1,write_file)7215 TEST_F(audit_layout1, write_file)
7216 {
7217 	struct audit_records records;
7218 
7219 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7220 					      .handled_access_fs = access_fs_16,
7221 				      });
7222 
7223 	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
7224 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7225 				    "fs\\.write_file", file1_s1d1));
7226 
7227 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7228 	EXPECT_EQ(0, records.access);
7229 	EXPECT_EQ(1, records.domain);
7230 }
7231 
TEST_F(audit_layout1,read_file)7232 TEST_F(audit_layout1, read_file)
7233 {
7234 	struct audit_records records;
7235 
7236 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7237 					      .handled_access_fs = access_fs_16,
7238 				      });
7239 
7240 	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
7241 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_file",
7242 				    file1_s1d1));
7243 
7244 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7245 	EXPECT_EQ(0, records.access);
7246 	EXPECT_EQ(1, records.domain);
7247 }
7248 
TEST_F(audit_layout1,read_dir)7249 TEST_F(audit_layout1, read_dir)
7250 {
7251 	struct audit_records records;
7252 
7253 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7254 					      .handled_access_fs = access_fs_16,
7255 				      });
7256 
7257 	EXPECT_EQ(EACCES, test_open(dir_s1d1, O_DIRECTORY));
7258 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_dir",
7259 				    dir_s1d1));
7260 
7261 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7262 	EXPECT_EQ(0, records.access);
7263 	EXPECT_EQ(1, records.domain);
7264 }
7265 
TEST_F(audit_layout1,remove_dir)7266 TEST_F(audit_layout1, remove_dir)
7267 {
7268 	struct audit_records records;
7269 
7270 	EXPECT_EQ(0, unlink(file1_s1d3));
7271 	EXPECT_EQ(0, unlink(file2_s1d3));
7272 
7273 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7274 					      .handled_access_fs = access_fs_16,
7275 				      });
7276 
7277 	EXPECT_EQ(-1, rmdir(dir_s1d3));
7278 	EXPECT_EQ(EACCES, errno);
7279 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7280 				    "fs\\.remove_dir", dir_s1d2));
7281 
7282 	EXPECT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
7283 	EXPECT_EQ(EACCES, errno);
7284 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7285 				    "fs\\.remove_dir", dir_s1d2));
7286 
7287 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7288 	EXPECT_EQ(0, records.access);
7289 	EXPECT_EQ(0, records.domain);
7290 }
7291 
TEST_F(audit_layout1,remove_file)7292 TEST_F(audit_layout1, remove_file)
7293 {
7294 	struct audit_records records;
7295 
7296 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7297 					      .handled_access_fs = access_fs_16,
7298 				      });
7299 
7300 	EXPECT_EQ(-1, unlink(file1_s1d3));
7301 	EXPECT_EQ(EACCES, errno);
7302 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7303 				    "fs\\.remove_file", dir_s1d3));
7304 
7305 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7306 	EXPECT_EQ(0, records.access);
7307 	EXPECT_EQ(1, records.domain);
7308 }
7309 
TEST_F(audit_layout1,make_char)7310 TEST_F(audit_layout1, make_char)
7311 {
7312 	struct audit_records records;
7313 
7314 	EXPECT_EQ(0, unlink(file1_s1d3));
7315 
7316 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7317 					      .handled_access_fs = access_fs_16,
7318 				      });
7319 
7320 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0));
7321 	EXPECT_EQ(EACCES, errno);
7322 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char",
7323 				    dir_s1d3));
7324 
7325 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7326 	EXPECT_EQ(0, records.access);
7327 	EXPECT_EQ(1, records.domain);
7328 }
7329 
TEST_F(audit_layout1,make_dir)7330 TEST_F(audit_layout1, make_dir)
7331 {
7332 	struct audit_records records;
7333 
7334 	EXPECT_EQ(0, unlink(file1_s1d3));
7335 
7336 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7337 					      .handled_access_fs = access_fs_16,
7338 				      });
7339 
7340 	EXPECT_EQ(-1, mkdir(file1_s1d3, 0755));
7341 	EXPECT_EQ(EACCES, errno);
7342 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_dir",
7343 				    dir_s1d3));
7344 
7345 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7346 	EXPECT_EQ(0, records.access);
7347 	EXPECT_EQ(1, records.domain);
7348 }
7349 
TEST_F(audit_layout1,make_reg)7350 TEST_F(audit_layout1, make_reg)
7351 {
7352 	struct audit_records records;
7353 
7354 	EXPECT_EQ(0, unlink(file1_s1d3));
7355 
7356 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7357 					      .handled_access_fs = access_fs_16,
7358 				      });
7359 
7360 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFREG | 0644, 0));
7361 	EXPECT_EQ(EACCES, errno);
7362 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_reg",
7363 				    dir_s1d3));
7364 
7365 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7366 	EXPECT_EQ(0, records.access);
7367 	EXPECT_EQ(1, records.domain);
7368 }
7369 
TEST_F(audit_layout1,make_sock)7370 TEST_F(audit_layout1, make_sock)
7371 {
7372 	struct audit_records records;
7373 
7374 	EXPECT_EQ(0, unlink(file1_s1d3));
7375 
7376 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7377 					      .handled_access_fs = access_fs_16,
7378 				      });
7379 
7380 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFSOCK | 0644, 0));
7381 	EXPECT_EQ(EACCES, errno);
7382 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sock",
7383 				    dir_s1d3));
7384 
7385 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7386 	EXPECT_EQ(0, records.access);
7387 	EXPECT_EQ(1, records.domain);
7388 }
7389 
TEST_F(audit_layout1,make_fifo)7390 TEST_F(audit_layout1, make_fifo)
7391 {
7392 	struct audit_records records;
7393 
7394 	EXPECT_EQ(0, unlink(file1_s1d3));
7395 
7396 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7397 					      .handled_access_fs = access_fs_16,
7398 				      });
7399 
7400 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFIFO | 0644, 0));
7401 	EXPECT_EQ(EACCES, errno);
7402 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_fifo",
7403 				    dir_s1d3));
7404 
7405 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7406 	EXPECT_EQ(0, records.access);
7407 	EXPECT_EQ(1, records.domain);
7408 }
7409 
TEST_F(audit_layout1,make_block)7410 TEST_F(audit_layout1, make_block)
7411 {
7412 	struct audit_records records;
7413 
7414 	EXPECT_EQ(0, unlink(file1_s1d3));
7415 
7416 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7417 					      .handled_access_fs = access_fs_16,
7418 				      });
7419 
7420 	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFBLK | 0644, 0));
7421 	EXPECT_EQ(EACCES, errno);
7422 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7423 				    "fs\\.make_block", dir_s1d3));
7424 
7425 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7426 	EXPECT_EQ(0, records.access);
7427 	EXPECT_EQ(1, records.domain);
7428 }
7429 
TEST_F(audit_layout1,make_sym)7430 TEST_F(audit_layout1, make_sym)
7431 {
7432 	struct audit_records records;
7433 
7434 	EXPECT_EQ(0, unlink(file1_s1d3));
7435 
7436 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7437 					      .handled_access_fs = access_fs_16,
7438 				      });
7439 
7440 	EXPECT_EQ(-1, symlink("target", file1_s1d3));
7441 	EXPECT_EQ(EACCES, errno);
7442 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sym",
7443 				    dir_s1d3));
7444 
7445 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7446 	EXPECT_EQ(0, records.access);
7447 	EXPECT_EQ(1, records.domain);
7448 }
7449 
TEST_F(audit_layout1,refer_handled)7450 TEST_F(audit_layout1, refer_handled)
7451 {
7452 	struct audit_records records;
7453 
7454 	EXPECT_EQ(0, unlink(file1_s1d3));
7455 
7456 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7457 					      .handled_access_fs =
7458 						      LANDLOCK_ACCESS_FS_REFER,
7459 				      });
7460 
7461 	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
7462 	EXPECT_EQ(EXDEV, errno);
7463 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7464 				    dir_s1d1));
7465 	EXPECT_EQ(0,
7466 		  matches_log_domain_allocated(self->audit_fd, getpid(), NULL));
7467 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7468 				    dir_s1d3));
7469 
7470 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7471 	EXPECT_EQ(0, records.access);
7472 	EXPECT_EQ(0, records.domain);
7473 }
7474 
TEST_F(audit_layout1,refer_make)7475 TEST_F(audit_layout1, refer_make)
7476 {
7477 	struct audit_records records;
7478 
7479 	EXPECT_EQ(0, unlink(file1_s1d3));
7480 
7481 	drop_access_rights(_metadata,
7482 			   &(struct landlock_ruleset_attr){
7483 				   .handled_access_fs =
7484 					   LANDLOCK_ACCESS_FS_MAKE_REG |
7485 					   LANDLOCK_ACCESS_FS_REFER,
7486 			   });
7487 
7488 	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
7489 	EXPECT_EQ(EACCES, errno);
7490 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7491 				    dir_s1d1));
7492 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7493 				    "fs\\.make_reg,fs\\.refer", dir_s1d3));
7494 
7495 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7496 	EXPECT_EQ(0, records.access);
7497 	EXPECT_EQ(0, records.domain);
7498 }
7499 
TEST_F(audit_layout1,refer_rename)7500 TEST_F(audit_layout1, refer_rename)
7501 {
7502 	struct audit_records records;
7503 
7504 	EXPECT_EQ(0, unlink(file1_s1d3));
7505 
7506 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7507 					      .handled_access_fs = access_fs_16,
7508 				      });
7509 
7510 	EXPECT_EQ(EACCES, test_rename(file1_s1d2, file1_s2d3));
7511 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7512 				    "fs\\.remove_file,fs\\.refer", dir_s1d2));
7513 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7514 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7515 				    dir_s2d3));
7516 
7517 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7518 	EXPECT_EQ(0, records.access);
7519 	EXPECT_EQ(0, records.domain);
7520 }
7521 
TEST_F(audit_layout1,refer_exchange)7522 TEST_F(audit_layout1, refer_exchange)
7523 {
7524 	struct audit_records records;
7525 
7526 	EXPECT_EQ(0, unlink(file1_s1d3));
7527 
7528 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7529 					      .handled_access_fs = access_fs_16,
7530 				      });
7531 
7532 	/*
7533 	 * The only difference with the previous audit_layout1.refer_rename test is
7534 	 * the extra ",fs\\.make_reg" blocked by the source directory.
7535 	 */
7536 	EXPECT_EQ(EACCES, test_exchange(file1_s1d2, file1_s2d3));
7537 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7538 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7539 				    dir_s1d2));
7540 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7541 				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7542 				    dir_s2d3));
7543 
7544 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7545 	EXPECT_EQ(0, records.access);
7546 	EXPECT_EQ(0, records.domain);
7547 }
7548 
7549 /*
7550  * This test checks that the audit record is correctly generated when the
7551  * operation is only partially denied.  This is the case for rename(2) when the
7552  * source file is allowed to be referenced but the destination directory is not.
7553  *
7554  * This is also a regression test for commit d617f0d72d80 ("landlock: Optimize
7555  * file path walks and prepare for audit support") and commit 058518c20920
7556  * ("landlock: Align partial refer access checks with final ones").
7557  */
TEST_F(audit_layout1,refer_rename_half)7558 TEST_F(audit_layout1, refer_rename_half)
7559 {
7560 	struct audit_records records;
7561 	const struct rule layer1[] = {
7562 		{
7563 			.path = dir_s2d2,
7564 			.access = LANDLOCK_ACCESS_FS_REFER,
7565 		},
7566 		{},
7567 	};
7568 	int ruleset_fd =
7569 		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
7570 
7571 	ASSERT_LE(0, ruleset_fd);
7572 	enforce_ruleset(_metadata, ruleset_fd);
7573 	ASSERT_EQ(0, close(ruleset_fd));
7574 
7575 	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
7576 	ASSERT_EQ(EXDEV, errno);
7577 
7578 	/* Only half of the request is denied. */
7579 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7580 				    dir_s1d1));
7581 
7582 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7583 	EXPECT_EQ(0, records.access);
7584 	EXPECT_EQ(1, records.domain);
7585 }
7586 
TEST_F(audit_layout1,truncate)7587 TEST_F(audit_layout1, truncate)
7588 {
7589 	struct audit_records records;
7590 
7591 	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7592 					      .handled_access_fs = access_fs_16,
7593 				      });
7594 
7595 	EXPECT_EQ(-1, truncate(file1_s1d3, 0));
7596 	EXPECT_EQ(EACCES, errno);
7597 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.truncate",
7598 				    file1_s1d3));
7599 
7600 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7601 	EXPECT_EQ(0, records.access);
7602 	EXPECT_EQ(1, records.domain);
7603 }
7604 
TEST_F(audit_layout1,ioctl_dev)7605 TEST_F(audit_layout1, ioctl_dev)
7606 {
7607 	struct audit_records records;
7608 	int fd;
7609 
7610 	drop_access_rights(_metadata,
7611 			   &(struct landlock_ruleset_attr){
7612 				   .handled_access_fs =
7613 					   access_fs_16 &
7614 					   ~LANDLOCK_ACCESS_FS_READ_FILE,
7615 			   });
7616 
7617 	fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
7618 	ASSERT_LE(0, fd);
7619 	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
7620 	EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd,
7621 					  "fs\\.ioctl_dev", "/dev/null",
7622 					  " ioctlcmd=0x541b"));
7623 
7624 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7625 	EXPECT_EQ(0, records.access);
7626 	EXPECT_EQ(1, records.domain);
7627 }
7628 
TEST_F(audit_layout1,mount)7629 TEST_F(audit_layout1, mount)
7630 {
7631 	struct audit_records records;
7632 
7633 	drop_access_rights(_metadata,
7634 			   &(struct landlock_ruleset_attr){
7635 				   .handled_access_fs =
7636 					   LANDLOCK_ACCESS_FS_EXECUTE,
7637 			   });
7638 
7639 	set_cap(_metadata, CAP_SYS_ADMIN);
7640 	EXPECT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
7641 	EXPECT_EQ(EPERM, errno);
7642 	clear_cap(_metadata, CAP_SYS_ADMIN);
7643 	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7644 				    "fs\\.change_topology", dir_s3d2));
7645 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7646 	EXPECT_EQ(0, records.access);
7647 	EXPECT_EQ(1, records.domain);
7648 }
7649 
7650 TEST_HARNESS_MAIN
7651