File Index
Files and directories
Sign in
FILE

fs_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/landlock/fs_test.c C
   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
  48int 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
  57int open_tree(int dfd, const char *filename, unsigned int flags)
  58{
  59	return syscall(__NR_open_tree, dfd, filename, flags);
  60}
  61#endif
  62
  63static 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
  73static const char bin_true[] = "./true";
  74
  75/* Paths (sibling number and depth) */
  76static const char dir_s1d1[] = TMP_DIR "/s1d1";
  77static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
  78static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
  79static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
  80static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
  81static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
  82static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
  83static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
  84static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
  85
  86static const char dir_s2d1[] = TMP_DIR "/s2d1";
  87static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
  88static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
  89static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
  90static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
  91static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
  92static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
  93
  94static const char dir_s3d1[] = TMP_DIR "/s3d1";
  95static const char file1_s3d1[] = TMP_DIR "/s3d1/f1";
  96/* dir_s3d2 is a mount point. */
  97static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
  98static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
  99static const char file1_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3/f1";
 100static const char dir_s3d4[] = TMP_DIR "/s3d1/s3d2/s3d4";
 101static 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
 132static 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
 149static 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
 174out:
 175	fclose(inf);
 176	return res;
 177}
 178
 179static 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
 192static 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
 218static 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
 229static 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
 240static 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
 269out:
 270	free(walker);
 271	return err;
 272}
 273
 274struct 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
 283static const struct mnt_opt mnt_tmp = {
 284	.type = "tmpfs",
 285	.data = MNT_TMP_DATA,
 286};
 287
 288static 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
 294static 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
 323static void prepare_layout(struct __test_metadata *const _metadata)
 324{
 325	prepare_layout_opt(_metadata, &mnt_tmp);
 326}
 327
 328static 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 */
 345FIXTURE(layout0) {};
 346/* clang-format on */
 347
 348FIXTURE_SETUP(layout0)
 349{
 350	prepare_layout(_metadata);
 351}
 352
 353FIXTURE_TEARDOWN_PARENT(layout0)
 354{
 355	cleanup_layout(_metadata);
 356}
 357
 358static 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
 382static 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 */
 408FIXTURE(layout1) {};
 409/* clang-format on */
 410
 411FIXTURE_SETUP(layout1)
 412{
 413	prepare_layout(_metadata);
 414
 415	create_layout1(_metadata);
 416}
 417
 418FIXTURE_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 */
 429static 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
 447static int test_open(const char *const path, const int flags)
 448{
 449	return test_open_rel(AT_FDCWD, path, flags);
 450}
 451
 452TEST_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
 475TEST_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
 598TEST_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
 642TEST_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
 658TEST_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
 685TEST_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
 719static 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
 742struct 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
 759static 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
 794TEST_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
 843TEST_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
 866TEST_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
 924TEST_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
 951TEST_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
 992TEST_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
1099TEST_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
1148TEST_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
1333TEST_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
1450TEST_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
1487TEST_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
1511TEST_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
1545TEST_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
1574TEST_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 */
1607TEST_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
1637TEST_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
1657TEST_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
1685TEST_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
1708TEST_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
1742TEST_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
1769TEST_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
1801TEST_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 */
1840TEST_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
1875enum relative_access {
1876	REL_OPEN,
1877	REL_CHDIR,
1878	REL_CHROOT_ONLY,
1879	REL_CHROOT_CHDIR,
1880};
1881
1882static 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
1999TEST_F_FORK(layout1, relative_open)
2000{
2001	test_relative_path(_metadata, REL_OPEN);
2002}
2003
2004TEST_F_FORK(layout1, relative_chdir)
2005{
2006	test_relative_path(_metadata, REL_CHDIR);
2007}
2008
2009TEST_F_FORK(layout1, relative_chroot_only)
2010{
2011	test_relative_path(_metadata, REL_CHROOT_ONLY);
2012}
2013
2014TEST_F_FORK(layout1, relative_chroot_chdir)
2015{
2016	test_relative_path(_metadata, REL_CHROOT_CHDIR);
2017}
2018
2019static 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
2042static 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
2068static 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
2084TEST_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
2124TEST_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
2201TEST_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
2256static 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
2263static 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
2270static 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
2278static 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
2286TEST_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
2368TEST_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
2432TEST_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. */
2475static 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
2515const struct rule layer_dir_s1d1_refer[] = {
2516	{
2517		.path = dir_s1d1,
2518		.access = LANDLOCK_ACCESS_FS_REFER,
2519	},
2520	{},
2521};
2522
2523const 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
2532const 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 */
2546TEST_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 */
2556TEST_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 */
2567TEST_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 */
2577TEST_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 */
2586TEST_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
2620TEST_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
2658TEST_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
2735TEST_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
2880static void
2881reparent_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
2912static void
2913reparent_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
2934TEST_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
2988TEST_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
3032TEST_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
3138TEST_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
3157TEST_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
3181TEST_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
3243TEST_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
3336TEST_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
3373TEST_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
3397static 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
3451TEST_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
3459TEST_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
3467TEST_F_FORK(layout1, make_reg_1)
3468{
3469	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
3470}
3471
3472TEST_F_FORK(layout1, make_reg_2)
3473{
3474	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
3475}
3476
3477TEST_F_FORK(layout1, make_sock)
3478{
3479	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
3480}
3481
3482TEST_F_FORK(layout1, make_fifo)
3483{
3484	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
3485}
3486
3487TEST_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
3532TEST_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
3560static 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
3572TEST_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
3612TEST_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. */
3672static 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 */
3683static 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 */
3703TEST_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
3760TEST_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. */
3864static int test_ftruncate(int fd)
3865{
3866	if (ftruncate(fd, 10) < 0)
3867		return errno;
3868	return 0;
3869}
3870
3871TEST_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 */
3955FIXTURE(ftruncate) {};
3956/* clang-format on */
3957
3958FIXTURE_SETUP(ftruncate)
3959{
3960	prepare_layout(_metadata);
3961	create_file(_metadata, file1_s1d1);
3962}
3963
3964FIXTURE_TEARDOWN_PARENT(ftruncate)
3965{
3966	EXPECT_EQ(0, remove_path(file1_s1d1));
3967	cleanup_layout(_metadata);
3968}
3969
3970FIXTURE_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 */
3979FIXTURE_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 */
3988FIXTURE_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 */
3997FIXTURE_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 */
4006FIXTURE_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 */
4015FIXTURE_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
4022TEST_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
4049TEST_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. */
4112static 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
4121TEST(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
4155static 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
4164TEST_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 */
4210static 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. */
4241struct 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 */
4260TEST_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 */
4321TEST_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. */
4361TEST_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	struct sockaddr_un srv_un = {
4366		.sun_family = AF_UNIX,
4367	};
4368	struct sockaddr_un cli_un = {
4369		.sun_family = AF_UNIX,
4370	};
4371	const struct landlock_ruleset_attr attr = {
4372		.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4373	};
4374
4375	/* Sets up a server */
4376	ASSERT_EQ(0, unlink(path));
4377	srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4378	ASSERT_LE(0, srv_fd);
4379
4380	strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path));
4381	ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, sizeof(srv_un)));
4382
4383	ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */));
4384
4385	/* Enables Landlock. */
4386	ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
4387	ASSERT_LE(0, ruleset_fd);
4388	enforce_ruleset(_metadata, ruleset_fd);
4389	ASSERT_EQ(0, close(ruleset_fd));
4390
4391	/* Sets up a client connection to it */
4392	cli_fd = socket(AF_UNIX, SOCK_STREAM, 0);
4393	ASSERT_LE(0, cli_fd);
4394
4395	strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path));
4396	ASSERT_EQ(0,
4397		  connect(cli_fd, (struct sockaddr *)&cli_un, sizeof(cli_un)));
4398
4399	/* FIONREAD and other IOCTLs should not be forbidden. */
4400	EXPECT_EQ(0, test_fionread_ioctl(cli_fd));
4401
4402	EXPECT_EQ(0, close(cli_fd));
4403	EXPECT_EQ(0, close(srv_fd));
4404}
4405
4406/* clang-format off */
4407FIXTURE(ioctl) {};
4408
4409FIXTURE_SETUP(ioctl) {};
4410
4411FIXTURE_TEARDOWN(ioctl) {};
4412/* clang-format on */
4413
4414FIXTURE_VARIANT(ioctl)
4415{
4416	const __u64 handled;
4417	const __u64 allowed;
4418	const mode_t open_mode;
4419	/*
4420	 * FIONREAD is used as a characteristic device-specific IOCTL command.
4421	 * It is implemented in fs/ioctl.c for regular files,
4422	 * but we do not blanket-permit it for devices.
4423	 */
4424	const int expected_fionread_result;
4425};
4426
4427/* clang-format off */
4428FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_none) {
4429	/* clang-format on */
4430	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4431	.allowed = 0,
4432	.open_mode = O_RDWR,
4433	.expected_fionread_result = EACCES,
4434};
4435
4436/* clang-format off */
4437FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_i) {
4438	/* clang-format on */
4439	.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4440	.allowed = LANDLOCK_ACCESS_FS_IOCTL_DEV,
4441	.open_mode = O_RDWR,
4442	.expected_fionread_result = 0,
4443};
4444
4445/* clang-format off */
4446FIXTURE_VARIANT_ADD(ioctl, unhandled) {
4447	/* clang-format on */
4448	.handled = LANDLOCK_ACCESS_FS_EXECUTE,
4449	.allowed = LANDLOCK_ACCESS_FS_EXECUTE,
4450	.open_mode = O_RDWR,
4451	.expected_fionread_result = 0,
4452};
4453
4454TEST_F_FORK(ioctl, handle_dir_access_file)
4455{
4456	const int flag = 0;
4457	const struct rule rules[] = {
4458		{
4459			.path = "/dev",
4460			.access = variant->allowed,
4461		},
4462		{},
4463	};
4464	int file_fd, ruleset_fd;
4465
4466	/* Enables Landlock. */
4467	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4468	ASSERT_LE(0, ruleset_fd);
4469	enforce_ruleset(_metadata, ruleset_fd);
4470	ASSERT_EQ(0, close(ruleset_fd));
4471
4472	file_fd = open("/dev/zero", variant->open_mode);
4473	ASSERT_LE(0, file_fd);
4474
4475	/* Checks that IOCTL commands return the expected errors. */
4476	EXPECT_EQ(variant->expected_fionread_result,
4477		  test_fionread_ioctl(file_fd));
4478
4479	/* Checks that unrestrictable commands are unrestricted. */
4480	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4481	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4482	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4483	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4484	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4485
4486	ASSERT_EQ(0, close(file_fd));
4487}
4488
4489TEST_F_FORK(ioctl, handle_dir_access_dir)
4490{
4491	const int flag = 0;
4492	const struct rule rules[] = {
4493		{
4494			.path = "/dev",
4495			.access = variant->allowed,
4496		},
4497		{},
4498	};
4499	int dir_fd, ruleset_fd;
4500
4501	/* Enables Landlock. */
4502	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4503	ASSERT_LE(0, ruleset_fd);
4504	enforce_ruleset(_metadata, ruleset_fd);
4505	ASSERT_EQ(0, close(ruleset_fd));
4506
4507	/*
4508	 * Ignore variant->open_mode for this test, as we intend to open a
4509	 * directory.  If the directory can not be opened, the variant is
4510	 * infeasible to test with an opened directory.
4511	 */
4512	dir_fd = open("/dev", O_RDONLY);
4513	if (dir_fd < 0)
4514		return;
4515
4516	/*
4517	 * Checks that IOCTL commands return the expected errors.
4518	 * We do not use the expected values from the fixture here.
4519	 *
4520	 * When using IOCTL on a directory, no Landlock restrictions apply.
4521	 */
4522	EXPECT_EQ(0, test_fionread_ioctl(dir_fd));
4523
4524	/* Checks that unrestrictable commands are unrestricted. */
4525	EXPECT_EQ(0, ioctl(dir_fd, FIOCLEX));
4526	EXPECT_EQ(0, ioctl(dir_fd, FIONCLEX));
4527	EXPECT_EQ(0, ioctl(dir_fd, FIONBIO, &flag));
4528	EXPECT_EQ(0, ioctl(dir_fd, FIOASYNC, &flag));
4529	EXPECT_EQ(0, ioctl(dir_fd, FIGETBSZ, &flag));
4530
4531	ASSERT_EQ(0, close(dir_fd));
4532}
4533
4534TEST_F_FORK(ioctl, handle_file_access_file)
4535{
4536	const int flag = 0;
4537	const struct rule rules[] = {
4538		{
4539			.path = "/dev/zero",
4540			.access = variant->allowed,
4541		},
4542		{},
4543	};
4544	int file_fd, ruleset_fd;
4545
4546	/* Enables Landlock. */
4547	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
4548	ASSERT_LE(0, ruleset_fd);
4549	enforce_ruleset(_metadata, ruleset_fd);
4550	ASSERT_EQ(0, close(ruleset_fd));
4551
4552	file_fd = open("/dev/zero", variant->open_mode);
4553	ASSERT_LE(0, file_fd)
4554	{
4555		TH_LOG("Failed to open /dev/zero: %s", strerror(errno));
4556	}
4557
4558	/* Checks that IOCTL commands return the expected errors. */
4559	EXPECT_EQ(variant->expected_fionread_result,
4560		  test_fionread_ioctl(file_fd));
4561
4562	/* Checks that unrestrictable commands are unrestricted. */
4563	EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
4564	EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
4565	EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
4566	EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
4567	EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
4568
4569	ASSERT_EQ(0, close(file_fd));
4570}
4571
4572/* clang-format off */
4573FIXTURE(layout1_bind) {};
4574/* clang-format on */
4575
4576static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
4577static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
4578
4579/* Move targets for disconnected path tests. */
4580static const char dir_s4d1[] = TMP_DIR "/s4d1";
4581static const char file1_s4d1[] = TMP_DIR "/s4d1/f1";
4582static const char file2_s4d1[] = TMP_DIR "/s4d1/f2";
4583static const char dir_s4d2[] = TMP_DIR "/s4d1/s4d2";
4584static const char file1_s4d2[] = TMP_DIR "/s4d1/s4d2/f1";
4585static const char file1_name[] = "f1";
4586static const char file2_name[] = "f2";
4587
4588FIXTURE_SETUP(layout1_bind)
4589{
4590	prepare_layout(_metadata);
4591
4592	create_layout1(_metadata);
4593
4594	set_cap(_metadata, CAP_SYS_ADMIN);
4595	ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL));
4596	clear_cap(_metadata, CAP_SYS_ADMIN);
4597}
4598
4599FIXTURE_TEARDOWN_PARENT(layout1_bind)
4600{
4601	/* umount(dir_s2d2)) is handled by namespace lifetime. */
4602
4603	remove_path(file1_s4d1);
4604	remove_path(file2_s4d1);
4605
4606	remove_layout1(_metadata);
4607
4608	cleanup_layout(_metadata);
4609}
4610
4611/*
4612 * layout1_bind hierarchy:
4613 *
4614 * tmp
4615 * ├── s1d1
4616 * │   ├── f1
4617 * │   ├── f2
4618 * │   └── s1d2
4619 * │       ├── f1
4620 * │       ├── f2
4621 * │       └── s1d3 [disconnected by path_disconnected]
4622 * │           ├── f1
4623 * │           └── f2
4624 * ├── s2d1
4625 * │   ├── f1
4626 * │   └── s2d2 [bind mount from s1d2]
4627 * │       ├── f1
4628 * │       ├── f2
4629 * │       └── s1d3
4630 * │           ├── f1
4631 * │           └── f2
4632 * ├── s3d1
4633 * │   └── s3d2
4634 * │       └── s3d3
4635 * └── s4d1 [renamed from s1d3 by path_disconnected]
4636 *     ├── f1
4637 *     ├── f2
4638 *     └── s4d2
4639 *         └── f1
4640 */
4641
4642TEST_F_FORK(layout1_bind, no_restriction)
4643{
4644	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
4645	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4646	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
4647	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4648	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
4649	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4650
4651	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
4652	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
4653	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
4654	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
4655	ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY));
4656	ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY));
4657
4658	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY));
4659	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4660
4661	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
4662}
4663
4664TEST_F_FORK(layout1_bind, same_content_same_file)
4665{
4666	/*
4667	 * Sets access right on parent directories of both source and
4668	 * destination mount points.
4669	 */
4670	const struct rule layer1_parent[] = {
4671		{
4672			.path = dir_s1d1,
4673			.access = ACCESS_RO,
4674		},
4675		{
4676			.path = dir_s2d1,
4677			.access = ACCESS_RW,
4678		},
4679		{},
4680	};
4681	/*
4682	 * Sets access rights on the same bind-mounted directories.  The result
4683	 * should be ACCESS_RW for both directories, but not both hierarchies
4684	 * because of the first layer.
4685	 */
4686	const struct rule layer2_mount_point[] = {
4687		{
4688			.path = dir_s1d2,
4689			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4690		},
4691		{
4692			.path = dir_s2d2,
4693			.access = ACCESS_RW,
4694		},
4695		{},
4696	};
4697	/* Only allow read-access to the s1d3 hierarchies. */
4698	const struct rule layer3_source[] = {
4699		{
4700			.path = dir_s1d3,
4701			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4702		},
4703		{},
4704	};
4705	/* Removes all access rights. */
4706	const struct rule layer4_destination[] = {
4707		{
4708			.path = bind_file1_s1d3,
4709			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
4710		},
4711		{},
4712	};
4713	int ruleset_fd;
4714
4715	/* Sets rules for the parent directories. */
4716	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent);
4717	ASSERT_LE(0, ruleset_fd);
4718	enforce_ruleset(_metadata, ruleset_fd);
4719	ASSERT_EQ(0, close(ruleset_fd));
4720
4721	/* Checks source hierarchy. */
4722	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
4723	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4724	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4725
4726	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4727	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4728	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4729
4730	/* Checks destination hierarchy. */
4731	ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR));
4732	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4733
4734	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4735	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4736
4737	/* Sets rules for the mount points. */
4738	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point);
4739	ASSERT_LE(0, ruleset_fd);
4740	enforce_ruleset(_metadata, ruleset_fd);
4741	ASSERT_EQ(0, close(ruleset_fd));
4742
4743	/* Checks source hierarchy. */
4744	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
4745	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4746	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4747
4748	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4749	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4750	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4751
4752	/* Checks destination hierarchy. */
4753	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY));
4754	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY));
4755	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4756
4757	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4758	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4759	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4760
4761	/* Sets a (shared) rule only on the source. */
4762	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source);
4763	ASSERT_LE(0, ruleset_fd);
4764	enforce_ruleset(_metadata, ruleset_fd);
4765	ASSERT_EQ(0, close(ruleset_fd));
4766
4767	/* Checks source hierarchy. */
4768	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
4769	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4770	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4771
4772	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4773	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4774	ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
4775
4776	/* Checks destination hierarchy. */
4777	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY));
4778	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY));
4779	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4780
4781	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4782	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4783	ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4784
4785	/* Sets a (shared) rule only on the destination. */
4786	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination);
4787	ASSERT_LE(0, ruleset_fd);
4788	enforce_ruleset(_metadata, ruleset_fd);
4789	ASSERT_EQ(0, close(ruleset_fd));
4790
4791	/* Checks source hierarchy. */
4792	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
4793	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4794
4795	/* Checks destination hierarchy. */
4796	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY));
4797	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4798}
4799
4800TEST_F_FORK(layout1_bind, reparent_cross_mount)
4801{
4802	const struct rule layer1[] = {
4803		{
4804			/* dir_s2d1 is beneath the dir_s2d2 mount point. */
4805			.path = dir_s2d1,
4806			.access = LANDLOCK_ACCESS_FS_REFER,
4807		},
4808		{
4809			.path = bind_dir_s1d3,
4810			.access = LANDLOCK_ACCESS_FS_EXECUTE,
4811		},
4812		{},
4813	};
4814	int ruleset_fd = create_ruleset(
4815		_metadata,
4816		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1);
4817
4818	ASSERT_LE(0, ruleset_fd);
4819	enforce_ruleset(_metadata, ruleset_fd);
4820	ASSERT_EQ(0, close(ruleset_fd));
4821
4822	/* Checks basic denied move. */
4823	ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2));
4824	ASSERT_EQ(EXDEV, errno);
4825
4826	/* Checks real cross-mount move (Landlock is not involved). */
4827	ASSERT_EQ(-1, rename(file1_s2d1, file1_s2d2));
4828	ASSERT_EQ(EXDEV, errno);
4829
4830	/* Checks move that will give more accesses. */
4831	ASSERT_EQ(-1, rename(file1_s2d2, bind_file1_s1d3));
4832	ASSERT_EQ(EXDEV, errno);
4833
4834	/* Checks legitimate downgrade move. */
4835	ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2));
4836}
4837
4838/*
4839 * Make sure access to file through a disconnected path works as expected.
4840 * This test moves s1d3 to s4d1.
4841 */
4842TEST_F_FORK(layout1_bind, path_disconnected)
4843{
4844	const struct rule layer1_allow_all[] = {
4845		{
4846			.path = TMP_DIR,
4847			.access = ACCESS_ALL,
4848		},
4849		{},
4850	};
4851	const struct rule layer2_allow_just_f1[] = {
4852		{
4853			.path = file1_s1d3,
4854			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4855		},
4856		{},
4857	};
4858	const struct rule layer3_only_s1d2[] = {
4859		{
4860			.path = dir_s1d2,
4861			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4862		},
4863		{},
4864	};
4865
4866	/* Landlock should not deny access just because it is disconnected. */
4867	int ruleset_fd_l1 =
4868		create_ruleset(_metadata, ACCESS_ALL, layer1_allow_all);
4869
4870	/* Creates the new ruleset now before we move the dir containing the file. */
4871	int ruleset_fd_l2 =
4872		create_ruleset(_metadata, ACCESS_RW, layer2_allow_just_f1);
4873	int ruleset_fd_l3 =
4874		create_ruleset(_metadata, ACCESS_RW, layer3_only_s1d2);
4875	int bind_s1d3_fd;
4876
4877	ASSERT_LE(0, ruleset_fd_l1);
4878	ASSERT_LE(0, ruleset_fd_l2);
4879	ASSERT_LE(0, ruleset_fd_l3);
4880
4881	enforce_ruleset(_metadata, ruleset_fd_l1);
4882	EXPECT_EQ(0, close(ruleset_fd_l1));
4883
4884	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
4885	ASSERT_LE(0, bind_s1d3_fd);
4886
4887	/* Tests access is possible before we move. */
4888	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4889	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4890	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY));
4891
4892	/* Makes it disconnected. */
4893	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1))
4894	{
4895		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1,
4896		       strerror(errno));
4897	}
4898
4899	/* Tests that access is still possible. */
4900	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4901	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4902
4903	/*
4904	 * Tests that ".." is not possible (not because of Landlock, but just
4905	 * because it's disconnected).
4906	 */
4907	EXPECT_EQ(ENOENT,
4908		  test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY));
4909
4910	/* This should still work with a narrower rule. */
4911	enforce_ruleset(_metadata, ruleset_fd_l2);
4912	EXPECT_EQ(0, close(ruleset_fd_l2));
4913
4914	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY));
4915	/*
4916	 * Accessing a file through a disconnected file descriptor can still be
4917	 * allowed by a rule tied to this file, even if it is no longer visible in
4918	 * its mount point.
4919	 */
4920	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4921	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4922
4923	enforce_ruleset(_metadata, ruleset_fd_l3);
4924	EXPECT_EQ(0, close(ruleset_fd_l3));
4925
4926	EXPECT_EQ(EACCES, test_open(file1_s4d1, O_RDONLY));
4927	/*
4928	 * Accessing a file through a disconnected file descriptor can still be
4929	 * allowed by a rule tied to the original mount point, even if it is no
4930	 * longer visible in its mount point.
4931	 */
4932	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4933	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
4934}
4935
4936/*
4937 * Test that renameat with disconnected paths works under Landlock.  This test
4938 * moves s1d3 to s4d2, so that we can have a rule allowing refers on the move
4939 * target's immediate parent.
4940 */
4941TEST_F_FORK(layout1_bind, path_disconnected_rename)
4942{
4943	const struct rule layer1[] = {
4944		{
4945			.path = dir_s1d2,
4946			.access = LANDLOCK_ACCESS_FS_REFER |
4947				  LANDLOCK_ACCESS_FS_MAKE_DIR |
4948				  LANDLOCK_ACCESS_FS_REMOVE_DIR |
4949				  LANDLOCK_ACCESS_FS_MAKE_REG |
4950				  LANDLOCK_ACCESS_FS_REMOVE_FILE |
4951				  LANDLOCK_ACCESS_FS_READ_FILE,
4952		},
4953		{
4954			.path = dir_s4d1,
4955			.access = LANDLOCK_ACCESS_FS_REFER |
4956				  LANDLOCK_ACCESS_FS_MAKE_DIR |
4957				  LANDLOCK_ACCESS_FS_REMOVE_DIR |
4958				  LANDLOCK_ACCESS_FS_MAKE_REG |
4959				  LANDLOCK_ACCESS_FS_REMOVE_FILE |
4960				  LANDLOCK_ACCESS_FS_READ_FILE,
4961		},
4962		{}
4963	};
4964
4965	/* This layer only handles LANDLOCK_ACCESS_FS_READ_FILE. */
4966	const struct rule layer2_only_s1d2[] = {
4967		{
4968			.path = dir_s1d2,
4969			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4970		},
4971		{},
4972	};
4973	int ruleset_fd_l1, ruleset_fd_l2;
4974	pid_t child_pid;
4975	int bind_s1d3_fd, status;
4976
4977	ASSERT_EQ(0, mkdir(dir_s4d1, 0755))
4978	{
4979		TH_LOG("Failed to create %s: %s", dir_s4d1, strerror(errno));
4980	}
4981	ruleset_fd_l1 = create_ruleset(_metadata, ACCESS_ALL, layer1);
4982	ruleset_fd_l2 = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
4983				       layer2_only_s1d2);
4984	ASSERT_LE(0, ruleset_fd_l1);
4985	ASSERT_LE(0, ruleset_fd_l2);
4986
4987	enforce_ruleset(_metadata, ruleset_fd_l1);
4988	EXPECT_EQ(0, close(ruleset_fd_l1));
4989
4990	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
4991	ASSERT_LE(0, bind_s1d3_fd);
4992	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
4993
4994	/* Tests ENOENT priority over EACCES for disconnected directory. */
4995	EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY));
4996	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2))
4997	{
4998		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2,
4999		       strerror(errno));
5000	}
5001	EXPECT_EQ(ENOENT, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY));
5002
5003	/*
5004	 * The file is no longer under s1d2 but we should still be able to access it
5005	 * with layer 2 because its mount point is evaluated as the first valid
5006	 * directory because it was initially a parent.  Do a fork to test this so
5007	 * we don't prevent ourselves from renaming it back later.
5008	 */
5009	child_pid = fork();
5010	ASSERT_LE(0, child_pid);
5011	if (child_pid == 0) {
5012		enforce_ruleset(_metadata, ruleset_fd_l2);
5013		EXPECT_EQ(0, close(ruleset_fd_l2));
5014		EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5015		EXPECT_EQ(EACCES, test_open(file1_s4d2, O_RDONLY));
5016
5017		/*
5018		 * Tests that access widening checks indeed prevents us from renaming it
5019		 * back.
5020		 */
5021		EXPECT_EQ(-1, rename(dir_s4d2, dir_s1d3));
5022		EXPECT_EQ(EXDEV, errno);
5023
5024		/*
5025		 * Including through the now disconnected fd (but it should return
5026		 * EXDEV).
5027		 */
5028		EXPECT_EQ(-1, renameat(bind_s1d3_fd, file1_name, AT_FDCWD,
5029				       file1_s2d2));
5030		EXPECT_EQ(EXDEV, errno);
5031		_exit(_metadata->exit_code);
5032		return;
5033	}
5034
5035	EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0));
5036	EXPECT_EQ(1, WIFEXITED(status));
5037	EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
5038
5039	ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3))
5040	{
5041		TH_LOG("Failed to rename %s back to %s: %s", dir_s4d1, dir_s1d3,
5042		       strerror(errno));
5043	}
5044
5045	/* Now checks that we can access it under l2. */
5046	child_pid = fork();
5047	ASSERT_LE(0, child_pid);
5048	if (child_pid == 0) {
5049		enforce_ruleset(_metadata, ruleset_fd_l2);
5050		EXPECT_EQ(0, close(ruleset_fd_l2));
5051		EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5052		EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY));
5053		_exit(_metadata->exit_code);
5054		return;
5055	}
5056
5057	EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0));
5058	EXPECT_EQ(1, WIFEXITED(status));
5059	EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
5060
5061	/*
5062	 * Also test that we can rename via a disconnected path.  We move the
5063	 * dir back to the disconnected place first, then we rename file1 to
5064	 * file2 through our dir fd.
5065	 */
5066	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2))
5067	{
5068		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2,
5069		       strerror(errno));
5070	}
5071	ASSERT_EQ(0,
5072		  renameat(bind_s1d3_fd, file1_name, bind_s1d3_fd, file2_name))
5073	{
5074		TH_LOG("Failed to rename %s to %s within disconnected %s: %s",
5075		       file1_name, file2_name, bind_dir_s1d3, strerror(errno));
5076	}
5077	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY));
5078	ASSERT_EQ(0, renameat(bind_s1d3_fd, file2_name, AT_FDCWD, file1_s2d2))
5079	{
5080		TH_LOG("Failed to rename %s to %s through disconnected %s: %s",
5081		       file2_name, file1_s2d2, bind_dir_s1d3, strerror(errno));
5082	}
5083	EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY));
5084	EXPECT_EQ(0, test_open(file1_s1d2, O_RDONLY));
5085
5086	/* Move it back using the disconnected path as the target. */
5087	ASSERT_EQ(0, renameat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file1_name))
5088	{
5089		TH_LOG("Failed to rename %s to %s through disconnected %s: %s",
5090		       file1_s1d2, file1_name, bind_dir_s1d3, strerror(errno));
5091	}
5092
5093	/* Now make it connected again. */
5094	ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3))
5095	{
5096		TH_LOG("Failed to rename %s back to %s: %s", dir_s4d2, dir_s1d3,
5097		       strerror(errno));
5098	}
5099
5100	/* Checks again that we can access it under l2. */
5101	enforce_ruleset(_metadata, ruleset_fd_l2);
5102	EXPECT_EQ(0, close(ruleset_fd_l2));
5103	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5104	EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY));
5105}
5106
5107/*
5108 * Test that linkat(2) with disconnected paths works under Landlock. This
5109 * test moves s1d3 to s4d1.
5110 */
5111TEST_F_FORK(layout1_bind, path_disconnected_link)
5112{
5113	/* Ruleset to be applied after renaming s1d3 to s4d1. */
5114	const struct rule layer1[] = {
5115		{
5116			.path = dir_s4d1,
5117			.access = LANDLOCK_ACCESS_FS_REFER |
5118				  LANDLOCK_ACCESS_FS_READ_FILE |
5119				  LANDLOCK_ACCESS_FS_MAKE_REG |
5120				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
5121		},
5122		{
5123			.path = dir_s2d2,
5124			.access = LANDLOCK_ACCESS_FS_REFER |
5125				  LANDLOCK_ACCESS_FS_READ_FILE |
5126				  LANDLOCK_ACCESS_FS_MAKE_REG |
5127				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
5128		},
5129		{}
5130	};
5131	int ruleset_fd, bind_s1d3_fd;
5132
5133	/* Removes unneeded files created by layout1, otherwise it will EEXIST. */
5134	ASSERT_EQ(0, unlink(file1_s1d2));
5135	ASSERT_EQ(0, unlink(file2_s1d3));
5136
5137	bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC);
5138	ASSERT_LE(0, bind_s1d3_fd);
5139	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY));
5140
5141	/* Disconnects bind_s1d3_fd. */
5142	ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1))
5143	{
5144		TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1,
5145		       strerror(errno));
5146	}
5147
5148	/* Need this later to test different parent link. */
5149	ASSERT_EQ(0, mkdir(dir_s4d2, 0755))
5150	{
5151		TH_LOG("Failed to create %s: %s", dir_s4d2, strerror(errno));
5152	}
5153
5154	ruleset_fd = create_ruleset(_metadata, ACCESS_ALL, layer1);
5155	ASSERT_LE(0, ruleset_fd);
5156	enforce_ruleset(_metadata, ruleset_fd);
5157	EXPECT_EQ(0, close(ruleset_fd));
5158
5159	/* From disconnected to connected. */
5160	ASSERT_EQ(0, linkat(bind_s1d3_fd, file1_name, AT_FDCWD, file1_s2d2, 0))
5161	{
5162		TH_LOG("Failed to link %s to %s via disconnected %s: %s",
5163		       file1_name, file1_s2d2, bind_dir_s1d3, strerror(errno));
5164	}
5165
5166	/* Tests that we can access via the new link... */
5167	EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY))
5168	{
5169		TH_LOG("Failed to open newly linked %s: %s", file1_s2d2,
5170		       strerror(errno));
5171	}
5172
5173	/* ...as well as the old one. */
5174	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY))
5175	{
5176		TH_LOG("Failed to open original %s: %s", file1_s4d1,
5177		       strerror(errno));
5178	}
5179
5180	/* From connected to disconnected. */
5181	ASSERT_EQ(0, unlink(file1_s4d1));
5182	ASSERT_EQ(0, linkat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file2_name, 0))
5183	{
5184		TH_LOG("Failed to link %s to %s via disconnected %s: %s",
5185		       file1_s2d2, file2_name, bind_dir_s1d3, strerror(errno));
5186	}
5187	EXPECT_EQ(0, test_open(file2_s4d1, O_RDONLY));
5188	ASSERT_EQ(0, unlink(file1_s2d2));
5189
5190	/* From disconnected to disconnected (same parent). */
5191	ASSERT_EQ(0,
5192		  linkat(bind_s1d3_fd, file2_name, bind_s1d3_fd, file1_name, 0))
5193	{
5194		TH_LOG("Failed to link %s to %s within disconnected %s: %s",
5195		       file2_name, file1_name, bind_dir_s1d3, strerror(errno));
5196	}
5197	EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY))
5198	{
5199		TH_LOG("Failed to open newly linked %s: %s", file1_s4d1,
5200		       strerror(errno));
5201	}
5202	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY))
5203	{
5204		TH_LOG("Failed to open %s through newly created link under disconnected path: %s",
5205		       file1_name, strerror(errno));
5206	}
5207	ASSERT_EQ(0, unlink(file2_s4d1));
5208
5209	/* From disconnected to disconnected (different parent). */
5210	ASSERT_EQ(0,
5211		  linkat(bind_s1d3_fd, file1_name, bind_s1d3_fd, "s4d2/f1", 0))
5212	{
5213		TH_LOG("Failed to link %s to %s within disconnected %s: %s",
5214		       file1_name, "s4d2/f1", bind_dir_s1d3, strerror(errno));
5215	}
5216	EXPECT_EQ(0, test_open(file1_s4d2, O_RDONLY))
5217	{
5218		TH_LOG("Failed to open %s after link: %s", file1_s4d2,
5219		       strerror(errno));
5220	}
5221	EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "s4d2/f1", O_RDONLY))
5222	{
5223		TH_LOG("Failed to open %s through disconnected path after link: %s",
5224		       "s4d2/f1", strerror(errno));
5225	}
5226}
5227
5228/*
5229 * layout4_disconnected_leafs with bind mount and renames:
5230 *
5231 * tmp
5232 * ├── s1d1
5233 * │   └── s1d2 [source of the bind mount]
5234 * │       ├── s1d31
5235 * │       │   └── s1d41 [now renamed beneath s3d1]
5236 * │       │       ├── f1
5237 * │       │       └── f2
5238 * │       └── s1d32
5239 * │           └── s1d42 [now renamed beneath s4d1]
5240 * │               ├── f3
5241 * │               └── f4
5242 * ├── s2d1
5243 * │   └── s2d2 [bind mount of s1d2]
5244 * │       ├── s1d31
5245 * │       │   └── s1d41 [opened FD, now renamed beneath s3d1]
5246 * │       │       ├── f1
5247 * │       │       └── f2
5248 * │       └── s1d32
5249 * │           └── s1d42 [opened FD, now renamed beneath s4d1]
5250 * │               ├── f3
5251 * │               └── f4
5252 * ├── s3d1
5253 * │   └── s1d41 [renamed here]
5254 * │       ├── f1
5255 * │       └── f2
5256 * └── s4d1
5257 *     └── s1d42 [renamed here]
5258 *         ├── f3
5259 *         └── f4
5260 */
5261/* clang-format off */
5262FIXTURE(layout4_disconnected_leafs) {
5263	int s2d2_fd;
5264};
5265/* clang-format on */
5266
5267FIXTURE_SETUP(layout4_disconnected_leafs)
5268{
5269	prepare_layout(_metadata);
5270
5271	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1");
5272	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2");
5273	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3");
5274	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f4");
5275	create_directory(_metadata, TMP_DIR "/s2d1/s2d2");
5276	create_directory(_metadata, TMP_DIR "/s3d1");
5277	create_directory(_metadata, TMP_DIR "/s4d1");
5278
5279	self->s2d2_fd =
5280		open(TMP_DIR "/s2d1/s2d2", O_DIRECTORY | O_PATH | O_CLOEXEC);
5281	ASSERT_LE(0, self->s2d2_fd);
5282
5283	set_cap(_metadata, CAP_SYS_ADMIN);
5284	ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2", NULL,
5285			   MS_BIND, NULL));
5286	clear_cap(_metadata, CAP_SYS_ADMIN);
5287}
5288
5289FIXTURE_TEARDOWN_PARENT(layout4_disconnected_leafs)
5290{
5291	/* umount(TMP_DIR "/s2d1") is handled by namespace lifetime. */
5292
5293	/* Removes files after renames. */
5294	remove_path(TMP_DIR "/s3d1/s1d41/f1");
5295	remove_path(TMP_DIR "/s3d1/s1d41/f2");
5296	remove_path(TMP_DIR "/s4d1/s1d42/f1");
5297	remove_path(TMP_DIR "/s4d1/s1d42/f3");
5298	remove_path(TMP_DIR "/s4d1/s1d42/f4");
5299	remove_path(TMP_DIR "/s4d1/s1d42/f5");
5300
5301	cleanup_layout(_metadata);
5302}
5303
5304FIXTURE_VARIANT(layout4_disconnected_leafs)
5305{
5306	/*
5307	 * Parent of the bind mount source.  It should always be ignored when
5308	 * testing against files under the s1d41 or s1d42 disconnected directories.
5309	 */
5310	const __u64 allowed_s1d1;
5311	/*
5312	 * Source of bind mount (to s2d2).  It should always be enforced when
5313	 * testing against files under the s1d41 or s1d42 disconnected directories.
5314	 */
5315	const __u64 allowed_s1d2;
5316	/*
5317	 * Original parent of s1d41.  It should always be ignored when testing
5318	 * against files under the s1d41 disconnected directory.
5319	 */
5320	const __u64 allowed_s1d31;
5321	/*
5322	 * Original parent of s1d42.  It should always be ignored when testing
5323	 * against files under the s1d42 disconnected directory.
5324	 */
5325	const __u64 allowed_s1d32;
5326	/*
5327	 * Opened and disconnected source directory.  It should always be enforced
5328	 * when testing against files under the s1d41 disconnected directory.
5329	 */
5330	const __u64 allowed_s1d41;
5331	/*
5332	 * Opened and disconnected source directory.  It should always be enforced
5333	 * when testing against files under the s1d42 disconnected directory.
5334	 */
5335	const __u64 allowed_s1d42;
5336	/*
5337	 * File in the s1d41 disconnected directory.  It should always be enforced
5338	 * when testing against itself under the s1d41 disconnected directory.
5339	 */
5340	const __u64 allowed_f1;
5341	/*
5342	 * File in the s1d41 disconnected directory.  It should always be enforced
5343	 * when testing against itself under the s1d41 disconnected directory.
5344	 */
5345	const __u64 allowed_f2;
5346	/*
5347	 * File in the s1d42 disconnected directory.  It should always be enforced
5348	 * when testing against itself under the s1d42 disconnected directory.
5349	 */
5350	const __u64 allowed_f3;
5351	/*
5352	 * Parent of the bind mount destination.  It should always be enforced when
5353	 * testing against files under the s1d41 or s1d42 disconnected directories.
5354	 */
5355	const __u64 allowed_s2d1;
5356	/*
5357	 * Directory covered by the bind mount.  It should always be ignored when
5358	 * testing against files under the s1d41 or s1d42 disconnected directories.
5359	 */
5360	const __u64 allowed_s2d2;
5361	/*
5362	 * New parent of the renamed s1d41.  It should always be ignored when
5363	 * testing against files under the s1d41 disconnected directory.
5364	 */
5365	const __u64 allowed_s3d1;
5366	/*
5367	 * New parent of the renamed s1d42.  It should always be ignored when
5368	 * testing against files under the s1d42 disconnected directory.
5369	 */
5370	const __u64 allowed_s4d1;
5371
5372	/* Expected result of the call to open([fd:s1d41]/f1, O_RDONLY). */
5373	const int expected_read_result;
5374	/* Expected result of the call to renameat([fd:s1d41]/f1, [fd:s1d42]/f1). */
5375	const int expected_rename_result;
5376	/*
5377	 * Expected result of the call to renameat([fd:s1d41]/f2, [fd:s1d42]/f3,
5378	 * RENAME_EXCHANGE).
5379	 */
5380	const int expected_exchange_result;
5381	/* Expected result of the call to renameat([fd:s1d42]/f4, [fd:s1d42]/f5). */
5382	const int expected_same_dir_rename_result;
5383};
5384
5385/* clang-format off */
5386FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d1_mount_src_parent) {
5387	/* clang-format on */
5388	.allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER |
5389			LANDLOCK_ACCESS_FS_READ_FILE |
5390			LANDLOCK_ACCESS_FS_EXECUTE |
5391			LANDLOCK_ACCESS_FS_MAKE_REG,
5392	.expected_read_result = EACCES,
5393	.expected_same_dir_rename_result = EACCES,
5394	.expected_rename_result = EACCES,
5395	.expected_exchange_result = EACCES,
5396};
5397
5398/* clang-format off */
5399FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_refer) {
5400	/* clang-format on */
5401	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5402	.expected_read_result = 0,
5403	.expected_same_dir_rename_result = EACCES,
5404	.expected_rename_result = EACCES,
5405	.expected_exchange_result = EACCES,
5406};
5407
5408/* clang-format off */
5409FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_create) {
5410	/* clang-format on */
5411	.allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE |
5412			LANDLOCK_ACCESS_FS_MAKE_REG,
5413	.expected_read_result = 0,
5414	.expected_same_dir_rename_result = 0,
5415	.expected_rename_result = EXDEV,
5416	.expected_exchange_result = EXDEV,
5417};
5418
5419/* clang-format off */
5420FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_rename) {
5421	/* clang-format on */
5422	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5423	.expected_read_result = EACCES,
5424	.expected_same_dir_rename_result = 0,
5425	.expected_rename_result = 0,
5426	.expected_exchange_result = 0,
5427};
5428
5429/* clang-format off */
5430FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d31_s1d32_old_parent) {
5431	/* clang-format on */
5432	.allowed_s1d31 = LANDLOCK_ACCESS_FS_REFER |
5433			 LANDLOCK_ACCESS_FS_READ_FILE |
5434			 LANDLOCK_ACCESS_FS_EXECUTE |
5435			 LANDLOCK_ACCESS_FS_MAKE_REG,
5436	.allowed_s1d32 = LANDLOCK_ACCESS_FS_REFER |
5437			 LANDLOCK_ACCESS_FS_READ_FILE |
5438			 LANDLOCK_ACCESS_FS_EXECUTE |
5439			 LANDLOCK_ACCESS_FS_MAKE_REG,
5440	.expected_read_result = EACCES,
5441	.expected_same_dir_rename_result = EACCES,
5442	.expected_rename_result = EACCES,
5443	.expected_exchange_result = EACCES,
5444};
5445
5446/* clang-format off */
5447FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_refer) {
5448	/* clang-format on */
5449	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER |
5450			 LANDLOCK_ACCESS_FS_READ_FILE,
5451	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER |
5452			 LANDLOCK_ACCESS_FS_READ_FILE,
5453	.expected_read_result = 0,
5454	.expected_same_dir_rename_result = EACCES,
5455	.expected_rename_result = EACCES,
5456	.expected_exchange_result = EACCES,
5457};
5458
5459/* clang-format off */
5460FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_create) {
5461	/* clang-format on */
5462	.allowed_s1d41 = LANDLOCK_ACCESS_FS_READ_FILE |
5463			 LANDLOCK_ACCESS_FS_MAKE_REG,
5464	.allowed_s1d42 = LANDLOCK_ACCESS_FS_READ_FILE |
5465			 LANDLOCK_ACCESS_FS_MAKE_REG,
5466	.expected_read_result = 0,
5467	.expected_same_dir_rename_result = 0,
5468	.expected_rename_result = EXDEV,
5469	.expected_exchange_result = EXDEV,
5470};
5471
5472/* clang-format off */
5473FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_even) {
5474	/* clang-format on */
5475	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5476	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5477	.expected_read_result = EACCES,
5478	.expected_same_dir_rename_result = 0,
5479	.expected_rename_result = 0,
5480	.expected_exchange_result = 0,
5481};
5482
5483/* The destination directory has more access right. */
5484/* clang-format off */
5485FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_more) {
5486	/* clang-format on */
5487	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5488	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER |
5489			 LANDLOCK_ACCESS_FS_MAKE_REG |
5490			 LANDLOCK_ACCESS_FS_EXECUTE,
5491	.expected_read_result = EACCES,
5492	.expected_same_dir_rename_result = 0,
5493	/* Access denied. */
5494	.expected_rename_result = EXDEV,
5495	.expected_exchange_result = EXDEV,
5496};
5497
5498/* The destination directory has less access right. */
5499/* clang-format off */
5500FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_less) {
5501	/* clang-format on */
5502	.allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER |
5503			 LANDLOCK_ACCESS_FS_MAKE_REG |
5504			 LANDLOCK_ACCESS_FS_EXECUTE,
5505	.allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5506	.expected_read_result = EACCES,
5507	.expected_same_dir_rename_result = 0,
5508	/* Access allowed. */
5509	.expected_rename_result = 0,
5510	.expected_exchange_result = EXDEV,
5511};
5512
5513/* clang-format off */
5514FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_create) {
5515	/* clang-format on */
5516	.allowed_s2d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5517			LANDLOCK_ACCESS_FS_MAKE_REG,
5518	.expected_read_result = 0,
5519	.expected_same_dir_rename_result = 0,
5520	.expected_rename_result = EXDEV,
5521	.expected_exchange_result = EXDEV,
5522};
5523
5524/* clang-format off */
5525FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_refer) {
5526	/* clang-format on */
5527	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5528	.expected_read_result = 0,
5529	.expected_same_dir_rename_result = EACCES,
5530	.expected_rename_result = EACCES,
5531	.expected_exchange_result = EACCES,
5532};
5533
5534/* clang-format off */
5535FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_mini) {
5536	/* clang-format on */
5537	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER |
5538			LANDLOCK_ACCESS_FS_READ_FILE |
5539			LANDLOCK_ACCESS_FS_MAKE_REG,
5540	.expected_read_result = 0,
5541	.expected_same_dir_rename_result = 0,
5542	.expected_rename_result = 0,
5543	.expected_exchange_result = 0,
5544};
5545
5546/* clang-format off */
5547FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d2_covered_by_mount) {
5548	/* clang-format on */
5549	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER |
5550			LANDLOCK_ACCESS_FS_READ_FILE |
5551			LANDLOCK_ACCESS_FS_EXECUTE |
5552			LANDLOCK_ACCESS_FS_MAKE_REG,
5553	.expected_read_result = EACCES,
5554	.expected_same_dir_rename_result = EACCES,
5555	.expected_rename_result = EACCES,
5556	.expected_exchange_result = EACCES,
5557};
5558
5559/* Tests collect_domain_accesses(). */
5560/* clang-format off */
5561FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_refer) {
5562	/* clang-format on */
5563	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5564	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5565	.expected_read_result = 0,
5566	.expected_same_dir_rename_result = EACCES,
5567	.expected_rename_result = EACCES,
5568	.expected_exchange_result = EACCES,
5569};
5570
5571/* clang-format off */
5572FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_create) {
5573	/* clang-format on */
5574	.allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5575			LANDLOCK_ACCESS_FS_MAKE_REG,
5576	.allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE |
5577			LANDLOCK_ACCESS_FS_MAKE_REG,
5578	.expected_read_result = 0,
5579	.expected_same_dir_rename_result = 0,
5580	.expected_rename_result = EXDEV,
5581	.expected_exchange_result = EXDEV,
5582};
5583
5584FIXTURE_VARIANT_ADD(layout4_disconnected_leafs,
5585		    s3d1_s4d1_disconnected_rename_even){
5586	/* clang-format on */
5587	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5588	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5589	.expected_read_result = EACCES,
5590	.expected_same_dir_rename_result = 0,
5591	.expected_rename_result = 0,
5592	.expected_exchange_result = 0,
5593};
5594
5595/* The destination directory has more access right. */
5596/* clang-format off */
5597FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_more) {
5598	/* clang-format on */
5599	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5600	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG |
5601			LANDLOCK_ACCESS_FS_EXECUTE,
5602	.expected_read_result = EACCES,
5603	.expected_same_dir_rename_result = 0,
5604	/* Access denied. */
5605	.expected_rename_result = EXDEV,
5606	.expected_exchange_result = EXDEV,
5607};
5608
5609/* The destination directory has less access right. */
5610/* clang-format off */
5611FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_less) {
5612	/* clang-format on */
5613	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG |
5614			LANDLOCK_ACCESS_FS_EXECUTE,
5615	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5616	.expected_read_result = EACCES,
5617	.expected_same_dir_rename_result = 0,
5618	/* Access allowed. */
5619	.expected_rename_result = 0,
5620	.expected_exchange_result = EXDEV,
5621};
5622
5623/* clang-format off */
5624FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, f1_f2_f3) {
5625	/* clang-format on */
5626	.allowed_f1 = LANDLOCK_ACCESS_FS_READ_FILE,
5627	.allowed_f2 = LANDLOCK_ACCESS_FS_READ_FILE,
5628	.allowed_f3 = LANDLOCK_ACCESS_FS_READ_FILE,
5629	.expected_read_result = 0,
5630	.expected_same_dir_rename_result = EACCES,
5631	.expected_rename_result = EACCES,
5632	.expected_exchange_result = EACCES,
5633};
5634
5635TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange)
5636{
5637	const __u64 handled_access =
5638		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE |
5639		LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG;
5640	const struct rule rules[] = {
5641		{
5642			.path = TMP_DIR "/s1d1",
5643			.access = variant->allowed_s1d1,
5644		},
5645		{
5646			.path = TMP_DIR "/s1d1/s1d2",
5647			.access = variant->allowed_s1d2,
5648		},
5649		{
5650			.path = TMP_DIR "/s1d1/s1d2/s1d31",
5651			.access = variant->allowed_s1d31,
5652		},
5653		{
5654			.path = TMP_DIR "/s1d1/s1d2/s1d32",
5655			.access = variant->allowed_s1d32,
5656		},
5657		{
5658			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41",
5659			.access = variant->allowed_s1d41,
5660		},
5661		{
5662			.path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42",
5663			.access = variant->allowed_s1d42,
5664		},
5665		{
5666			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1",
5667			.access = variant->allowed_f1,
5668		},
5669		{
5670			.path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2",
5671			.access = variant->allowed_f2,
5672		},
5673		{
5674			.path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3",
5675			.access = variant->allowed_f3,
5676		},
5677		{
5678			.path = TMP_DIR "/s2d1",
5679			.access = variant->allowed_s2d1,
5680		},
5681		/* s2d2_fd */
5682		{
5683			.path = TMP_DIR "/s3d1",
5684			.access = variant->allowed_s3d1,
5685		},
5686		{
5687			.path = TMP_DIR "/s4d1",
5688			.access = variant->allowed_s4d1,
5689		},
5690		{},
5691	};
5692	int ruleset_fd, s1d41_bind_fd, s1d42_bind_fd;
5693
5694	ruleset_fd = create_ruleset(_metadata, handled_access, rules);
5695	ASSERT_LE(0, ruleset_fd);
5696
5697	/* Adds rule for the covered directory. */
5698	if (variant->allowed_s2d2) {
5699		ASSERT_EQ(0, landlock_add_rule(
5700				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
5701				     &(struct landlock_path_beneath_attr){
5702					     .parent_fd = self->s2d2_fd,
5703					     .allowed_access =
5704						     variant->allowed_s2d2,
5705				     },
5706				     0));
5707	}
5708	EXPECT_EQ(0, close(self->s2d2_fd));
5709
5710	s1d41_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d31/s1d41",
5711			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5712	ASSERT_LE(0, s1d41_bind_fd);
5713	s1d42_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d32/s1d42",
5714			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5715	ASSERT_LE(0, s1d42_bind_fd);
5716
5717	/* Disconnects and checks source and destination directories. */
5718	EXPECT_EQ(0, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY));
5719	EXPECT_EQ(0, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY));
5720	/* Renames to make it accessible through s3d1/s1d41 */
5721	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d31/s1d41",
5722				   AT_FDCWD, TMP_DIR "/s3d1/s1d41"));
5723	/* Renames to make it accessible through s4d1/s1d42 */
5724	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d32/s1d42",
5725				   AT_FDCWD, TMP_DIR "/s4d1/s1d42"));
5726	EXPECT_EQ(ENOENT, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY));
5727	EXPECT_EQ(ENOENT, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY));
5728
5729	enforce_ruleset(_metadata, ruleset_fd);
5730	EXPECT_EQ(0, close(ruleset_fd));
5731
5732	EXPECT_EQ(variant->expected_read_result,
5733		  test_open_rel(s1d41_bind_fd, "f1", O_RDONLY));
5734
5735	EXPECT_EQ(variant->expected_rename_result,
5736		  test_renameat(s1d41_bind_fd, "f1", s1d42_bind_fd, "f1"));
5737	EXPECT_EQ(variant->expected_exchange_result,
5738		  test_exchangeat(s1d41_bind_fd, "f2", s1d42_bind_fd, "f3"));
5739
5740	EXPECT_EQ(variant->expected_same_dir_rename_result,
5741		  test_renameat(s1d42_bind_fd, "f4", s1d42_bind_fd, "f5"));
5742}
5743
5744/*
5745 * layout5_disconnected_branch before rename:
5746 *
5747 * tmp
5748 * ├── s1d1
5749 * │   └── s1d2 [source of the first bind mount]
5750 * │       └── s1d3
5751 * │           ├── s1d41
5752 * │           │   ├── f1
5753 * │           │   └── f2
5754 * │           └── s1d42
5755 * │               ├── f3
5756 * │               └── f4
5757 * ├── s2d1
5758 * │   └── s2d2 [source of the second bind mount]
5759 * │       └── s2d3
5760 * │           └── s2d4 [first s1d2 bind mount]
5761 * │               └── s1d3
5762 * │                   ├── s1d41
5763 * │                   │   ├── f1
5764 * │                   │   └── f2
5765 * │                   └── s1d42
5766 * │                       ├── f3
5767 * │                       └── f4
5768 * ├── s3d1
5769 * │   └── s3d2 [second s2d2 bind mount]
5770 * │       └── s2d3
5771 * │           └── s2d4 [first s1d2 bind mount]
5772 * │               └── s1d3
5773 * │                   ├── s1d41
5774 * │                   │   ├── f1
5775 * │                   │   └── f2
5776 * │                   └── s1d42
5777 * │                       ├── f3
5778 * │                       └── f4
5779 * └── s4d1
5780 *
5781 * After rename:
5782 *
5783 * tmp
5784 * ├── s1d1
5785 * │   └── s1d2 [source of the first bind mount]
5786 * │       └── s1d3
5787 * │           ├── s1d41
5788 * │           │   ├── f1
5789 * │           │   └── f2
5790 * │           └── s1d42
5791 * │               ├── f3
5792 * │               └── f4
5793 * ├── s2d1
5794 * │   └── s2d2 [source of the second bind mount]
5795 * ├── s3d1
5796 * │   └── s3d2 [second s2d2 bind mount]
5797 * └── s4d1
5798 *     └── s2d3 [renamed here]
5799 *         └── s2d4 [first s1d2 bind mount]
5800 *             └── s1d3
5801 *                 ├── s1d41
5802 *                 │   ├── f1
5803 *                 │   └── f2
5804 *                 └── s1d42
5805 *                     ├── f3
5806 *                     └── f4
5807 *
5808 * Decision path for access from the s3d1/s3d2/s2d3/s2d4/s1d3 file descriptor:
5809 *   1. first bind mount:   s1d3 -> s1d2
5810 *   2. second bind mount:    s2d3
5811 *   3. tmp mount:              s4d1 -> tmp [disconnected branch]
5812 *   4. second bind mount:        s2d2
5813 *   5. tmp mount:                  s3d1 -> tmp
5814 *   6. parent mounts:                [...] -> /
5815 *
5816 * The s4d1 directory is evaluated even if it is not in the s2d2 mount.
5817 */
5818
5819/* clang-format off */
5820FIXTURE(layout5_disconnected_branch) {
5821	int s2d4_fd, s3d2_fd;
5822};
5823/* clang-format on */
5824
5825FIXTURE_SETUP(layout5_disconnected_branch)
5826{
5827	prepare_layout(_metadata);
5828
5829	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1");
5830	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2");
5831	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3");
5832	create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4");
5833	create_directory(_metadata, TMP_DIR "/s2d1/s2d2/s2d3/s2d4");
5834	create_directory(_metadata, TMP_DIR "/s3d1/s3d2");
5835	create_directory(_metadata, TMP_DIR "/s4d1");
5836
5837	self->s2d4_fd = open(TMP_DIR "/s2d1/s2d2/s2d3/s2d4",
5838			     O_DIRECTORY | O_PATH | O_CLOEXEC);
5839	ASSERT_LE(0, self->s2d4_fd);
5840
5841	self->s3d2_fd =
5842		open(TMP_DIR "/s3d1/s3d2", O_DIRECTORY | O_PATH | O_CLOEXEC);
5843	ASSERT_LE(0, self->s3d2_fd);
5844
5845	set_cap(_metadata, CAP_SYS_ADMIN);
5846	ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2/s2d3/s2d4",
5847			   NULL, MS_BIND, NULL));
5848	ASSERT_EQ(0, mount(TMP_DIR "/s2d1/s2d2", TMP_DIR "/s3d1/s3d2", NULL,
5849			   MS_BIND | MS_REC, NULL));
5850	clear_cap(_metadata, CAP_SYS_ADMIN);
5851}
5852
5853FIXTURE_TEARDOWN_PARENT(layout5_disconnected_branch)
5854{
5855	/* Bind mounts are handled by namespace lifetime. */
5856
5857	/* Removes files after renames. */
5858	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1");
5859	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2");
5860	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f1");
5861	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3");
5862	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4");
5863	remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f5");
5864
5865	cleanup_layout(_metadata);
5866}
5867
5868FIXTURE_VARIANT(layout5_disconnected_branch)
5869{
5870	/*
5871	 * Parent of all files.  It should always be enforced when testing against
5872	 * files under the s1d41 or s1d42 disconnected directories.
5873	 */
5874	const __u64 allowed_base;
5875	/*
5876	 * Parent of the first bind mount source.  It should always be ignored when
5877	 * testing against files under the s1d41 or s1d42 disconnected directories.
5878	 */
5879	const __u64 allowed_s1d1;
5880	const __u64 allowed_s1d2;
5881	const __u64 allowed_s1d3;
5882	const __u64 allowed_s2d1;
5883	const __u64 allowed_s2d2;
5884	const __u64 allowed_s2d3;
5885	const __u64 allowed_s2d4;
5886	const __u64 allowed_s3d1;
5887	const __u64 allowed_s3d2;
5888	const __u64 allowed_s4d1;
5889
5890	/* Expected result of the call to open([fd:s1d3]/s1d41/f1, O_RDONLY). */
5891	const int expected_read_result;
5892	/*
5893	 * Expected result of the call to renameat([fd:s1d3]/s1d41/f1,
5894	 * [fd:s1d3]/s1d42/f1).
5895	 */
5896	const int expected_rename_result;
5897	/*
5898	 * Expected result of the call to renameat([fd:s1d3]/s1d41/f2,
5899	 * [fd:s1d3]/s1d42/f3,  RENAME_EXCHANGE).
5900	 */
5901	const int expected_exchange_result;
5902	/*
5903	 * Expected result of the call to renameat([fd:s1d3]/s1d42/f4,
5904	 * [fd:s1d3]/s1d42/f5).
5905	 */
5906	const int expected_same_dir_rename_result;
5907};
5908
5909/* clang-format off */
5910FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d1_mount1_src_parent) {
5911	/* clang-format on */
5912	.allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER |
5913			LANDLOCK_ACCESS_FS_READ_FILE |
5914			LANDLOCK_ACCESS_FS_EXECUTE |
5915			LANDLOCK_ACCESS_FS_MAKE_REG,
5916	.expected_read_result = EACCES,
5917	.expected_same_dir_rename_result = EACCES,
5918	.expected_rename_result = EACCES,
5919	.expected_exchange_result = EACCES,
5920};
5921
5922/* clang-format off */
5923FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_refer) {
5924	/* clang-format on */
5925	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5926	.expected_read_result = 0,
5927	.expected_same_dir_rename_result = EACCES,
5928	.expected_rename_result = EACCES,
5929	.expected_exchange_result = EACCES,
5930};
5931
5932/* clang-format off */
5933FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_create) {
5934	/* clang-format on */
5935	.allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE |
5936			LANDLOCK_ACCESS_FS_MAKE_REG,
5937	.expected_read_result = 0,
5938	.expected_same_dir_rename_result = 0,
5939	.expected_rename_result = EXDEV,
5940	.expected_exchange_result = EXDEV,
5941};
5942
5943/* clang-format off */
5944FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_rename) {
5945	/* clang-format on */
5946	.allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5947	.expected_read_result = EACCES,
5948	.expected_same_dir_rename_result = 0,
5949	.expected_rename_result = 0,
5950	.expected_exchange_result = 0,
5951};
5952
5953/* clang-format off */
5954FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_refer) {
5955	/* clang-format on */
5956	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
5957	.expected_read_result = 0,
5958	.expected_same_dir_rename_result = EACCES,
5959	.expected_rename_result = EACCES,
5960	.expected_exchange_result = EACCES,
5961};
5962
5963/* clang-format off */
5964FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_create) {
5965	/* clang-format on */
5966	.allowed_s1d3 = LANDLOCK_ACCESS_FS_READ_FILE |
5967			LANDLOCK_ACCESS_FS_MAKE_REG,
5968	.expected_read_result = 0,
5969	.expected_same_dir_rename_result = 0,
5970	.expected_rename_result = EXDEV,
5971	.expected_exchange_result = EXDEV,
5972};
5973
5974/* clang-format off */
5975FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_rename) {
5976	/* clang-format on */
5977	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
5978	.expected_read_result = EACCES,
5979	.expected_same_dir_rename_result = 0,
5980	.expected_rename_result = 0,
5981	.expected_exchange_result = 0,
5982};
5983
5984/* clang-format off */
5985FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_full) {
5986	/* clang-format on */
5987	.allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER |
5988			LANDLOCK_ACCESS_FS_READ_FILE |
5989			LANDLOCK_ACCESS_FS_EXECUTE |
5990			LANDLOCK_ACCESS_FS_MAKE_REG,
5991	.expected_read_result = 0,
5992	.expected_same_dir_rename_result = 0,
5993	.expected_rename_result = 0,
5994	.expected_exchange_result = 0,
5995};
5996
5997/* clang-format off */
5998FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d1_mount2_src_parent) {
5999	/* clang-format on */
6000	.allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER |
6001			LANDLOCK_ACCESS_FS_READ_FILE |
6002			LANDLOCK_ACCESS_FS_EXECUTE |
6003			LANDLOCK_ACCESS_FS_MAKE_REG,
6004	.expected_read_result = EACCES,
6005	.expected_same_dir_rename_result = EACCES,
6006	.expected_rename_result = EACCES,
6007	.expected_exchange_result = EACCES,
6008};
6009
6010/* clang-format off */
6011FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_refer) {
6012	/* clang-format on */
6013	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6014	.expected_read_result = 0,
6015	.expected_same_dir_rename_result = EACCES,
6016	.expected_rename_result = EACCES,
6017	.expected_exchange_result = EACCES,
6018};
6019
6020/* clang-format off */
6021FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_create) {
6022	/* clang-format on */
6023	.allowed_s2d2 = LANDLOCK_ACCESS_FS_READ_FILE |
6024			LANDLOCK_ACCESS_FS_MAKE_REG,
6025	.expected_read_result = 0,
6026	.expected_same_dir_rename_result = 0,
6027	.expected_rename_result = EXDEV,
6028	.expected_exchange_result = EXDEV,
6029};
6030
6031/* clang-format off */
6032FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_rename) {
6033	/* clang-format on */
6034	.allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6035	.expected_read_result = EACCES,
6036	.expected_same_dir_rename_result = 0,
6037	.expected_rename_result = 0,
6038	.expected_exchange_result = 0,
6039};
6040
6041/* clang-format off */
6042FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_refer) {
6043	/* clang-format on */
6044	.allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6045	.expected_read_result = 0,
6046	.expected_same_dir_rename_result = EACCES,
6047	.expected_rename_result = EACCES,
6048	.expected_exchange_result = EACCES,
6049};
6050
6051/* clang-format off */
6052FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_create) {
6053	/* clang-format on */
6054	.allowed_s2d3 = LANDLOCK_ACCESS_FS_READ_FILE |
6055			LANDLOCK_ACCESS_FS_MAKE_REG,
6056	.expected_read_result = 0,
6057	.expected_same_dir_rename_result = 0,
6058	.expected_rename_result = EXDEV,
6059	.expected_exchange_result = EXDEV,
6060};
6061
6062/* clang-format off */
6063FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_rename) {
6064	/* clang-format on */
6065	.allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6066	.expected_read_result = EACCES,
6067	.expected_same_dir_rename_result = 0,
6068	.expected_rename_result = 0,
6069	.expected_exchange_result = 0,
6070};
6071
6072/* clang-format off */
6073FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d4_mount1_dst) {
6074	/* clang-format on */
6075	.allowed_s2d4 = LANDLOCK_ACCESS_FS_REFER |
6076			LANDLOCK_ACCESS_FS_READ_FILE |
6077			LANDLOCK_ACCESS_FS_EXECUTE |
6078			LANDLOCK_ACCESS_FS_MAKE_REG,
6079	.expected_read_result = EACCES,
6080	.expected_same_dir_rename_result = EACCES,
6081	.expected_rename_result = EACCES,
6082	.expected_exchange_result = EACCES,
6083};
6084
6085/* clang-format off */
6086FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_refer) {
6087	/* clang-format on */
6088	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6089	.expected_read_result = 0,
6090	.expected_same_dir_rename_result = EACCES,
6091	.expected_rename_result = EACCES,
6092	.expected_exchange_result = EACCES,
6093};
6094
6095/* clang-format off */
6096FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_create) {
6097	/* clang-format on */
6098	.allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE |
6099			LANDLOCK_ACCESS_FS_MAKE_REG,
6100	.expected_read_result = 0,
6101	.expected_same_dir_rename_result = 0,
6102	.expected_rename_result = EXDEV,
6103	.expected_exchange_result = EXDEV,
6104};
6105
6106/* clang-format off */
6107FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_rename) {
6108	/* clang-format on */
6109	.allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6110	.expected_read_result = EACCES,
6111	.expected_same_dir_rename_result = 0,
6112	.expected_rename_result = 0,
6113	.expected_exchange_result = 0,
6114};
6115
6116/* clang-format off */
6117FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d2_mount1_dst) {
6118	/* clang-format on */
6119	.allowed_s3d2 = LANDLOCK_ACCESS_FS_REFER |
6120			LANDLOCK_ACCESS_FS_READ_FILE |
6121			LANDLOCK_ACCESS_FS_EXECUTE |
6122			LANDLOCK_ACCESS_FS_MAKE_REG,
6123	.expected_read_result = EACCES,
6124	.expected_same_dir_rename_result = EACCES,
6125	.expected_rename_result = EACCES,
6126	.expected_exchange_result = EACCES,
6127};
6128
6129/* clang-format off */
6130FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_refer) {
6131	/* clang-format on */
6132	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE,
6133	.expected_read_result = 0,
6134	.expected_same_dir_rename_result = EACCES,
6135	.expected_rename_result = EACCES,
6136	.expected_exchange_result = EACCES,
6137};
6138
6139/* clang-format off */
6140FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_create) {
6141	/* clang-format on */
6142	.allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE |
6143			LANDLOCK_ACCESS_FS_MAKE_REG,
6144	.expected_read_result = 0,
6145	.expected_same_dir_rename_result = 0,
6146	.expected_rename_result = EXDEV,
6147	.expected_exchange_result = EXDEV,
6148};
6149
6150/* clang-format off */
6151FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_rename) {
6152	/* clang-format on */
6153	.allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG,
6154	.expected_read_result = EACCES,
6155	.expected_same_dir_rename_result = 0,
6156	.expected_rename_result = 0,
6157	.expected_exchange_result = 0,
6158};
6159
6160TEST_F_FORK(layout5_disconnected_branch, read_rename_exchange)
6161{
6162	const __u64 handled_access =
6163		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE |
6164		LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG;
6165	const struct rule rules[] = {
6166		{
6167			.path = TMP_DIR "/s1d1",
6168			.access = variant->allowed_s1d1,
6169		},
6170		{
6171			.path = TMP_DIR "/s1d1/s1d2",
6172			.access = variant->allowed_s1d2,
6173		},
6174		{
6175			.path = TMP_DIR "/s1d1/s1d2/s1d3",
6176			.access = variant->allowed_s1d3,
6177		},
6178		{
6179			.path = TMP_DIR "/s2d1",
6180			.access = variant->allowed_s2d1,
6181		},
6182		{
6183			.path = TMP_DIR "/s2d1/s2d2",
6184			.access = variant->allowed_s2d2,
6185		},
6186		{
6187			.path = TMP_DIR "/s2d1/s2d2/s2d3",
6188			.access = variant->allowed_s2d3,
6189		},
6190		/* s2d4_fd */
6191		{
6192			.path = TMP_DIR "/s3d1",
6193			.access = variant->allowed_s3d1,
6194		},
6195		/* s3d2_fd */
6196		{
6197			.path = TMP_DIR "/s4d1",
6198			.access = variant->allowed_s4d1,
6199		},
6200		{},
6201	};
6202	int ruleset_fd, s1d3_bind_fd;
6203
6204	ruleset_fd = create_ruleset(_metadata, handled_access, rules);
6205	ASSERT_LE(0, ruleset_fd);
6206
6207	/* Adds rules for the covered directories. */
6208	if (variant->allowed_s2d4) {
6209		ASSERT_EQ(0, landlock_add_rule(
6210				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
6211				     &(struct landlock_path_beneath_attr){
6212					     .parent_fd = self->s2d4_fd,
6213					     .allowed_access =
6214						     variant->allowed_s2d4,
6215				     },
6216				     0));
6217	}
6218	EXPECT_EQ(0, close(self->s2d4_fd));
6219
6220	if (variant->allowed_s3d2) {
6221		ASSERT_EQ(0, landlock_add_rule(
6222				     ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
6223				     &(struct landlock_path_beneath_attr){
6224					     .parent_fd = self->s3d2_fd,
6225					     .allowed_access =
6226						     variant->allowed_s3d2,
6227				     },
6228				     0));
6229	}
6230	EXPECT_EQ(0, close(self->s3d2_fd));
6231
6232	s1d3_bind_fd = open(TMP_DIR "/s3d1/s3d2/s2d3/s2d4/s1d3",
6233			    O_DIRECTORY | O_PATH | O_CLOEXEC);
6234	ASSERT_LE(0, s1d3_bind_fd);
6235
6236	/* Disconnects and checks source and destination directories. */
6237	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY));
6238	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY));
6239	/* Renames to make it accessible through s3d1/s1d41 */
6240	ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s2d1/s2d2/s2d3",
6241				   AT_FDCWD, TMP_DIR "/s4d1/s2d3"));
6242	EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY));
6243	EXPECT_EQ(ENOENT, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY));
6244
6245	enforce_ruleset(_metadata, ruleset_fd);
6246	EXPECT_EQ(0, close(ruleset_fd));
6247
6248	EXPECT_EQ(variant->expected_read_result,
6249		  test_open_rel(s1d3_bind_fd, "s1d41/f1", O_RDONLY));
6250
6251	EXPECT_EQ(variant->expected_rename_result,
6252		  test_renameat(s1d3_bind_fd, "s1d41/f1", s1d3_bind_fd,
6253				"s1d42/f1"));
6254	EXPECT_EQ(variant->expected_exchange_result,
6255		  test_exchangeat(s1d3_bind_fd, "s1d41/f2", s1d3_bind_fd,
6256				  "s1d42/f3"));
6257
6258	EXPECT_EQ(variant->expected_same_dir_rename_result,
6259		  test_renameat(s1d3_bind_fd, "s1d42/f4", s1d3_bind_fd,
6260				"s1d42/f5"));
6261}
6262
6263#define LOWER_BASE TMP_DIR "/lower"
6264#define LOWER_DATA LOWER_BASE "/data"
6265static const char lower_fl1[] = LOWER_DATA "/fl1";
6266static const char lower_dl1[] = LOWER_DATA "/dl1";
6267static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
6268static const char lower_fo1[] = LOWER_DATA "/fo1";
6269static const char lower_do1[] = LOWER_DATA "/do1";
6270static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
6271static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
6272
6273static const char (*lower_base_files[])[] = {
6274	&lower_fl1,
6275	&lower_fo1,
6276	NULL,
6277};
6278static const char (*lower_base_directories[])[] = {
6279	&lower_dl1,
6280	&lower_do1,
6281	NULL,
6282};
6283static const char (*lower_sub_files[])[] = {
6284	&lower_dl1_fl2,
6285	&lower_do1_fo2,
6286	&lower_do1_fl3,
6287	NULL,
6288};
6289
6290#define UPPER_BASE TMP_DIR "/upper"
6291#define UPPER_DATA UPPER_BASE "/data"
6292#define UPPER_WORK UPPER_BASE "/work"
6293static const char upper_fu1[] = UPPER_DATA "/fu1";
6294static const char upper_du1[] = UPPER_DATA "/du1";
6295static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
6296static const char upper_fo1[] = UPPER_DATA "/fo1";
6297static const char upper_do1[] = UPPER_DATA "/do1";
6298static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
6299static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
6300
6301static const char (*upper_base_files[])[] = {
6302	&upper_fu1,
6303	&upper_fo1,
6304	NULL,
6305};
6306static const char (*upper_base_directories[])[] = {
6307	&upper_du1,
6308	&upper_do1,
6309	NULL,
6310};
6311static const char (*upper_sub_files[])[] = {
6312	&upper_du1_fu2,
6313	&upper_do1_fo2,
6314	&upper_do1_fu3,
6315	NULL,
6316};
6317
6318#define MERGE_BASE TMP_DIR "/merge"
6319#define MERGE_DATA MERGE_BASE "/data"
6320static const char merge_fl1[] = MERGE_DATA "/fl1";
6321static const char merge_dl1[] = MERGE_DATA "/dl1";
6322static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
6323static const char merge_fu1[] = MERGE_DATA "/fu1";
6324static const char merge_du1[] = MERGE_DATA "/du1";
6325static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
6326static const char merge_fo1[] = MERGE_DATA "/fo1";
6327static const char merge_do1[] = MERGE_DATA "/do1";
6328static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
6329static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
6330static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
6331
6332static const char (*merge_base_files[])[] = {
6333	&merge_fl1,
6334	&merge_fu1,
6335	&merge_fo1,
6336	NULL,
6337};
6338static const char (*merge_base_directories[])[] = {
6339	&merge_dl1,
6340	&merge_du1,
6341	&merge_do1,
6342	NULL,
6343};
6344static const char (*merge_sub_files[])[] = {
6345	&merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2,
6346	&merge_do1_fl3, &merge_do1_fu3, NULL,
6347};
6348
6349/*
6350 * layout2_overlay hierarchy:
6351 *
6352 * tmp
6353 * ├── lower
6354 * │   └── data
6355 * │       ├── dl1
6356 * │       │   └── fl2
6357 * │       ├── do1
6358 * │       │   ├── fl3
6359 * │       │   └── fo2
6360 * │       ├── fl1
6361 * │       └── fo1
6362 * ├── merge
6363 * │   └── data
6364 * │       ├── dl1
6365 * │       │   └── fl2
6366 * │       ├── do1
6367 * │       │   ├── fl3
6368 * │       │   ├── fo2
6369 * │       │   └── fu3
6370 * │       ├── du1
6371 * │       │   └── fu2
6372 * │       ├── fl1
6373 * │       ├── fo1
6374 * │       └── fu1
6375 * └── upper
6376 *     ├── data
6377 *     │   ├── do1
6378 *     │   │   ├── fo2
6379 *     │   │   └── fu3
6380 *     │   ├── du1
6381 *     │   │   └── fu2
6382 *     │   ├── fo1
6383 *     │   └── fu1
6384 *     └── work
6385 *         └── work
6386 */
6387
6388FIXTURE(layout2_overlay)
6389{
6390	bool skip_test;
6391};
6392
6393FIXTURE_SETUP(layout2_overlay)
6394{
6395	if (!supports_filesystem("overlay")) {
6396		self->skip_test = true;
6397		SKIP(return, "overlayfs is not supported (setup)");
6398	}
6399
6400	prepare_layout(_metadata);
6401
6402	create_directory(_metadata, LOWER_BASE);
6403	set_cap(_metadata, CAP_SYS_ADMIN);
6404	/* Creates tmpfs mount points to get deterministic overlayfs. */
6405	ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE));
6406	clear_cap(_metadata, CAP_SYS_ADMIN);
6407	create_file(_metadata, lower_fl1);
6408	create_file(_metadata, lower_dl1_fl2);
6409	create_file(_metadata, lower_fo1);
6410	create_file(_metadata, lower_do1_fo2);
6411	create_file(_metadata, lower_do1_fl3);
6412
6413	create_directory(_metadata, UPPER_BASE);
6414	set_cap(_metadata, CAP_SYS_ADMIN);
6415	ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE));
6416	clear_cap(_metadata, CAP_SYS_ADMIN);
6417	create_file(_metadata, upper_fu1);
6418	create_file(_metadata, upper_du1_fu2);
6419	create_file(_metadata, upper_fo1);
6420	create_file(_metadata, upper_do1_fo2);
6421	create_file(_metadata, upper_do1_fu3);
6422	ASSERT_EQ(0, mkdir(UPPER_WORK, 0700));
6423
6424	create_directory(_metadata, MERGE_DATA);
6425	set_cap(_metadata, CAP_SYS_ADMIN);
6426	set_cap(_metadata, CAP_DAC_OVERRIDE);
6427	ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0,
6428			   "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA
6429			   ",workdir=" UPPER_WORK));
6430	clear_cap(_metadata, CAP_DAC_OVERRIDE);
6431	clear_cap(_metadata, CAP_SYS_ADMIN);
6432}
6433
6434FIXTURE_TEARDOWN_PARENT(layout2_overlay)
6435{
6436	if (self->skip_test)
6437		SKIP(return, "overlayfs is not supported (teardown)");
6438
6439	EXPECT_EQ(0, remove_path(lower_do1_fl3));
6440	EXPECT_EQ(0, remove_path(lower_dl1_fl2));
6441	EXPECT_EQ(0, remove_path(lower_fl1));
6442	EXPECT_EQ(0, remove_path(lower_do1_fo2));
6443	EXPECT_EQ(0, remove_path(lower_fo1));
6444
6445	/* umount(LOWER_BASE)) is handled by namespace lifetime. */
6446	EXPECT_EQ(0, remove_path(LOWER_BASE));
6447
6448	EXPECT_EQ(0, remove_path(upper_do1_fu3));
6449	EXPECT_EQ(0, remove_path(upper_du1_fu2));
6450	EXPECT_EQ(0, remove_path(upper_fu1));
6451	EXPECT_EQ(0, remove_path(upper_do1_fo2));
6452	EXPECT_EQ(0, remove_path(upper_fo1));
6453	EXPECT_EQ(0, remove_path(UPPER_WORK "/work"));
6454
6455	/* umount(UPPER_BASE)) is handled by namespace lifetime. */
6456	EXPECT_EQ(0, remove_path(UPPER_BASE));
6457
6458	/* umount(MERGE_DATA)) is handled by namespace lifetime. */
6459	EXPECT_EQ(0, remove_path(MERGE_DATA));
6460
6461	cleanup_layout(_metadata);
6462}
6463
6464TEST_F_FORK(layout2_overlay, no_restriction)
6465{
6466	if (self->skip_test)
6467		SKIP(return, "overlayfs is not supported (test)");
6468
6469	ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
6470	ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
6471	ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY));
6472	ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY));
6473	ASSERT_EQ(0, test_open(lower_do1, O_RDONLY));
6474	ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY));
6475	ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY));
6476
6477	ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY));
6478	ASSERT_EQ(0, test_open(upper_du1, O_RDONLY));
6479	ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY));
6480	ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY));
6481	ASSERT_EQ(0, test_open(upper_do1, O_RDONLY));
6482	ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY));
6483	ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY));
6484
6485	ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY));
6486	ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY));
6487	ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY));
6488	ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY));
6489	ASSERT_EQ(0, test_open(merge_du1, O_RDONLY));
6490	ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY));
6491	ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY));
6492	ASSERT_EQ(0, test_open(merge_do1, O_RDONLY));
6493	ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY));
6494	ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY));
6495	ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY));
6496}
6497
6498#define for_each_path(path_list, path_entry, i)               \
6499	for (i = 0, path_entry = *path_list[i]; path_list[i]; \
6500	     path_entry = *path_list[++i])
6501
6502TEST_F_FORK(layout2_overlay, same_content_different_file)
6503{
6504	/* Sets access right on parent directories of both layers. */
6505	const struct rule layer1_base[] = {
6506		{
6507			.path = LOWER_BASE,
6508			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6509		},
6510		{
6511			.path = UPPER_BASE,
6512			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6513		},
6514		{
6515			.path = MERGE_BASE,
6516			.access = ACCESS_RW,
6517		},
6518		{},
6519	};
6520	const struct rule layer2_data[] = {
6521		{
6522			.path = LOWER_DATA,
6523			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6524		},
6525		{
6526			.path = UPPER_DATA,
6527			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6528		},
6529		{
6530			.path = MERGE_DATA,
6531			.access = ACCESS_RW,
6532		},
6533		{},
6534	};
6535	/* Sets access right on directories inside both layers. */
6536	const struct rule layer3_subdirs[] = {
6537		{
6538			.path = lower_dl1,
6539			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6540		},
6541		{
6542			.path = lower_do1,
6543			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6544		},
6545		{
6546			.path = upper_du1,
6547			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6548		},
6549		{
6550			.path = upper_do1,
6551			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6552		},
6553		{
6554			.path = merge_dl1,
6555			.access = ACCESS_RW,
6556		},
6557		{
6558			.path = merge_du1,
6559			.access = ACCESS_RW,
6560		},
6561		{
6562			.path = merge_do1,
6563			.access = ACCESS_RW,
6564		},
6565		{},
6566	};
6567	/* Tighten access rights to the files. */
6568	const struct rule layer4_files[] = {
6569		{
6570			.path = lower_dl1_fl2,
6571			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6572		},
6573		{
6574			.path = lower_do1_fo2,
6575			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6576		},
6577		{
6578			.path = lower_do1_fl3,
6579			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6580		},
6581		{
6582			.path = upper_du1_fu2,
6583			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6584		},
6585		{
6586			.path = upper_do1_fo2,
6587			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6588		},
6589		{
6590			.path = upper_do1_fu3,
6591			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6592		},
6593		{
6594			.path = merge_dl1_fl2,
6595			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6596				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6597		},
6598		{
6599			.path = merge_du1_fu2,
6600			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6601				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6602		},
6603		{
6604			.path = merge_do1_fo2,
6605			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6606				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6607		},
6608		{
6609			.path = merge_do1_fl3,
6610			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6611				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6612		},
6613		{
6614			.path = merge_do1_fu3,
6615			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6616				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6617		},
6618		{},
6619	};
6620	const struct rule layer5_merge_only[] = {
6621		{
6622			.path = MERGE_DATA,
6623			.access = LANDLOCK_ACCESS_FS_READ_FILE |
6624				  LANDLOCK_ACCESS_FS_WRITE_FILE,
6625		},
6626		{},
6627	};
6628	int ruleset_fd;
6629	size_t i;
6630	const char *path_entry;
6631
6632	if (self->skip_test)
6633		SKIP(return, "overlayfs is not supported (test)");
6634
6635	/* Sets rules on base directories (i.e. outside overlay scope). */
6636	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
6637	ASSERT_LE(0, ruleset_fd);
6638	enforce_ruleset(_metadata, ruleset_fd);
6639	ASSERT_EQ(0, close(ruleset_fd));
6640
6641	/* Checks lower layer. */
6642	for_each_path(lower_base_files, path_entry, i) {
6643		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6644		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6645	}
6646	for_each_path(lower_base_directories, path_entry, i) {
6647		ASSERT_EQ(EACCES,
6648			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6649	}
6650	for_each_path(lower_sub_files, path_entry, i) {
6651		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6652		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6653	}
6654	/* Checks upper layer. */
6655	for_each_path(upper_base_files, path_entry, i) {
6656		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6657		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6658	}
6659	for_each_path(upper_base_directories, path_entry, i) {
6660		ASSERT_EQ(EACCES,
6661			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6662	}
6663	for_each_path(upper_sub_files, path_entry, i) {
6664		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6665		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6666	}
6667	/*
6668	 * Checks that access rights are independent from the lower and upper
6669	 * layers: write access to upper files viewed through the merge point
6670	 * is still allowed, and write access to lower file viewed (and copied)
6671	 * through the merge point is still allowed.
6672	 */
6673	for_each_path(merge_base_files, path_entry, i) {
6674		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6675	}
6676	for_each_path(merge_base_directories, path_entry, i) {
6677		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6678	}
6679	for_each_path(merge_sub_files, path_entry, i) {
6680		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6681	}
6682
6683	/* Sets rules on data directories (i.e. inside overlay scope). */
6684	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data);
6685	ASSERT_LE(0, ruleset_fd);
6686	enforce_ruleset(_metadata, ruleset_fd);
6687	ASSERT_EQ(0, close(ruleset_fd));
6688
6689	/* Checks merge. */
6690	for_each_path(merge_base_files, path_entry, i) {
6691		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6692	}
6693	for_each_path(merge_base_directories, path_entry, i) {
6694		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6695	}
6696	for_each_path(merge_sub_files, path_entry, i) {
6697		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6698	}
6699
6700	/* Same checks with tighter rules. */
6701	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs);
6702	ASSERT_LE(0, ruleset_fd);
6703	enforce_ruleset(_metadata, ruleset_fd);
6704	ASSERT_EQ(0, close(ruleset_fd));
6705
6706	/* Checks changes for lower layer. */
6707	for_each_path(lower_base_files, path_entry, i) {
6708		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6709	}
6710	/* Checks changes for upper layer. */
6711	for_each_path(upper_base_files, path_entry, i) {
6712		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6713	}
6714	/* Checks all merge accesses. */
6715	for_each_path(merge_base_files, path_entry, i) {
6716		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6717	}
6718	for_each_path(merge_base_directories, path_entry, i) {
6719		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
6720	}
6721	for_each_path(merge_sub_files, path_entry, i) {
6722		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6723	}
6724
6725	/* Sets rules directly on overlayed files. */
6726	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files);
6727	ASSERT_LE(0, ruleset_fd);
6728	enforce_ruleset(_metadata, ruleset_fd);
6729	ASSERT_EQ(0, close(ruleset_fd));
6730
6731	/* Checks unchanged accesses on lower layer. */
6732	for_each_path(lower_sub_files, path_entry, i) {
6733		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6734		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6735	}
6736	/* Checks unchanged accesses on upper layer. */
6737	for_each_path(upper_sub_files, path_entry, i) {
6738		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
6739		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
6740	}
6741	/* Checks all merge accesses. */
6742	for_each_path(merge_base_files, path_entry, i) {
6743		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6744	}
6745	for_each_path(merge_base_directories, path_entry, i) {
6746		ASSERT_EQ(EACCES,
6747			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6748	}
6749	for_each_path(merge_sub_files, path_entry, i) {
6750		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6751	}
6752
6753	/* Only allowes access to the merge hierarchy. */
6754	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only);
6755	ASSERT_LE(0, ruleset_fd);
6756	enforce_ruleset(_metadata, ruleset_fd);
6757	ASSERT_EQ(0, close(ruleset_fd));
6758
6759	/* Checks new accesses on lower layer. */
6760	for_each_path(lower_sub_files, path_entry, i) {
6761		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6762	}
6763	/* Checks new accesses on upper layer. */
6764	for_each_path(upper_sub_files, path_entry, i) {
6765		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
6766	}
6767	/* Checks all merge accesses. */
6768	for_each_path(merge_base_files, path_entry, i) {
6769		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
6770	}
6771	for_each_path(merge_base_directories, path_entry, i) {
6772		ASSERT_EQ(EACCES,
6773			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
6774	}
6775	for_each_path(merge_sub_files, path_entry, i) {
6776		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
6777	}
6778}
6779
6780FIXTURE(layout3_fs)
6781{
6782	bool has_created_dir;
6783	bool has_created_file;
6784	bool skip_test;
6785};
6786
6787FIXTURE_VARIANT(layout3_fs)
6788{
6789	const struct mnt_opt mnt;
6790	const char *const file_path;
6791	unsigned int cwd_fs_magic;
6792};
6793
6794/* clang-format off */
6795FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
6796	/* clang-format on */
6797	.mnt = {
6798		.type = "tmpfs",
6799		.data = MNT_TMP_DATA,
6800	},
6801	.file_path = file1_s1d1,
6802};
6803
6804FIXTURE_VARIANT_ADD(layout3_fs, ramfs) {
6805	.mnt = {
6806		.type = "ramfs",
6807		.data = "mode=700",
6808	},
6809	.file_path = TMP_DIR "/dir/file",
6810};
6811
6812FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) {
6813	.mnt = {
6814		.type = "cgroup2",
6815	},
6816	.file_path = TMP_DIR "/test/cgroup.procs",
6817};
6818
6819FIXTURE_VARIANT_ADD(layout3_fs, proc) {
6820	.mnt = {
6821		.type = "proc",
6822	},
6823	.file_path = TMP_DIR "/self/status",
6824};
6825
6826FIXTURE_VARIANT_ADD(layout3_fs, sysfs) {
6827	.mnt = {
6828		.type = "sysfs",
6829	},
6830	.file_path = TMP_DIR "/kernel/notes",
6831};
6832
6833FIXTURE_VARIANT_ADD(layout3_fs, hostfs) {
6834	.mnt = {
6835		.source = TMP_DIR,
6836		.flags = MS_BIND,
6837	},
6838	.file_path = TMP_DIR "/dir/file",
6839	.cwd_fs_magic = HOSTFS_SUPER_MAGIC,
6840};
6841
6842static char *dirname_alloc(const char *path)
6843{
6844	char *dup;
6845
6846	if (!path)
6847		return NULL;
6848
6849	dup = strdup(path);
6850	if (!dup)
6851		return NULL;
6852
6853	return dirname(dup);
6854}
6855
6856FIXTURE_SETUP(layout3_fs)
6857{
6858	struct stat statbuf;
6859	char *dir_path = dirname_alloc(variant->file_path);
6860
6861	if (!supports_filesystem(variant->mnt.type) ||
6862	    !cwd_matches_fs(variant->cwd_fs_magic)) {
6863		self->skip_test = true;
6864		SKIP(return, "this filesystem is not supported (setup)");
6865	}
6866
6867	prepare_layout_opt(_metadata, &variant->mnt);
6868
6869	/* Creates directory when required. */
6870	if (stat(dir_path, &statbuf)) {
6871		set_cap(_metadata, CAP_DAC_OVERRIDE);
6872		EXPECT_EQ(0, mkdir(dir_path, 0700))
6873		{
6874			TH_LOG("Failed to create directory \"%s\": %s",
6875			       dir_path, strerror(errno));
6876		}
6877		self->has_created_dir = true;
6878		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6879	}
6880
6881	/* Creates file when required. */
6882	if (stat(variant->file_path, &statbuf)) {
6883		int fd;
6884
6885		set_cap(_metadata, CAP_DAC_OVERRIDE);
6886		fd = creat(variant->file_path, 0600);
6887		EXPECT_LE(0, fd)
6888		{
6889			TH_LOG("Failed to create file \"%s\": %s",
6890			       variant->file_path, strerror(errno));
6891		}
6892		EXPECT_EQ(0, close(fd));
6893		self->has_created_file = true;
6894		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6895	}
6896
6897	free(dir_path);
6898}
6899
6900FIXTURE_TEARDOWN_PARENT(layout3_fs)
6901{
6902	if (self->skip_test)
6903		SKIP(return, "this filesystem is not supported (teardown)");
6904
6905	if (self->has_created_file) {
6906		set_cap(_metadata, CAP_DAC_OVERRIDE);
6907		/*
6908		 * Don't check for error because the file might already
6909		 * have been removed (cf. release_inode test).
6910		 */
6911		unlink(variant->file_path);
6912		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6913	}
6914
6915	if (self->has_created_dir) {
6916		char *dir_path = dirname_alloc(variant->file_path);
6917
6918		set_cap(_metadata, CAP_DAC_OVERRIDE);
6919		/*
6920		 * Don't check for error because the directory might already
6921		 * have been removed (cf. release_inode test).
6922		 */
6923		rmdir(dir_path);
6924		clear_cap(_metadata, CAP_DAC_OVERRIDE);
6925		free(dir_path);
6926	}
6927
6928	cleanup_layout(_metadata);
6929}
6930
6931static void layer3_fs_tag_inode(struct __test_metadata *const _metadata,
6932				FIXTURE_DATA(layout3_fs) * self,
6933				const FIXTURE_VARIANT(layout3_fs) * variant,
6934				const char *const rule_path)
6935{
6936	const struct rule layer1_allow_read_file[] = {
6937		{
6938			.path = rule_path,
6939			.access = LANDLOCK_ACCESS_FS_READ_FILE,
6940		},
6941		{},
6942	};
6943	const struct landlock_ruleset_attr layer2_deny_everything_attr = {
6944		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
6945	};
6946	const char *const dev_null_path = "/dev/null";
6947	int ruleset_fd;
6948
6949	if (self->skip_test)
6950		SKIP(return, "this filesystem is not supported (test)");
6951
6952	/* Checks without Landlock. */
6953	EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6954	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6955
6956	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
6957				    layer1_allow_read_file);
6958	EXPECT_LE(0, ruleset_fd);
6959	enforce_ruleset(_metadata, ruleset_fd);
6960	EXPECT_EQ(0, close(ruleset_fd));
6961
6962	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6963	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6964
6965	/* Forbids directory reading. */
6966	ruleset_fd =
6967		landlock_create_ruleset(&layer2_deny_everything_attr,
6968					sizeof(layer2_deny_everything_attr), 0);
6969	EXPECT_LE(0, ruleset_fd);
6970	enforce_ruleset(_metadata, ruleset_fd);
6971	EXPECT_EQ(0, close(ruleset_fd));
6972
6973	/* Checks with Landlock and forbidden access. */
6974	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
6975	EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
6976}
6977
6978/* Matrix of tests to check file hierarchy evaluation. */
6979
6980TEST_F_FORK(layout3_fs, tag_inode_dir_parent)
6981{
6982	/* The current directory must not be the root for this test. */
6983	layer3_fs_tag_inode(_metadata, self, variant, ".");
6984}
6985
6986TEST_F_FORK(layout3_fs, tag_inode_dir_mnt)
6987{
6988	layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR);
6989}
6990
6991TEST_F_FORK(layout3_fs, tag_inode_dir_child)
6992{
6993	char *dir_path = dirname_alloc(variant->file_path);
6994
6995	layer3_fs_tag_inode(_metadata, self, variant, dir_path);
6996	free(dir_path);
6997}
6998
6999TEST_F_FORK(layout3_fs, tag_inode_file)
7000{
7001	layer3_fs_tag_inode(_metadata, self, variant, variant->file_path);
7002}
7003
7004/* Light version of layout1.release_inodes */
7005TEST_F_FORK(layout3_fs, release_inodes)
7006{
7007	const struct rule layer1[] = {
7008		{
7009			.path = TMP_DIR,
7010			.access = LANDLOCK_ACCESS_FS_READ_DIR,
7011		},
7012		{},
7013	};
7014	int ruleset_fd;
7015
7016	if (self->skip_test)
7017		SKIP(return, "this filesystem is not supported (test)");
7018
7019	/* Clean up for the teardown to not fail. */
7020	if (self->has_created_file)
7021		EXPECT_EQ(0, remove_path(variant->file_path));
7022
7023	if (self->has_created_dir) {
7024		char *dir_path = dirname_alloc(variant->file_path);
7025
7026		/* Don't check for error because of cgroup specificities. */
7027		remove_path(dir_path);
7028		free(dir_path);
7029	}
7030
7031	ruleset_fd =
7032		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
7033	ASSERT_LE(0, ruleset_fd);
7034
7035	/* Unmount the filesystem while it is being used by a ruleset. */
7036	set_cap(_metadata, CAP_SYS_ADMIN);
7037	ASSERT_EQ(0, umount(TMP_DIR));
7038	clear_cap(_metadata, CAP_SYS_ADMIN);
7039
7040	/* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */
7041	set_cap(_metadata, CAP_SYS_ADMIN);
7042	ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR));
7043	clear_cap(_metadata, CAP_SYS_ADMIN);
7044
7045	enforce_ruleset(_metadata, ruleset_fd);
7046	ASSERT_EQ(0, close(ruleset_fd));
7047
7048	/* Checks that access to the new mount point is denied. */
7049	ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY));
7050}
7051
7052static int matches_log_fs_extra(struct __test_metadata *const _metadata,
7053				int audit_fd, const char *const blockers,
7054				const char *const path, const char *const extra)
7055{
7056	static const char log_template[] = REGEX_LANDLOCK_PREFIX
7057		" blockers=fs\\.%s path=\"%s\" dev=\"[^\"]\\+\" ino=[0-9]\\+$";
7058	char *absolute_path = NULL;
7059	size_t log_match_remaining = sizeof(log_template) + strlen(blockers) +
7060				     PATH_MAX * 2 +
7061				     (extra ? strlen(extra) : 0) + 1;
7062	char log_match[log_match_remaining];
7063	char *log_match_cursor = log_match;
7064	size_t chunk_len;
7065
7066	chunk_len = snprintf(log_match_cursor, log_match_remaining,
7067			     REGEX_LANDLOCK_PREFIX " blockers=%s path=\"",
7068			     blockers);
7069	if (chunk_len < 0 || chunk_len >= log_match_remaining)
7070		return -E2BIG;
7071
7072	/*
7073	 * It is assumed that absolute_path does not contain control
7074	 * characters nor spaces, see audit_string_contains_control().
7075	 */
7076	absolute_path = realpath(path, NULL);
7077	if (!absolute_path)
7078		return -errno;
7079
7080	log_match_remaining -= chunk_len;
7081	log_match_cursor += chunk_len;
7082	log_match_cursor = regex_escape(absolute_path, log_match_cursor,
7083					log_match_remaining);
7084	free(absolute_path);
7085	if (log_match_cursor < 0)
7086		return (long long)log_match_cursor;
7087
7088	log_match_remaining -= log_match_cursor - log_match;
7089	chunk_len = snprintf(log_match_cursor, log_match_remaining,
7090			     "\" dev=\"[^\"]\\+\" ino=[0-9]\\+%s$",
7091			     extra ?: "");
7092	if (chunk_len < 0 || chunk_len >= log_match_remaining)
7093		return -E2BIG;
7094
7095	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
7096				  NULL);
7097}
7098
7099static int matches_log_fs(struct __test_metadata *const _metadata, int audit_fd,
7100			  const char *const blockers, const char *const path)
7101{
7102	return matches_log_fs_extra(_metadata, audit_fd, blockers, path, NULL);
7103}
7104
7105FIXTURE(audit_layout1)
7106{
7107	struct audit_filter audit_filter;
7108	int audit_fd;
7109};
7110
7111FIXTURE_SETUP(audit_layout1)
7112{
7113	prepare_layout(_metadata);
7114
7115	create_layout1(_metadata);
7116
7117	set_cap(_metadata, CAP_AUDIT_CONTROL);
7118	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
7119	EXPECT_LE(0, self->audit_fd);
7120	disable_caps(_metadata);
7121}
7122
7123FIXTURE_TEARDOWN_PARENT(audit_layout1)
7124{
7125	remove_layout1(_metadata);
7126
7127	cleanup_layout(_metadata);
7128
7129	EXPECT_EQ(0, audit_cleanup(-1, NULL));
7130}
7131
7132TEST_F(audit_layout1, execute_make)
7133{
7134	struct audit_records records;
7135
7136	copy_file(_metadata, bin_true, file1_s1d1);
7137	test_execute(_metadata, 0, file1_s1d1);
7138	test_check_exec(_metadata, 0, file1_s1d1);
7139
7140	drop_access_rights(_metadata,
7141			   &(struct landlock_ruleset_attr){
7142				   .handled_access_fs =
7143					   LANDLOCK_ACCESS_FS_EXECUTE,
7144			   });
7145
7146	test_execute(_metadata, EACCES, file1_s1d1);
7147	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
7148				    file1_s1d1));
7149	test_check_exec(_metadata, EACCES, file1_s1d1);
7150	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute",
7151				    file1_s1d1));
7152
7153	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7154	EXPECT_EQ(0, records.access);
7155	EXPECT_EQ(0, records.domain);
7156}
7157
7158/*
7159 * Using a set of handled/denied access rights make it possible to check that
7160 * only the blocked ones are logged.
7161 */
7162
7163/* clang-format off */
7164static const __u64 access_fs_16 =
7165	LANDLOCK_ACCESS_FS_EXECUTE |
7166	LANDLOCK_ACCESS_FS_WRITE_FILE |
7167	LANDLOCK_ACCESS_FS_READ_FILE |
7168	LANDLOCK_ACCESS_FS_READ_DIR |
7169	LANDLOCK_ACCESS_FS_REMOVE_DIR |
7170	LANDLOCK_ACCESS_FS_REMOVE_FILE |
7171	LANDLOCK_ACCESS_FS_MAKE_CHAR |
7172	LANDLOCK_ACCESS_FS_MAKE_DIR |
7173	LANDLOCK_ACCESS_FS_MAKE_REG |
7174	LANDLOCK_ACCESS_FS_MAKE_SOCK |
7175	LANDLOCK_ACCESS_FS_MAKE_FIFO |
7176	LANDLOCK_ACCESS_FS_MAKE_BLOCK |
7177	LANDLOCK_ACCESS_FS_MAKE_SYM |
7178	LANDLOCK_ACCESS_FS_REFER |
7179	LANDLOCK_ACCESS_FS_TRUNCATE |
7180	LANDLOCK_ACCESS_FS_IOCTL_DEV;
7181/* clang-format on */
7182
7183TEST_F(audit_layout1, execute_read)
7184{
7185	struct audit_records records;
7186
7187	copy_file(_metadata, bin_true, file1_s1d1);
7188	test_execute(_metadata, 0, file1_s1d1);
7189	test_check_exec(_metadata, 0, file1_s1d1);
7190
7191	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7192					      .handled_access_fs = access_fs_16,
7193				      });
7194
7195	/*
7196	 * The only difference with the previous audit_layout1.execute_read test is
7197	 * the extra ",fs\\.read_file" blocked by the executable file.
7198	 */
7199	test_execute(_metadata, EACCES, file1_s1d1);
7200	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7201				    "fs\\.execute,fs\\.read_file", file1_s1d1));
7202	test_check_exec(_metadata, EACCES, file1_s1d1);
7203	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7204				    "fs\\.execute,fs\\.read_file", file1_s1d1));
7205
7206	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7207	EXPECT_EQ(0, records.access);
7208	EXPECT_EQ(0, records.domain);
7209}
7210
7211TEST_F(audit_layout1, write_file)
7212{
7213	struct audit_records records;
7214
7215	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7216					      .handled_access_fs = access_fs_16,
7217				      });
7218
7219	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
7220	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7221				    "fs\\.write_file", file1_s1d1));
7222
7223	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7224	EXPECT_EQ(0, records.access);
7225	EXPECT_EQ(1, records.domain);
7226}
7227
7228TEST_F(audit_layout1, read_file)
7229{
7230	struct audit_records records;
7231
7232	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7233					      .handled_access_fs = access_fs_16,
7234				      });
7235
7236	EXPECT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
7237	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_file",
7238				    file1_s1d1));
7239
7240	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7241	EXPECT_EQ(0, records.access);
7242	EXPECT_EQ(1, records.domain);
7243}
7244
7245TEST_F(audit_layout1, read_dir)
7246{
7247	struct audit_records records;
7248
7249	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7250					      .handled_access_fs = access_fs_16,
7251				      });
7252
7253	EXPECT_EQ(EACCES, test_open(dir_s1d1, O_DIRECTORY));
7254	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_dir",
7255				    dir_s1d1));
7256
7257	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7258	EXPECT_EQ(0, records.access);
7259	EXPECT_EQ(1, records.domain);
7260}
7261
7262TEST_F(audit_layout1, remove_dir)
7263{
7264	struct audit_records records;
7265
7266	EXPECT_EQ(0, unlink(file1_s1d3));
7267	EXPECT_EQ(0, unlink(file2_s1d3));
7268
7269	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7270					      .handled_access_fs = access_fs_16,
7271				      });
7272
7273	EXPECT_EQ(-1, rmdir(dir_s1d3));
7274	EXPECT_EQ(EACCES, errno);
7275	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7276				    "fs\\.remove_dir", dir_s1d2));
7277
7278	EXPECT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
7279	EXPECT_EQ(EACCES, errno);
7280	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7281				    "fs\\.remove_dir", dir_s1d2));
7282
7283	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7284	EXPECT_EQ(0, records.access);
7285	EXPECT_EQ(0, records.domain);
7286}
7287
7288TEST_F(audit_layout1, remove_file)
7289{
7290	struct audit_records records;
7291
7292	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7293					      .handled_access_fs = access_fs_16,
7294				      });
7295
7296	EXPECT_EQ(-1, unlink(file1_s1d3));
7297	EXPECT_EQ(EACCES, errno);
7298	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7299				    "fs\\.remove_file", dir_s1d3));
7300
7301	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7302	EXPECT_EQ(0, records.access);
7303	EXPECT_EQ(1, records.domain);
7304}
7305
7306TEST_F(audit_layout1, make_char)
7307{
7308	struct audit_records records;
7309
7310	EXPECT_EQ(0, unlink(file1_s1d3));
7311
7312	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7313					      .handled_access_fs = access_fs_16,
7314				      });
7315
7316	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0));
7317	EXPECT_EQ(EACCES, errno);
7318	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char",
7319				    dir_s1d3));
7320
7321	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7322	EXPECT_EQ(0, records.access);
7323	EXPECT_EQ(1, records.domain);
7324}
7325
7326TEST_F(audit_layout1, make_dir)
7327{
7328	struct audit_records records;
7329
7330	EXPECT_EQ(0, unlink(file1_s1d3));
7331
7332	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7333					      .handled_access_fs = access_fs_16,
7334				      });
7335
7336	EXPECT_EQ(-1, mkdir(file1_s1d3, 0755));
7337	EXPECT_EQ(EACCES, errno);
7338	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_dir",
7339				    dir_s1d3));
7340
7341	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7342	EXPECT_EQ(0, records.access);
7343	EXPECT_EQ(1, records.domain);
7344}
7345
7346TEST_F(audit_layout1, make_reg)
7347{
7348	struct audit_records records;
7349
7350	EXPECT_EQ(0, unlink(file1_s1d3));
7351
7352	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7353					      .handled_access_fs = access_fs_16,
7354				      });
7355
7356	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFREG | 0644, 0));
7357	EXPECT_EQ(EACCES, errno);
7358	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_reg",
7359				    dir_s1d3));
7360
7361	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7362	EXPECT_EQ(0, records.access);
7363	EXPECT_EQ(1, records.domain);
7364}
7365
7366TEST_F(audit_layout1, make_sock)
7367{
7368	struct audit_records records;
7369
7370	EXPECT_EQ(0, unlink(file1_s1d3));
7371
7372	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7373					      .handled_access_fs = access_fs_16,
7374				      });
7375
7376	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFSOCK | 0644, 0));
7377	EXPECT_EQ(EACCES, errno);
7378	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sock",
7379				    dir_s1d3));
7380
7381	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7382	EXPECT_EQ(0, records.access);
7383	EXPECT_EQ(1, records.domain);
7384}
7385
7386TEST_F(audit_layout1, make_fifo)
7387{
7388	struct audit_records records;
7389
7390	EXPECT_EQ(0, unlink(file1_s1d3));
7391
7392	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7393					      .handled_access_fs = access_fs_16,
7394				      });
7395
7396	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFIFO | 0644, 0));
7397	EXPECT_EQ(EACCES, errno);
7398	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_fifo",
7399				    dir_s1d3));
7400
7401	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7402	EXPECT_EQ(0, records.access);
7403	EXPECT_EQ(1, records.domain);
7404}
7405
7406TEST_F(audit_layout1, make_block)
7407{
7408	struct audit_records records;
7409
7410	EXPECT_EQ(0, unlink(file1_s1d3));
7411
7412	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7413					      .handled_access_fs = access_fs_16,
7414				      });
7415
7416	EXPECT_EQ(-1, mknod(file1_s1d3, S_IFBLK | 0644, 0));
7417	EXPECT_EQ(EACCES, errno);
7418	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7419				    "fs\\.make_block", dir_s1d3));
7420
7421	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7422	EXPECT_EQ(0, records.access);
7423	EXPECT_EQ(1, records.domain);
7424}
7425
7426TEST_F(audit_layout1, make_sym)
7427{
7428	struct audit_records records;
7429
7430	EXPECT_EQ(0, unlink(file1_s1d3));
7431
7432	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7433					      .handled_access_fs = access_fs_16,
7434				      });
7435
7436	EXPECT_EQ(-1, symlink("target", file1_s1d3));
7437	EXPECT_EQ(EACCES, errno);
7438	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sym",
7439				    dir_s1d3));
7440
7441	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7442	EXPECT_EQ(0, records.access);
7443	EXPECT_EQ(1, records.domain);
7444}
7445
7446TEST_F(audit_layout1, refer_handled)
7447{
7448	struct audit_records records;
7449
7450	EXPECT_EQ(0, unlink(file1_s1d3));
7451
7452	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7453					      .handled_access_fs =
7454						      LANDLOCK_ACCESS_FS_REFER,
7455				      });
7456
7457	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
7458	EXPECT_EQ(EXDEV, errno);
7459	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7460				    dir_s1d1));
7461	EXPECT_EQ(0,
7462		  matches_log_domain_allocated(self->audit_fd, getpid(), NULL));
7463	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7464				    dir_s1d3));
7465
7466	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7467	EXPECT_EQ(0, records.access);
7468	EXPECT_EQ(0, records.domain);
7469}
7470
7471TEST_F(audit_layout1, refer_make)
7472{
7473	struct audit_records records;
7474
7475	EXPECT_EQ(0, unlink(file1_s1d3));
7476
7477	drop_access_rights(_metadata,
7478			   &(struct landlock_ruleset_attr){
7479				   .handled_access_fs =
7480					   LANDLOCK_ACCESS_FS_MAKE_REG |
7481					   LANDLOCK_ACCESS_FS_REFER,
7482			   });
7483
7484	EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3));
7485	EXPECT_EQ(EACCES, errno);
7486	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7487				    dir_s1d1));
7488	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7489				    "fs\\.make_reg,fs\\.refer", dir_s1d3));
7490
7491	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7492	EXPECT_EQ(0, records.access);
7493	EXPECT_EQ(0, records.domain);
7494}
7495
7496TEST_F(audit_layout1, refer_rename)
7497{
7498	struct audit_records records;
7499
7500	EXPECT_EQ(0, unlink(file1_s1d3));
7501
7502	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7503					      .handled_access_fs = access_fs_16,
7504				      });
7505
7506	EXPECT_EQ(EACCES, test_rename(file1_s1d2, file1_s2d3));
7507	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7508				    "fs\\.remove_file,fs\\.refer", dir_s1d2));
7509	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7510				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7511				    dir_s2d3));
7512
7513	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7514	EXPECT_EQ(0, records.access);
7515	EXPECT_EQ(0, records.domain);
7516}
7517
7518TEST_F(audit_layout1, refer_exchange)
7519{
7520	struct audit_records records;
7521
7522	EXPECT_EQ(0, unlink(file1_s1d3));
7523
7524	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7525					      .handled_access_fs = access_fs_16,
7526				      });
7527
7528	/*
7529	 * The only difference with the previous audit_layout1.refer_rename test is
7530	 * the extra ",fs\\.make_reg" blocked by the source directory.
7531	 */
7532	EXPECT_EQ(EACCES, test_exchange(file1_s1d2, file1_s2d3));
7533	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7534				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7535				    dir_s1d2));
7536	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7537				    "fs\\.remove_file,fs\\.make_reg,fs\\.refer",
7538				    dir_s2d3));
7539
7540	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7541	EXPECT_EQ(0, records.access);
7542	EXPECT_EQ(0, records.domain);
7543}
7544
7545/*
7546 * This test checks that the audit record is correctly generated when the
7547 * operation is only partially denied.  This is the case for rename(2) when the
7548 * source file is allowed to be referenced but the destination directory is not.
7549 *
7550 * This is also a regression test for commit d617f0d72d80 ("landlock: Optimize
7551 * file path walks and prepare for audit support") and commit 058518c20920
7552 * ("landlock: Align partial refer access checks with final ones").
7553 */
7554TEST_F(audit_layout1, refer_rename_half)
7555{
7556	struct audit_records records;
7557	const struct rule layer1[] = {
7558		{
7559			.path = dir_s2d2,
7560			.access = LANDLOCK_ACCESS_FS_REFER,
7561		},
7562		{},
7563	};
7564	int ruleset_fd =
7565		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
7566
7567	ASSERT_LE(0, ruleset_fd);
7568	enforce_ruleset(_metadata, ruleset_fd);
7569	ASSERT_EQ(0, close(ruleset_fd));
7570
7571	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
7572	ASSERT_EQ(EXDEV, errno);
7573
7574	/* Only half of the request is denied. */
7575	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer",
7576				    dir_s1d1));
7577
7578	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7579	EXPECT_EQ(0, records.access);
7580	EXPECT_EQ(1, records.domain);
7581}
7582
7583TEST_F(audit_layout1, truncate)
7584{
7585	struct audit_records records;
7586
7587	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
7588					      .handled_access_fs = access_fs_16,
7589				      });
7590
7591	EXPECT_EQ(-1, truncate(file1_s1d3, 0));
7592	EXPECT_EQ(EACCES, errno);
7593	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.truncate",
7594				    file1_s1d3));
7595
7596	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7597	EXPECT_EQ(0, records.access);
7598	EXPECT_EQ(1, records.domain);
7599}
7600
7601TEST_F(audit_layout1, ioctl_dev)
7602{
7603	struct audit_records records;
7604	int fd;
7605
7606	drop_access_rights(_metadata,
7607			   &(struct landlock_ruleset_attr){
7608				   .handled_access_fs =
7609					   access_fs_16 &
7610					   ~LANDLOCK_ACCESS_FS_READ_FILE,
7611			   });
7612
7613	fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
7614	ASSERT_LE(0, fd);
7615	EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
7616	EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd,
7617					  "fs\\.ioctl_dev", "/dev/null",
7618					  " ioctlcmd=0x541b"));
7619
7620	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7621	EXPECT_EQ(0, records.access);
7622	EXPECT_EQ(1, records.domain);
7623}
7624
7625TEST_F(audit_layout1, mount)
7626{
7627	struct audit_records records;
7628
7629	drop_access_rights(_metadata,
7630			   &(struct landlock_ruleset_attr){
7631				   .handled_access_fs =
7632					   LANDLOCK_ACCESS_FS_EXECUTE,
7633			   });
7634
7635	set_cap(_metadata, CAP_SYS_ADMIN);
7636	EXPECT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
7637	EXPECT_EQ(EPERM, errno);
7638	clear_cap(_metadata, CAP_SYS_ADMIN);
7639	EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
7640				    "fs\\.change_topology", dir_s3d2));
7641	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
7642	EXPECT_EQ(0, records.access);
7643	EXPECT_EQ(1, records.domain);
7644}
7645
7646TEST_HARNESS_MAIN
~/ Read-only file preview.