Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
   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 <fcntl.h>
  12#include <linux/landlock.h>
  13#include <linux/magic.h>
  14#include <sched.h>
  15#include <stdio.h>
  16#include <string.h>
  17#include <sys/capability.h>
  18#include <sys/mount.h>
  19#include <sys/prctl.h>
  20#include <sys/sendfile.h>
  21#include <sys/stat.h>
  22#include <sys/sysmacros.h>
  23#include <sys/vfs.h>
  24#include <unistd.h>
  25
  26#include "common.h"
  27
  28#ifndef renameat2
  29int renameat2(int olddirfd, const char *oldpath, int newdirfd,
  30	      const char *newpath, unsigned int flags)
  31{
  32	return syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath,
  33		       flags);
  34}
  35#endif
  36
  37#ifndef RENAME_EXCHANGE
  38#define RENAME_EXCHANGE (1 << 1)
  39#endif
  40
  41#define TMP_DIR "tmp"
  42#define BINARY_PATH "./true"
  43
  44/* Paths (sibling number and depth) */
  45static const char dir_s1d1[] = TMP_DIR "/s1d1";
  46static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
  47static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
  48static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
  49static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
  50static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
  51static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
  52static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
  53static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
  54
  55static const char dir_s2d1[] = TMP_DIR "/s2d1";
  56static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
  57static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
  58static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
  59static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
  60static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
  61static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
  62
  63static const char dir_s3d1[] = TMP_DIR "/s3d1";
  64static const char file1_s3d1[] = TMP_DIR "/s3d1/f1";
  65/* dir_s3d2 is a mount point. */
  66static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
  67static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
  68
  69/*
  70 * layout1 hierarchy:
  71 *
  72 * tmp
  73 * ├── s1d1
  74 * │   ├── f1
  75 * │   ├── f2
  76 * │   └── s1d2
  77 * │       ├── f1
  78 * │       ├── f2
  79 * │       └── s1d3
  80 * │           ├── f1
  81 * │           └── f2
  82 * ├── s2d1
  83 * │   ├── f1
  84 * │   └── s2d2
  85 * │       ├── f1
  86 * │       └── s2d3
  87 * │           ├── f1
  88 * │           └── f2
  89 * └── s3d1
  90 *     ├── f1
  91 *     └── s3d2
  92 *         └── s3d3
  93 */
  94
  95static bool fgrep(FILE *const inf, const char *const str)
  96{
  97	char line[32];
  98	const int slen = strlen(str);
  99
 100	while (!feof(inf)) {
 101		if (!fgets(line, sizeof(line), inf))
 102			break;
 103		if (strncmp(line, str, slen))
 104			continue;
 105
 106		return true;
 107	}
 108
 109	return false;
 110}
 111
 112static bool supports_filesystem(const char *const filesystem)
 113{
 114	char str[32];
 115	int len;
 116	bool res = true;
 117	FILE *const inf = fopen("/proc/filesystems", "r");
 118
 119	/*
 120	 * Consider that the filesystem is supported if we cannot get the
 121	 * supported ones.
 122	 */
 123	if (!inf)
 124		return true;
 125
 126	/* filesystem can be null for bind mounts. */
 127	if (!filesystem)
 128		goto out;
 129
 130	len = snprintf(str, sizeof(str), "nodev\t%s\n", filesystem);
 131	if (len >= sizeof(str))
 132		/* Ignores too-long filesystem names. */
 133		goto out;
 134
 135	res = fgrep(inf, str);
 136
 137out:
 138	fclose(inf);
 139	return res;
 140}
 141
 142static bool cwd_matches_fs(unsigned int fs_magic)
 143{
 144	struct statfs statfs_buf;
 145
 146	if (!fs_magic)
 147		return true;
 148
 149	if (statfs(".", &statfs_buf))
 150		return true;
 151
 152	return statfs_buf.f_type == fs_magic;
 153}
 154
 155static void mkdir_parents(struct __test_metadata *const _metadata,
 156			  const char *const path)
 157{
 158	char *walker;
 159	const char *parent;
 160	int i, err;
 161
 162	ASSERT_NE(path[0], '\0');
 163	walker = strdup(path);
 164	ASSERT_NE(NULL, walker);
 165	parent = walker;
 166	for (i = 1; walker[i]; i++) {
 167		if (walker[i] != '/')
 168			continue;
 169		walker[i] = '\0';
 170		err = mkdir(parent, 0700);
 171		ASSERT_FALSE(err && errno != EEXIST)
 172		{
 173			TH_LOG("Failed to create directory \"%s\": %s", parent,
 174			       strerror(errno));
 175		}
 176		walker[i] = '/';
 177	}
 178	free(walker);
 179}
 180
 181static void create_directory(struct __test_metadata *const _metadata,
 182			     const char *const path)
 183{
 184	mkdir_parents(_metadata, path);
 185	ASSERT_EQ(0, mkdir(path, 0700))
 186	{
 187		TH_LOG("Failed to create directory \"%s\": %s", path,
 188		       strerror(errno));
 189	}
 190}
 191
 192static void create_file(struct __test_metadata *const _metadata,
 193			const char *const path)
 194{
 195	mkdir_parents(_metadata, path);
 196	ASSERT_EQ(0, mknod(path, S_IFREG | 0700, 0))
 197	{
 198		TH_LOG("Failed to create file \"%s\": %s", path,
 199		       strerror(errno));
 200	}
 201}
 202
 203static int remove_path(const char *const path)
 204{
 205	char *walker;
 206	int i, ret, err = 0;
 207
 208	walker = strdup(path);
 209	if (!walker) {
 210		err = ENOMEM;
 211		goto out;
 212	}
 213	if (unlink(path) && rmdir(path)) {
 214		if (errno != ENOENT && errno != ENOTDIR)
 215			err = errno;
 216		goto out;
 217	}
 218	for (i = strlen(walker); i > 0; i--) {
 219		if (walker[i] != '/')
 220			continue;
 221		walker[i] = '\0';
 222		ret = rmdir(walker);
 223		if (ret) {
 224			if (errno != ENOTEMPTY && errno != EBUSY)
 225				err = errno;
 226			goto out;
 227		}
 228		if (strcmp(walker, TMP_DIR) == 0)
 229			goto out;
 230	}
 231
 232out:
 233	free(walker);
 234	return err;
 235}
 236
 237struct mnt_opt {
 238	const char *const source;
 239	const char *const type;
 240	const unsigned long flags;
 241	const char *const data;
 242};
 243
 244#define MNT_TMP_DATA "size=4m,mode=700"
 245
 246static const struct mnt_opt mnt_tmp = {
 247	.type = "tmpfs",
 248	.data = MNT_TMP_DATA,
 249};
 250
 251static int mount_opt(const struct mnt_opt *const mnt, const char *const target)
 252{
 253	return mount(mnt->source ?: mnt->type, target, mnt->type, mnt->flags,
 254		     mnt->data);
 255}
 256
 257static void prepare_layout_opt(struct __test_metadata *const _metadata,
 258			       const struct mnt_opt *const mnt)
 259{
 260	disable_caps(_metadata);
 261	umask(0077);
 262	create_directory(_metadata, TMP_DIR);
 263
 264	/*
 265	 * Do not pollute the rest of the system: creates a private mount point
 266	 * for tests relying on pivot_root(2) and move_mount(2).
 267	 */
 268	set_cap(_metadata, CAP_SYS_ADMIN);
 269	ASSERT_EQ(0, unshare(CLONE_NEWNS | CLONE_NEWCGROUP));
 270	ASSERT_EQ(0, mount_opt(mnt, TMP_DIR))
 271	{
 272		TH_LOG("Failed to mount the %s filesystem: %s", mnt->type,
 273		       strerror(errno));
 274		/*
 275		 * FIXTURE_TEARDOWN() is not called when FIXTURE_SETUP()
 276		 * failed, so we need to explicitly do a minimal cleanup to
 277		 * avoid cascading errors with other tests that don't depend on
 278		 * the same filesystem.
 279		 */
 280		remove_path(TMP_DIR);
 281	}
 282	ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL));
 283	clear_cap(_metadata, CAP_SYS_ADMIN);
 284}
 285
 286static void prepare_layout(struct __test_metadata *const _metadata)
 287{
 288	prepare_layout_opt(_metadata, &mnt_tmp);
 289}
 290
 291static void cleanup_layout(struct __test_metadata *const _metadata)
 292{
 293	set_cap(_metadata, CAP_SYS_ADMIN);
 294	EXPECT_EQ(0, umount(TMP_DIR));
 295	clear_cap(_metadata, CAP_SYS_ADMIN);
 296	EXPECT_EQ(0, remove_path(TMP_DIR));
 297}
 298
 299/* clang-format off */
 300FIXTURE(layout0) {};
 301/* clang-format on */
 302
 303FIXTURE_SETUP(layout0)
 304{
 305	prepare_layout(_metadata);
 306}
 307
 308FIXTURE_TEARDOWN(layout0)
 309{
 310	cleanup_layout(_metadata);
 311}
 312
 313static void create_layout1(struct __test_metadata *const _metadata)
 314{
 315	create_file(_metadata, file1_s1d1);
 316	create_file(_metadata, file1_s1d2);
 317	create_file(_metadata, file1_s1d3);
 318	create_file(_metadata, file2_s1d1);
 319	create_file(_metadata, file2_s1d2);
 320	create_file(_metadata, file2_s1d3);
 321
 322	create_file(_metadata, file1_s2d1);
 323	create_file(_metadata, file1_s2d2);
 324	create_file(_metadata, file1_s2d3);
 325	create_file(_metadata, file2_s2d3);
 326
 327	create_file(_metadata, file1_s3d1);
 328	create_directory(_metadata, dir_s3d2);
 329	set_cap(_metadata, CAP_SYS_ADMIN);
 330	ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s3d2));
 331	clear_cap(_metadata, CAP_SYS_ADMIN);
 332
 333	ASSERT_EQ(0, mkdir(dir_s3d3, 0700));
 334}
 335
 336static void remove_layout1(struct __test_metadata *const _metadata)
 337{
 338	EXPECT_EQ(0, remove_path(file2_s1d3));
 339	EXPECT_EQ(0, remove_path(file2_s1d2));
 340	EXPECT_EQ(0, remove_path(file2_s1d1));
 341	EXPECT_EQ(0, remove_path(file1_s1d3));
 342	EXPECT_EQ(0, remove_path(file1_s1d2));
 343	EXPECT_EQ(0, remove_path(file1_s1d1));
 344	EXPECT_EQ(0, remove_path(dir_s1d3));
 345
 346	EXPECT_EQ(0, remove_path(file2_s2d3));
 347	EXPECT_EQ(0, remove_path(file1_s2d3));
 348	EXPECT_EQ(0, remove_path(file1_s2d2));
 349	EXPECT_EQ(0, remove_path(file1_s2d1));
 350	EXPECT_EQ(0, remove_path(dir_s2d2));
 351
 352	EXPECT_EQ(0, remove_path(file1_s3d1));
 353	EXPECT_EQ(0, remove_path(dir_s3d3));
 354	set_cap(_metadata, CAP_SYS_ADMIN);
 355	umount(dir_s3d2);
 356	clear_cap(_metadata, CAP_SYS_ADMIN);
 357	EXPECT_EQ(0, remove_path(dir_s3d2));
 358}
 359
 360/* clang-format off */
 361FIXTURE(layout1) {};
 362/* clang-format on */
 363
 364FIXTURE_SETUP(layout1)
 365{
 366	prepare_layout(_metadata);
 367
 368	create_layout1(_metadata);
 369}
 370
 371FIXTURE_TEARDOWN(layout1)
 372{
 373	remove_layout1(_metadata);
 374
 375	cleanup_layout(_metadata);
 376}
 377
 378/*
 379 * This helper enables to use the ASSERT_* macros and print the line number
 380 * pointing to the test caller.
 381 */
 382static int test_open_rel(const int dirfd, const char *const path,
 383			 const int flags)
 384{
 385	int fd;
 386
 387	/* Works with file and directories. */
 388	fd = openat(dirfd, path, flags | O_CLOEXEC);
 389	if (fd < 0)
 390		return errno;
 391	/*
 392	 * Mixing error codes from close(2) and open(2) should not lead to any
 393	 * (access type) confusion for this test.
 394	 */
 395	if (close(fd) != 0)
 396		return errno;
 397	return 0;
 398}
 399
 400static int test_open(const char *const path, const int flags)
 401{
 402	return test_open_rel(AT_FDCWD, path, flags);
 403}
 404
 405TEST_F_FORK(layout1, no_restriction)
 406{
 407	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
 408	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
 409	ASSERT_EQ(0, test_open(file2_s1d1, O_RDONLY));
 410	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
 411	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
 412	ASSERT_EQ(0, test_open(file2_s1d2, O_RDONLY));
 413	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
 414	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
 415
 416	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
 417	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
 418	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
 419	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
 420	ASSERT_EQ(0, test_open(dir_s2d3, O_RDONLY));
 421	ASSERT_EQ(0, test_open(file1_s2d3, O_RDONLY));
 422
 423	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
 424	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
 425	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
 426}
 427
 428TEST_F_FORK(layout1, inval)
 429{
 430	struct landlock_path_beneath_attr path_beneath = {
 431		.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
 432				  LANDLOCK_ACCESS_FS_WRITE_FILE,
 433		.parent_fd = -1,
 434	};
 435	struct landlock_ruleset_attr ruleset_attr = {
 436		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
 437				     LANDLOCK_ACCESS_FS_WRITE_FILE,
 438	};
 439	int ruleset_fd;
 440
 441	path_beneath.parent_fd =
 442		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
 443	ASSERT_LE(0, path_beneath.parent_fd);
 444
 445	ruleset_fd = open(dir_s1d1, O_PATH | O_DIRECTORY | O_CLOEXEC);
 446	ASSERT_LE(0, ruleset_fd);
 447	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 448					&path_beneath, 0));
 449	/* Returns EBADF because ruleset_fd is not a landlock-ruleset FD. */
 450	ASSERT_EQ(EBADF, errno);
 451	ASSERT_EQ(0, close(ruleset_fd));
 452
 453	ruleset_fd = open(dir_s1d1, O_DIRECTORY | O_CLOEXEC);
 454	ASSERT_LE(0, ruleset_fd);
 455	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 456					&path_beneath, 0));
 457	/* Returns EBADFD because ruleset_fd is not a valid ruleset. */
 458	ASSERT_EQ(EBADFD, errno);
 459	ASSERT_EQ(0, close(ruleset_fd));
 460
 461	/* Gets a real ruleset. */
 462	ruleset_fd =
 463		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 464	ASSERT_LE(0, ruleset_fd);
 465	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 466				       &path_beneath, 0));
 467	ASSERT_EQ(0, close(path_beneath.parent_fd));
 468
 469	/* Tests without O_PATH. */
 470	path_beneath.parent_fd = open(dir_s1d2, O_DIRECTORY | O_CLOEXEC);
 471	ASSERT_LE(0, path_beneath.parent_fd);
 472	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 473				       &path_beneath, 0));
 474	ASSERT_EQ(0, close(path_beneath.parent_fd));
 475
 476	/* Tests with a ruleset FD. */
 477	path_beneath.parent_fd = ruleset_fd;
 478	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 479					&path_beneath, 0));
 480	ASSERT_EQ(EBADFD, errno);
 481
 482	/* Checks unhandled allowed_access. */
 483	path_beneath.parent_fd =
 484		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
 485	ASSERT_LE(0, path_beneath.parent_fd);
 486
 487	/* Test with legitimate values. */
 488	path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_EXECUTE;
 489	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 490					&path_beneath, 0));
 491	ASSERT_EQ(EINVAL, errno);
 492	path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE;
 493
 494	/* Tests with denied-by-default access right. */
 495	path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_REFER;
 496	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 497					&path_beneath, 0));
 498	ASSERT_EQ(EINVAL, errno);
 499	path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_REFER;
 500
 501	/* Test with unknown (64-bits) value. */
 502	path_beneath.allowed_access |= (1ULL << 60);
 503	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 504					&path_beneath, 0));
 505	ASSERT_EQ(EINVAL, errno);
 506	path_beneath.allowed_access &= ~(1ULL << 60);
 507
 508	/* Test with no access. */
 509	path_beneath.allowed_access = 0;
 510	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 511					&path_beneath, 0));
 512	ASSERT_EQ(ENOMSG, errno);
 513	path_beneath.allowed_access &= ~(1ULL << 60);
 514
 515	ASSERT_EQ(0, close(path_beneath.parent_fd));
 516
 517	/* Enforces the ruleset. */
 518	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
 519	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
 520
 521	ASSERT_EQ(0, close(ruleset_fd));
 522}
 523
 524/* clang-format off */
 525
 526#define ACCESS_FILE ( \
 527	LANDLOCK_ACCESS_FS_EXECUTE | \
 528	LANDLOCK_ACCESS_FS_WRITE_FILE | \
 529	LANDLOCK_ACCESS_FS_READ_FILE | \
 530	LANDLOCK_ACCESS_FS_TRUNCATE)
 531
 532#define ACCESS_LAST LANDLOCK_ACCESS_FS_TRUNCATE
 533
 534#define ACCESS_ALL ( \
 535	ACCESS_FILE | \
 536	LANDLOCK_ACCESS_FS_READ_DIR | \
 537	LANDLOCK_ACCESS_FS_REMOVE_DIR | \
 538	LANDLOCK_ACCESS_FS_REMOVE_FILE | \
 539	LANDLOCK_ACCESS_FS_MAKE_CHAR | \
 540	LANDLOCK_ACCESS_FS_MAKE_DIR | \
 541	LANDLOCK_ACCESS_FS_MAKE_REG | \
 542	LANDLOCK_ACCESS_FS_MAKE_SOCK | \
 543	LANDLOCK_ACCESS_FS_MAKE_FIFO | \
 544	LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
 545	LANDLOCK_ACCESS_FS_MAKE_SYM | \
 546	LANDLOCK_ACCESS_FS_REFER)
 547
 548/* clang-format on */
 549
 550TEST_F_FORK(layout1, file_and_dir_access_rights)
 551{
 552	__u64 access;
 553	int err;
 554	struct landlock_path_beneath_attr path_beneath_file = {},
 555					  path_beneath_dir = {};
 556	struct landlock_ruleset_attr ruleset_attr = {
 557		.handled_access_fs = ACCESS_ALL,
 558	};
 559	const int ruleset_fd =
 560		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 561
 562	ASSERT_LE(0, ruleset_fd);
 563
 564	/* Tests access rights for files. */
 565	path_beneath_file.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC);
 566	ASSERT_LE(0, path_beneath_file.parent_fd);
 567
 568	/* Tests access rights for directories. */
 569	path_beneath_dir.parent_fd =
 570		open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC);
 571	ASSERT_LE(0, path_beneath_dir.parent_fd);
 572
 573	for (access = 1; access <= ACCESS_LAST; access <<= 1) {
 574		path_beneath_dir.allowed_access = access;
 575		ASSERT_EQ(0, landlock_add_rule(ruleset_fd,
 576					       LANDLOCK_RULE_PATH_BENEATH,
 577					       &path_beneath_dir, 0));
 578
 579		path_beneath_file.allowed_access = access;
 580		err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 581					&path_beneath_file, 0);
 582		if (access & ACCESS_FILE) {
 583			ASSERT_EQ(0, err);
 584		} else {
 585			ASSERT_EQ(-1, err);
 586			ASSERT_EQ(EINVAL, errno);
 587		}
 588	}
 589	ASSERT_EQ(0, close(path_beneath_file.parent_fd));
 590	ASSERT_EQ(0, close(path_beneath_dir.parent_fd));
 591	ASSERT_EQ(0, close(ruleset_fd));
 592}
 593
 594TEST_F_FORK(layout0, ruleset_with_unknown_access)
 595{
 596	__u64 access_mask;
 597
 598	for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST;
 599	     access_mask >>= 1) {
 600		struct landlock_ruleset_attr ruleset_attr = {
 601			.handled_access_fs = access_mask,
 602		};
 603
 604		ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr,
 605						      sizeof(ruleset_attr), 0));
 606		ASSERT_EQ(EINVAL, errno);
 607	}
 608}
 609
 610TEST_F_FORK(layout0, rule_with_unknown_access)
 611{
 612	__u64 access;
 613	struct landlock_path_beneath_attr path_beneath = {};
 614	const struct landlock_ruleset_attr ruleset_attr = {
 615		.handled_access_fs = ACCESS_ALL,
 616	};
 617	const int ruleset_fd =
 618		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 619
 620	ASSERT_LE(0, ruleset_fd);
 621
 622	path_beneath.parent_fd =
 623		open(TMP_DIR, O_PATH | O_DIRECTORY | O_CLOEXEC);
 624	ASSERT_LE(0, path_beneath.parent_fd);
 625
 626	for (access = 1ULL << 63; access != ACCESS_LAST; access >>= 1) {
 627		path_beneath.allowed_access = access;
 628		EXPECT_EQ(-1, landlock_add_rule(ruleset_fd,
 629						LANDLOCK_RULE_PATH_BENEATH,
 630						&path_beneath, 0));
 631		EXPECT_EQ(EINVAL, errno);
 632	}
 633	ASSERT_EQ(0, close(path_beneath.parent_fd));
 634	ASSERT_EQ(0, close(ruleset_fd));
 635}
 636
 637TEST_F_FORK(layout1, rule_with_unhandled_access)
 638{
 639	struct landlock_ruleset_attr ruleset_attr = {
 640		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
 641	};
 642	struct landlock_path_beneath_attr path_beneath = {};
 643	int ruleset_fd;
 644	__u64 access;
 645
 646	ruleset_fd =
 647		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 648	ASSERT_LE(0, ruleset_fd);
 649
 650	path_beneath.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC);
 651	ASSERT_LE(0, path_beneath.parent_fd);
 652
 653	for (access = 1; access > 0; access <<= 1) {
 654		int err;
 655
 656		path_beneath.allowed_access = access;
 657		err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 658					&path_beneath, 0);
 659		if (access == ruleset_attr.handled_access_fs) {
 660			EXPECT_EQ(0, err);
 661		} else {
 662			EXPECT_EQ(-1, err);
 663			EXPECT_EQ(EINVAL, errno);
 664		}
 665	}
 666
 667	EXPECT_EQ(0, close(path_beneath.parent_fd));
 668	EXPECT_EQ(0, close(ruleset_fd));
 669}
 670
 671static void add_path_beneath(struct __test_metadata *const _metadata,
 672			     const int ruleset_fd, const __u64 allowed_access,
 673			     const char *const path)
 674{
 675	struct landlock_path_beneath_attr path_beneath = {
 676		.allowed_access = allowed_access,
 677	};
 678
 679	path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC);
 680	ASSERT_LE(0, path_beneath.parent_fd)
 681	{
 682		TH_LOG("Failed to open directory \"%s\": %s", path,
 683		       strerror(errno));
 684	}
 685	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 686				       &path_beneath, 0))
 687	{
 688		TH_LOG("Failed to update the ruleset with \"%s\": %s", path,
 689		       strerror(errno));
 690	}
 691	ASSERT_EQ(0, close(path_beneath.parent_fd));
 692}
 693
 694struct rule {
 695	const char *path;
 696	__u64 access;
 697};
 698
 699/* clang-format off */
 700
 701#define ACCESS_RO ( \
 702	LANDLOCK_ACCESS_FS_READ_FILE | \
 703	LANDLOCK_ACCESS_FS_READ_DIR)
 704
 705#define ACCESS_RW ( \
 706	ACCESS_RO | \
 707	LANDLOCK_ACCESS_FS_WRITE_FILE)
 708
 709/* clang-format on */
 710
 711static int create_ruleset(struct __test_metadata *const _metadata,
 712			  const __u64 handled_access_fs,
 713			  const struct rule rules[])
 714{
 715	int ruleset_fd, i;
 716	struct landlock_ruleset_attr ruleset_attr = {
 717		.handled_access_fs = handled_access_fs,
 718	};
 719
 720	ASSERT_NE(NULL, rules)
 721	{
 722		TH_LOG("No rule list");
 723	}
 724	ASSERT_NE(NULL, rules[0].path)
 725	{
 726		TH_LOG("Empty rule list");
 727	}
 728
 729	ruleset_fd =
 730		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 731	ASSERT_LE(0, ruleset_fd)
 732	{
 733		TH_LOG("Failed to create a ruleset: %s", strerror(errno));
 734	}
 735
 736	for (i = 0; rules[i].path; i++) {
 737		add_path_beneath(_metadata, ruleset_fd, rules[i].access,
 738				 rules[i].path);
 739	}
 740	return ruleset_fd;
 741}
 742
 743TEST_F_FORK(layout0, proc_nsfs)
 744{
 745	const struct rule rules[] = {
 746		{
 747			.path = "/dev/null",
 748			.access = LANDLOCK_ACCESS_FS_READ_FILE |
 749				  LANDLOCK_ACCESS_FS_WRITE_FILE,
 750		},
 751		{},
 752	};
 753	struct landlock_path_beneath_attr path_beneath;
 754	const int ruleset_fd = create_ruleset(
 755		_metadata, rules[0].access | LANDLOCK_ACCESS_FS_READ_DIR,
 756		rules);
 757
 758	ASSERT_LE(0, ruleset_fd);
 759	ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
 760
 761	enforce_ruleset(_metadata, ruleset_fd);
 762
 763	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
 764	ASSERT_EQ(EACCES, test_open("/dev", O_RDONLY));
 765	ASSERT_EQ(0, test_open("/dev/null", O_RDONLY));
 766	ASSERT_EQ(EACCES, test_open("/dev/full", O_RDONLY));
 767
 768	ASSERT_EQ(EACCES, test_open("/proc", O_RDONLY));
 769	ASSERT_EQ(EACCES, test_open("/proc/self", O_RDONLY));
 770	ASSERT_EQ(EACCES, test_open("/proc/self/ns", O_RDONLY));
 771	/*
 772	 * Because nsfs is an internal filesystem, /proc/self/ns/mnt is a
 773	 * disconnected path.  Such path cannot be identified and must then be
 774	 * allowed.
 775	 */
 776	ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
 777
 778	/*
 779	 * Checks that it is not possible to add nsfs-like filesystem
 780	 * references to a ruleset.
 781	 */
 782	path_beneath.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
 783				      LANDLOCK_ACCESS_FS_WRITE_FILE,
 784	path_beneath.parent_fd = open("/proc/self/ns/mnt", O_PATH | O_CLOEXEC);
 785	ASSERT_LE(0, path_beneath.parent_fd);
 786	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
 787					&path_beneath, 0));
 788	ASSERT_EQ(EBADFD, errno);
 789	ASSERT_EQ(0, close(path_beneath.parent_fd));
 790}
 791
 792TEST_F_FORK(layout0, unpriv)
 793{
 794	const struct rule rules[] = {
 795		{
 796			.path = TMP_DIR,
 797			.access = ACCESS_RO,
 798		},
 799		{},
 800	};
 801	int ruleset_fd;
 802
 803	drop_caps(_metadata);
 804
 805	ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
 806	ASSERT_LE(0, ruleset_fd);
 807	ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
 808	ASSERT_EQ(EPERM, errno);
 809
 810	/* enforce_ruleset() calls prctl(no_new_privs). */
 811	enforce_ruleset(_metadata, ruleset_fd);
 812	ASSERT_EQ(0, close(ruleset_fd));
 813}
 814
 815TEST_F_FORK(layout1, effective_access)
 816{
 817	const struct rule rules[] = {
 818		{
 819			.path = dir_s1d2,
 820			.access = ACCESS_RO,
 821		},
 822		{
 823			.path = file1_s2d2,
 824			.access = LANDLOCK_ACCESS_FS_READ_FILE |
 825				  LANDLOCK_ACCESS_FS_WRITE_FILE,
 826		},
 827		{},
 828	};
 829	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
 830	char buf;
 831	int reg_fd;
 832
 833	ASSERT_LE(0, ruleset_fd);
 834	enforce_ruleset(_metadata, ruleset_fd);
 835	ASSERT_EQ(0, close(ruleset_fd));
 836
 837	/* Tests on a directory (with or without O_PATH). */
 838	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
 839	ASSERT_EQ(0, test_open("/", O_RDONLY | O_PATH));
 840	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
 841	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_PATH));
 842	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
 843	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY | O_PATH));
 844
 845	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
 846	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
 847	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
 848	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
 849
 850	/* Tests on a file (with or without O_PATH). */
 851	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY));
 852	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_PATH));
 853
 854	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
 855
 856	/* Checks effective read and write actions. */
 857	reg_fd = open(file1_s2d2, O_RDWR | O_CLOEXEC);
 858	ASSERT_LE(0, reg_fd);
 859	ASSERT_EQ(1, write(reg_fd, ".", 1));
 860	ASSERT_LE(0, lseek(reg_fd, 0, SEEK_SET));
 861	ASSERT_EQ(1, read(reg_fd, &buf, 1));
 862	ASSERT_EQ('.', buf);
 863	ASSERT_EQ(0, close(reg_fd));
 864
 865	/* Just in case, double-checks effective actions. */
 866	reg_fd = open(file1_s2d2, O_RDONLY | O_CLOEXEC);
 867	ASSERT_LE(0, reg_fd);
 868	ASSERT_EQ(-1, write(reg_fd, &buf, 1));
 869	ASSERT_EQ(EBADF, errno);
 870	ASSERT_EQ(0, close(reg_fd));
 871}
 872
 873TEST_F_FORK(layout1, unhandled_access)
 874{
 875	const struct rule rules[] = {
 876		{
 877			.path = dir_s1d2,
 878			.access = ACCESS_RO,
 879		},
 880		{},
 881	};
 882	/* Here, we only handle read accesses, not write accesses. */
 883	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
 884
 885	ASSERT_LE(0, ruleset_fd);
 886	enforce_ruleset(_metadata, ruleset_fd);
 887	ASSERT_EQ(0, close(ruleset_fd));
 888
 889	/*
 890	 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE,
 891	 * opening for write-only should be allowed, but not read-write.
 892	 */
 893	ASSERT_EQ(0, test_open(file1_s1d1, O_WRONLY));
 894	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
 895
 896	ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
 897	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
 898}
 899
 900TEST_F_FORK(layout1, ruleset_overlap)
 901{
 902	const struct rule rules[] = {
 903		/* These rules should be ORed among them. */
 904		{
 905			.path = dir_s1d2,
 906			.access = LANDLOCK_ACCESS_FS_READ_FILE |
 907				  LANDLOCK_ACCESS_FS_WRITE_FILE,
 908		},
 909		{
 910			.path = dir_s1d2,
 911			.access = LANDLOCK_ACCESS_FS_READ_FILE |
 912				  LANDLOCK_ACCESS_FS_READ_DIR,
 913		},
 914		{},
 915	};
 916	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
 917
 918	ASSERT_LE(0, ruleset_fd);
 919	enforce_ruleset(_metadata, ruleset_fd);
 920	ASSERT_EQ(0, close(ruleset_fd));
 921
 922	/* Checks s1d1 hierarchy. */
 923	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
 924	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
 925	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
 926	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
 927
 928	/* Checks s1d2 hierarchy. */
 929	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
 930	ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
 931	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
 932	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
 933
 934	/* Checks s1d3 hierarchy. */
 935	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
 936	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
 937	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
 938	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
 939}
 940
 941TEST_F_FORK(layout1, layer_rule_unions)
 942{
 943	const struct rule layer1[] = {
 944		{
 945			.path = dir_s1d2,
 946			.access = LANDLOCK_ACCESS_FS_READ_FILE,
 947		},
 948		/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
 949		{
 950			.path = dir_s1d3,
 951			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
 952		},
 953		{},
 954	};
 955	const struct rule layer2[] = {
 956		/* Doesn't change anything from layer1. */
 957		{
 958			.path = dir_s1d2,
 959			.access = LANDLOCK_ACCESS_FS_READ_FILE |
 960				  LANDLOCK_ACCESS_FS_WRITE_FILE,
 961		},
 962		{},
 963	};
 964	const struct rule layer3[] = {
 965		/* Only allows write (but not read) to dir_s1d3. */
 966		{
 967			.path = dir_s1d2,
 968			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
 969		},
 970		{},
 971	};
 972	int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1);
 973
 974	ASSERT_LE(0, ruleset_fd);
 975	enforce_ruleset(_metadata, ruleset_fd);
 976	ASSERT_EQ(0, close(ruleset_fd));
 977
 978	/* Checks s1d1 hierarchy with layer1. */
 979	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
 980	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
 981	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
 982	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
 983
 984	/* Checks s1d2 hierarchy with layer1. */
 985	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
 986	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
 987	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
 988	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
 989
 990	/* Checks s1d3 hierarchy with layer1. */
 991	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
 992	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
 993	/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
 994	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
 995	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
 996
 997	/* Doesn't change anything from layer1. */
 998	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2);
 999	ASSERT_LE(0, ruleset_fd);
1000	enforce_ruleset(_metadata, ruleset_fd);
1001	ASSERT_EQ(0, close(ruleset_fd));
1002
1003	/* Checks s1d1 hierarchy with layer2. */
1004	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1005	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1006	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
1007	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1008
1009	/* Checks s1d2 hierarchy with layer2. */
1010	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
1011	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1012	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1013	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1014
1015	/* Checks s1d3 hierarchy with layer2. */
1016	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1017	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
1018	/* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */
1019	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1020	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1021
1022	/* Only allows write (but not read) to dir_s1d3. */
1023	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3);
1024	ASSERT_LE(0, ruleset_fd);
1025	enforce_ruleset(_metadata, ruleset_fd);
1026	ASSERT_EQ(0, close(ruleset_fd));
1027
1028	/* Checks s1d1 hierarchy with layer3. */
1029	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1030	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1031	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
1032	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1033
1034	/* Checks s1d2 hierarchy with layer3. */
1035	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
1036	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1037	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1038	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1039
1040	/* Checks s1d3 hierarchy with layer3. */
1041	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
1042	ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
1043	/* dir_s1d3 should now deny READ_FILE and WRITE_FILE (O_RDWR). */
1044	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDWR));
1045	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1046}
1047
1048TEST_F_FORK(layout1, non_overlapping_accesses)
1049{
1050	const struct rule layer1[] = {
1051		{
1052			.path = dir_s1d2,
1053			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
1054		},
1055		{},
1056	};
1057	const struct rule layer2[] = {
1058		{
1059			.path = dir_s1d3,
1060			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
1061		},
1062		{},
1063	};
1064	int ruleset_fd;
1065
1066	ASSERT_EQ(0, unlink(file1_s1d1));
1067	ASSERT_EQ(0, unlink(file1_s1d2));
1068
1069	ruleset_fd =
1070		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, layer1);
1071	ASSERT_LE(0, ruleset_fd);
1072	enforce_ruleset(_metadata, ruleset_fd);
1073	ASSERT_EQ(0, close(ruleset_fd));
1074
1075	ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
1076	ASSERT_EQ(EACCES, errno);
1077	ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
1078	ASSERT_EQ(0, unlink(file1_s1d2));
1079
1080	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE,
1081				    layer2);
1082	ASSERT_LE(0, ruleset_fd);
1083	enforce_ruleset(_metadata, ruleset_fd);
1084	ASSERT_EQ(0, close(ruleset_fd));
1085
1086	/* Unchanged accesses for file creation. */
1087	ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
1088	ASSERT_EQ(EACCES, errno);
1089	ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
1090
1091	/* Checks file removing. */
1092	ASSERT_EQ(-1, unlink(file1_s1d2));
1093	ASSERT_EQ(EACCES, errno);
1094	ASSERT_EQ(0, unlink(file1_s1d3));
1095}
1096
1097TEST_F_FORK(layout1, interleaved_masked_accesses)
1098{
1099	/*
1100	 * Checks overly restrictive rules:
1101	 * layer 1: allows R   s1d1/s1d2/s1d3/file1
1102	 * layer 2: allows RW  s1d1/s1d2/s1d3
1103	 *          allows  W  s1d1/s1d2
1104	 *          denies R   s1d1/s1d2
1105	 * layer 3: allows R   s1d1
1106	 * layer 4: allows R   s1d1/s1d2
1107	 *          denies  W  s1d1/s1d2
1108	 * layer 5: allows R   s1d1/s1d2
1109	 * layer 6: allows   X ----
1110	 * layer 7: allows  W  s1d1/s1d2
1111	 *          denies R   s1d1/s1d2
1112	 */
1113	const struct rule layer1_read[] = {
1114		/* Allows read access to file1_s1d3 with the first layer. */
1115		{
1116			.path = file1_s1d3,
1117			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1118		},
1119		{},
1120	};
1121	/* First rule with write restrictions. */
1122	const struct rule layer2_read_write[] = {
1123		/* Start by granting read-write access via its parent directory... */
1124		{
1125			.path = dir_s1d3,
1126			.access = LANDLOCK_ACCESS_FS_READ_FILE |
1127				  LANDLOCK_ACCESS_FS_WRITE_FILE,
1128		},
1129		/* ...but also denies read access via its grandparent directory. */
1130		{
1131			.path = dir_s1d2,
1132			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1133		},
1134		{},
1135	};
1136	const struct rule layer3_read[] = {
1137		/* Allows read access via its great-grandparent directory. */
1138		{
1139			.path = dir_s1d1,
1140			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1141		},
1142		{},
1143	};
1144	const struct rule layer4_read_write[] = {
1145		/*
1146		 * Try to confuse the deny access by denying write (but not
1147		 * read) access via its grandparent directory.
1148		 */
1149		{
1150			.path = dir_s1d2,
1151			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1152		},
1153		{},
1154	};
1155	const struct rule layer5_read[] = {
1156		/*
1157		 * Try to override layer2's deny read access by explicitly
1158		 * allowing read access via file1_s1d3's grandparent.
1159		 */
1160		{
1161			.path = dir_s1d2,
1162			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1163		},
1164		{},
1165	};
1166	const struct rule layer6_execute[] = {
1167		/*
1168		 * Restricts an unrelated file hierarchy with a new access
1169		 * (non-overlapping) type.
1170		 */
1171		{
1172			.path = dir_s2d1,
1173			.access = LANDLOCK_ACCESS_FS_EXECUTE,
1174		},
1175		{},
1176	};
1177	const struct rule layer7_read_write[] = {
1178		/*
1179		 * Finally, denies read access to file1_s1d3 via its
1180		 * grandparent.
1181		 */
1182		{
1183			.path = dir_s1d2,
1184			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
1185		},
1186		{},
1187	};
1188	int ruleset_fd;
1189
1190	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1191				    layer1_read);
1192	ASSERT_LE(0, ruleset_fd);
1193	enforce_ruleset(_metadata, ruleset_fd);
1194	ASSERT_EQ(0, close(ruleset_fd));
1195
1196	/* Checks that read access is granted for file1_s1d3 with layer 1. */
1197	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1198	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1199	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1200
1201	ruleset_fd = create_ruleset(_metadata,
1202				    LANDLOCK_ACCESS_FS_READ_FILE |
1203					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1204				    layer2_read_write);
1205	ASSERT_LE(0, ruleset_fd);
1206	enforce_ruleset(_metadata, ruleset_fd);
1207	ASSERT_EQ(0, close(ruleset_fd));
1208
1209	/* Checks that previous access rights are unchanged with layer 2. */
1210	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1211	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1212	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1213
1214	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1215				    layer3_read);
1216	ASSERT_LE(0, ruleset_fd);
1217	enforce_ruleset(_metadata, ruleset_fd);
1218	ASSERT_EQ(0, close(ruleset_fd));
1219
1220	/* Checks that previous access rights are unchanged with layer 3. */
1221	ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
1222	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1223	ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
1224
1225	/* This time, denies write access for the file hierarchy. */
1226	ruleset_fd = create_ruleset(_metadata,
1227				    LANDLOCK_ACCESS_FS_READ_FILE |
1228					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1229				    layer4_read_write);
1230	ASSERT_LE(0, ruleset_fd);
1231	enforce_ruleset(_metadata, ruleset_fd);
1232	ASSERT_EQ(0, close(ruleset_fd));
1233
1234	/*
1235	 * Checks that the only change with layer 4 is that write access is
1236	 * denied.
1237	 */
1238	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1239	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1240	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1241	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1242
1243	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
1244				    layer5_read);
1245	ASSERT_LE(0, ruleset_fd);
1246	enforce_ruleset(_metadata, ruleset_fd);
1247	ASSERT_EQ(0, close(ruleset_fd));
1248
1249	/* Checks that previous access rights are unchanged with layer 5. */
1250	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1251	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1252	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1253	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1254
1255	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE,
1256				    layer6_execute);
1257	ASSERT_LE(0, ruleset_fd);
1258	enforce_ruleset(_metadata, ruleset_fd);
1259	ASSERT_EQ(0, close(ruleset_fd));
1260
1261	/* Checks that previous access rights are unchanged with layer 6. */
1262	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1263	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1264	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1265	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1266
1267	ruleset_fd = create_ruleset(_metadata,
1268				    LANDLOCK_ACCESS_FS_READ_FILE |
1269					    LANDLOCK_ACCESS_FS_WRITE_FILE,
1270				    layer7_read_write);
1271	ASSERT_LE(0, ruleset_fd);
1272	enforce_ruleset(_metadata, ruleset_fd);
1273	ASSERT_EQ(0, close(ruleset_fd));
1274
1275	/* Checks read access is now denied with layer 7. */
1276	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
1277	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1278	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
1279	ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
1280}
1281
1282TEST_F_FORK(layout1, inherit_subset)
1283{
1284	const struct rule rules[] = {
1285		{
1286			.path = dir_s1d2,
1287			.access = LANDLOCK_ACCESS_FS_READ_FILE |
1288				  LANDLOCK_ACCESS_FS_READ_DIR,
1289		},
1290		{},
1291	};
1292	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1293
1294	ASSERT_LE(0, ruleset_fd);
1295	enforce_ruleset(_metadata, ruleset_fd);
1296
1297	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1298	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1299
1300	/* Write access is forbidden. */
1301	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1302	/* Readdir access is allowed. */
1303	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1304
1305	/* Write access is forbidden. */
1306	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1307	/* Readdir access is allowed. */
1308	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1309
1310	/*
1311	 * Tests shared rule extension: the following rules should not grant
1312	 * any new access, only remove some.  Once enforced, these rules are
1313	 * ANDed with the previous ones.
1314	 */
1315	add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
1316			 dir_s1d2);
1317	/*
1318	 * According to ruleset_fd, dir_s1d2 should now have the
1319	 * LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE
1320	 * access rights (even if this directory is opened a second time).
1321	 * However, when enforcing this updated ruleset, the ruleset tied to
1322	 * the current process (i.e. its domain) will still only have the
1323	 * dir_s1d2 with LANDLOCK_ACCESS_FS_READ_FILE and
1324	 * LANDLOCK_ACCESS_FS_READ_DIR accesses, but
1325	 * LANDLOCK_ACCESS_FS_WRITE_FILE must not be allowed because it would
1326	 * be a privilege escalation.
1327	 */
1328	enforce_ruleset(_metadata, ruleset_fd);
1329
1330	/* Same tests and results as above. */
1331	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1332	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1333
1334	/* It is still forbidden to write in file1_s1d2. */
1335	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1336	/* Readdir access is still allowed. */
1337	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1338
1339	/* It is still forbidden to write in file1_s1d3. */
1340	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1341	/* Readdir access is still allowed. */
1342	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1343
1344	/*
1345	 * Try to get more privileges by adding new access rights to the parent
1346	 * directory: dir_s1d1.
1347	 */
1348	add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1);
1349	enforce_ruleset(_metadata, ruleset_fd);
1350
1351	/* Same tests and results as above. */
1352	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1353	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1354
1355	/* It is still forbidden to write in file1_s1d2. */
1356	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1357	/* Readdir access is still allowed. */
1358	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1359
1360	/* It is still forbidden to write in file1_s1d3. */
1361	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1362	/* Readdir access is still allowed. */
1363	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1364
1365	/*
1366	 * Now, dir_s1d3 get a new rule tied to it, only allowing
1367	 * LANDLOCK_ACCESS_FS_WRITE_FILE.  The (kernel internal) difference is
1368	 * that there was no rule tied to it before.
1369	 */
1370	add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
1371			 dir_s1d3);
1372	enforce_ruleset(_metadata, ruleset_fd);
1373	ASSERT_EQ(0, close(ruleset_fd));
1374
1375	/*
1376	 * Same tests and results as above, except for open(dir_s1d3) which is
1377	 * now denied because the new rule mask the rule previously inherited
1378	 * from dir_s1d2.
1379	 */
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	/*
1393	 * Readdir of dir_s1d3 is still allowed because of the OR policy inside
1394	 * the same layer.
1395	 */
1396	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1397}
1398
1399TEST_F_FORK(layout1, inherit_superset)
1400{
1401	const struct rule rules[] = {
1402		{
1403			.path = dir_s1d3,
1404			.access = ACCESS_RO,
1405		},
1406		{},
1407	};
1408	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1409
1410	ASSERT_LE(0, ruleset_fd);
1411	enforce_ruleset(_metadata, ruleset_fd);
1412
1413	/* Readdir access is denied for dir_s1d2. */
1414	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1415	/* Readdir access is allowed for dir_s1d3. */
1416	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1417	/* File access is allowed for file1_s1d3. */
1418	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1419
1420	/* Now dir_s1d2, parent of dir_s1d3, gets a new rule tied to it. */
1421	add_path_beneath(_metadata, ruleset_fd,
1422			 LANDLOCK_ACCESS_FS_READ_FILE |
1423				 LANDLOCK_ACCESS_FS_READ_DIR,
1424			 dir_s1d2);
1425	enforce_ruleset(_metadata, ruleset_fd);
1426	ASSERT_EQ(0, close(ruleset_fd));
1427
1428	/* Readdir access is still denied for dir_s1d2. */
1429	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1430	/* Readdir access is still allowed for dir_s1d3. */
1431	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1432	/* File access is still allowed for file1_s1d3. */
1433	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1434}
1435
1436TEST_F_FORK(layout0, max_layers)
1437{
1438	int i, err;
1439	const struct rule rules[] = {
1440		{
1441			.path = TMP_DIR,
1442			.access = ACCESS_RO,
1443		},
1444		{},
1445	};
1446	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1447
1448	ASSERT_LE(0, ruleset_fd);
1449	for (i = 0; i < 16; i++)
1450		enforce_ruleset(_metadata, ruleset_fd);
1451
1452	for (i = 0; i < 2; i++) {
1453		err = landlock_restrict_self(ruleset_fd, 0);
1454		ASSERT_EQ(-1, err);
1455		ASSERT_EQ(E2BIG, errno);
1456	}
1457	ASSERT_EQ(0, close(ruleset_fd));
1458}
1459
1460TEST_F_FORK(layout1, empty_or_same_ruleset)
1461{
1462	struct landlock_ruleset_attr ruleset_attr = {};
1463	int ruleset_fd;
1464
1465	/* Tests empty handled_access_fs. */
1466	ruleset_fd =
1467		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1468	ASSERT_LE(-1, ruleset_fd);
1469	ASSERT_EQ(ENOMSG, errno);
1470
1471	/* Enforces policy which deny read access to all files. */
1472	ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE;
1473	ruleset_fd =
1474		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1475	ASSERT_LE(0, ruleset_fd);
1476	enforce_ruleset(_metadata, ruleset_fd);
1477	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1478	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1479
1480	/* Nests a policy which deny read access to all directories. */
1481	ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR;
1482	ruleset_fd =
1483		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
1484	ASSERT_LE(0, ruleset_fd);
1485	enforce_ruleset(_metadata, ruleset_fd);
1486	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1487	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1488
1489	/* Enforces a second time with the same ruleset. */
1490	enforce_ruleset(_metadata, ruleset_fd);
1491	ASSERT_EQ(0, close(ruleset_fd));
1492}
1493
1494TEST_F_FORK(layout1, rule_on_mountpoint)
1495{
1496	const struct rule rules[] = {
1497		{
1498			.path = dir_s1d1,
1499			.access = ACCESS_RO,
1500		},
1501		{
1502			/* dir_s3d2 is a mount point. */
1503			.path = dir_s3d2,
1504			.access = ACCESS_RO,
1505		},
1506		{},
1507	};
1508	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1509
1510	ASSERT_LE(0, ruleset_fd);
1511	enforce_ruleset(_metadata, ruleset_fd);
1512	ASSERT_EQ(0, close(ruleset_fd));
1513
1514	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1515
1516	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1517
1518	ASSERT_EQ(EACCES, test_open(dir_s3d1, O_RDONLY));
1519	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1520	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1521}
1522
1523TEST_F_FORK(layout1, rule_over_mountpoint)
1524{
1525	const struct rule rules[] = {
1526		{
1527			.path = dir_s1d1,
1528			.access = ACCESS_RO,
1529		},
1530		{
1531			/* dir_s3d2 is a mount point. */
1532			.path = dir_s3d1,
1533			.access = ACCESS_RO,
1534		},
1535		{},
1536	};
1537	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1538
1539	ASSERT_LE(0, ruleset_fd);
1540	enforce_ruleset(_metadata, ruleset_fd);
1541	ASSERT_EQ(0, close(ruleset_fd));
1542
1543	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1544
1545	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1546
1547	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
1548	ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1549	ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1550}
1551
1552/*
1553 * This test verifies that we can apply a landlock rule on the root directory
1554 * (which might require special handling).
1555 */
1556TEST_F_FORK(layout1, rule_over_root_allow_then_deny)
1557{
1558	struct rule rules[] = {
1559		{
1560			.path = "/",
1561			.access = ACCESS_RO,
1562		},
1563		{},
1564	};
1565	int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1566
1567	ASSERT_LE(0, ruleset_fd);
1568	enforce_ruleset(_metadata, ruleset_fd);
1569	ASSERT_EQ(0, close(ruleset_fd));
1570
1571	/* Checks allowed access. */
1572	ASSERT_EQ(0, test_open("/", O_RDONLY));
1573	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1574
1575	rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE;
1576	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1577	ASSERT_LE(0, ruleset_fd);
1578	enforce_ruleset(_metadata, ruleset_fd);
1579	ASSERT_EQ(0, close(ruleset_fd));
1580
1581	/* Checks denied access (on a directory). */
1582	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1583	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1584}
1585
1586TEST_F_FORK(layout1, rule_over_root_deny)
1587{
1588	const struct rule rules[] = {
1589		{
1590			.path = "/",
1591			.access = LANDLOCK_ACCESS_FS_READ_FILE,
1592		},
1593		{},
1594	};
1595	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1596
1597	ASSERT_LE(0, ruleset_fd);
1598	enforce_ruleset(_metadata, ruleset_fd);
1599	ASSERT_EQ(0, close(ruleset_fd));
1600
1601	/* Checks denied access (on a directory). */
1602	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1603	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1604}
1605
1606TEST_F_FORK(layout1, rule_inside_mount_ns)
1607{
1608	const struct rule rules[] = {
1609		{
1610			.path = "s3d3",
1611			.access = ACCESS_RO,
1612		},
1613		{},
1614	};
1615	int ruleset_fd;
1616
1617	set_cap(_metadata, CAP_SYS_ADMIN);
1618	ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3))
1619	{
1620		TH_LOG("Failed to pivot root: %s", strerror(errno));
1621	};
1622	ASSERT_EQ(0, chdir("/"));
1623	clear_cap(_metadata, CAP_SYS_ADMIN);
1624
1625	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1626	ASSERT_LE(0, ruleset_fd);
1627	enforce_ruleset(_metadata, ruleset_fd);
1628	ASSERT_EQ(0, close(ruleset_fd));
1629
1630	ASSERT_EQ(0, test_open("s3d3", O_RDONLY));
1631	ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1632}
1633
1634TEST_F_FORK(layout1, mount_and_pivot)
1635{
1636	const struct rule rules[] = {
1637		{
1638			.path = dir_s3d2,
1639			.access = ACCESS_RO,
1640		},
1641		{},
1642	};
1643	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1644
1645	ASSERT_LE(0, ruleset_fd);
1646	enforce_ruleset(_metadata, ruleset_fd);
1647	ASSERT_EQ(0, close(ruleset_fd));
1648
1649	set_cap(_metadata, CAP_SYS_ADMIN);
1650	ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
1651	ASSERT_EQ(EPERM, errno);
1652	ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1653	ASSERT_EQ(EPERM, errno);
1654	clear_cap(_metadata, CAP_SYS_ADMIN);
1655}
1656
1657TEST_F_FORK(layout1, move_mount)
1658{
1659	const struct rule rules[] = {
1660		{
1661			.path = dir_s3d2,
1662			.access = ACCESS_RO,
1663		},
1664		{},
1665	};
1666	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1667
1668	ASSERT_LE(0, ruleset_fd);
1669
1670	set_cap(_metadata, CAP_SYS_ADMIN);
1671	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1672			     dir_s1d2, 0))
1673	{
1674		TH_LOG("Failed to move mount: %s", strerror(errno));
1675	}
1676
1677	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD,
1678			     dir_s3d2, 0));
1679	clear_cap(_metadata, CAP_SYS_ADMIN);
1680
1681	enforce_ruleset(_metadata, ruleset_fd);
1682	ASSERT_EQ(0, close(ruleset_fd));
1683
1684	set_cap(_metadata, CAP_SYS_ADMIN);
1685	ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1686			      dir_s1d2, 0));
1687	ASSERT_EQ(EPERM, errno);
1688	clear_cap(_metadata, CAP_SYS_ADMIN);
1689}
1690
1691TEST_F_FORK(layout1, topology_changes_with_net_only)
1692{
1693	const struct landlock_ruleset_attr ruleset_net = {
1694		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1695				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
1696	};
1697	int ruleset_fd;
1698
1699	/* Add network restrictions. */
1700	ruleset_fd =
1701		landlock_create_ruleset(&ruleset_net, sizeof(ruleset_net), 0);
1702	ASSERT_LE(0, ruleset_fd);
1703	enforce_ruleset(_metadata, ruleset_fd);
1704	ASSERT_EQ(0, close(ruleset_fd));
1705
1706	/* Mount, remount, move_mount, umount, and pivot_root checks. */
1707	set_cap(_metadata, CAP_SYS_ADMIN);
1708	ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s1d2));
1709	ASSERT_EQ(0, mount(NULL, dir_s1d2, NULL, MS_PRIVATE | MS_REC, NULL));
1710	ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD,
1711			     dir_s2d2, 0));
1712	ASSERT_EQ(0, umount(dir_s2d2));
1713	ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1714	ASSERT_EQ(0, chdir("/"));
1715	clear_cap(_metadata, CAP_SYS_ADMIN);
1716}
1717
1718TEST_F_FORK(layout1, topology_changes_with_net_and_fs)
1719{
1720	const struct landlock_ruleset_attr ruleset_net_fs = {
1721		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1722				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
1723		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
1724	};
1725	int ruleset_fd;
1726
1727	/* Add network and filesystem restrictions. */
1728	ruleset_fd = landlock_create_ruleset(&ruleset_net_fs,
1729					     sizeof(ruleset_net_fs), 0);
1730	ASSERT_LE(0, ruleset_fd);
1731	enforce_ruleset(_metadata, ruleset_fd);
1732	ASSERT_EQ(0, close(ruleset_fd));
1733
1734	/* Mount, remount, move_mount, umount, and pivot_root checks. */
1735	set_cap(_metadata, CAP_SYS_ADMIN);
1736	ASSERT_EQ(-1, mount_opt(&mnt_tmp, dir_s1d2));
1737	ASSERT_EQ(EPERM, errno);
1738	ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_PRIVATE | MS_REC, NULL));
1739	ASSERT_EQ(EPERM, errno);
1740	ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1741			      dir_s2d2, 0));
1742	ASSERT_EQ(EPERM, errno);
1743	ASSERT_EQ(-1, umount(dir_s3d2));
1744	ASSERT_EQ(EPERM, errno);
1745	ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3));
1746	ASSERT_EQ(EPERM, errno);
1747	clear_cap(_metadata, CAP_SYS_ADMIN);
1748}
1749
1750TEST_F_FORK(layout1, release_inodes)
1751{
1752	const struct rule rules[] = {
1753		{
1754			.path = dir_s1d1,
1755			.access = ACCESS_RO,
1756		},
1757		{
1758			.path = dir_s3d2,
1759			.access = ACCESS_RO,
1760		},
1761		{
1762			.path = dir_s3d3,
1763			.access = ACCESS_RO,
1764		},
1765		{},
1766	};
1767	const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1768
1769	ASSERT_LE(0, ruleset_fd);
1770	/* Unmount a file hierarchy while it is being used by a ruleset. */
1771	set_cap(_metadata, CAP_SYS_ADMIN);
1772	ASSERT_EQ(0, umount(dir_s3d2));
1773	clear_cap(_metadata, CAP_SYS_ADMIN);
1774
1775	enforce_ruleset(_metadata, ruleset_fd);
1776	ASSERT_EQ(0, close(ruleset_fd));
1777
1778	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
1779	ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY));
1780	/* This dir_s3d3 would not be allowed and does not exist anyway. */
1781	ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY));
1782}
1783
1784enum relative_access {
1785	REL_OPEN,
1786	REL_CHDIR,
1787	REL_CHROOT_ONLY,
1788	REL_CHROOT_CHDIR,
1789};
1790
1791static void test_relative_path(struct __test_metadata *const _metadata,
1792			       const enum relative_access rel)
1793{
1794	/*
1795	 * Common layer to check that chroot doesn't ignore it (i.e. a chroot
1796	 * is not a disconnected root directory).
1797	 */
1798	const struct rule layer1_base[] = {
1799		{
1800			.path = TMP_DIR,
1801			.access = ACCESS_RO,
1802		},
1803		{},
1804	};
1805	const struct rule layer2_subs[] = {
1806		{
1807			.path = dir_s1d2,
1808			.access = ACCESS_RO,
1809		},
1810		{
1811			.path = dir_s2d2,
1812			.access = ACCESS_RO,
1813		},
1814		{},
1815	};
1816	int dirfd, ruleset_fd;
1817
1818	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
1819	ASSERT_LE(0, ruleset_fd);
1820	enforce_ruleset(_metadata, ruleset_fd);
1821	ASSERT_EQ(0, close(ruleset_fd));
1822
1823	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs);
1824
1825	ASSERT_LE(0, ruleset_fd);
1826	switch (rel) {
1827	case REL_OPEN:
1828	case REL_CHDIR:
1829		break;
1830	case REL_CHROOT_ONLY:
1831		ASSERT_EQ(0, chdir(dir_s2d2));
1832		break;
1833	case REL_CHROOT_CHDIR:
1834		ASSERT_EQ(0, chdir(dir_s1d2));
1835		break;
1836	default:
1837		ASSERT_TRUE(false);
1838		return;
1839	}
1840
1841	set_cap(_metadata, CAP_SYS_CHROOT);
1842	enforce_ruleset(_metadata, ruleset_fd);
1843
1844	switch (rel) {
1845	case REL_OPEN:
1846		dirfd = open(dir_s1d2, O_DIRECTORY);
1847		ASSERT_LE(0, dirfd);
1848		break;
1849	case REL_CHDIR:
1850		ASSERT_EQ(0, chdir(dir_s1d2));
1851		dirfd = AT_FDCWD;
1852		break;
1853	case REL_CHROOT_ONLY:
1854		/* Do chroot into dir_s1d2 (relative to dir_s2d2). */
1855		ASSERT_EQ(0, chroot("../../s1d1/s1d2"))
1856		{
1857			TH_LOG("Failed to chroot: %s", strerror(errno));
1858		}
1859		dirfd = AT_FDCWD;
1860		break;
1861	case REL_CHROOT_CHDIR:
1862		/* Do chroot into dir_s1d2. */
1863		ASSERT_EQ(0, chroot("."))
1864		{
1865			TH_LOG("Failed to chroot: %s", strerror(errno));
1866		}
1867		dirfd = AT_FDCWD;
1868		break;
1869	}
1870
1871	ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES,
1872		  test_open_rel(dirfd, "..", O_RDONLY));
1873	ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY));
1874
1875	if (rel == REL_CHROOT_ONLY) {
1876		/* The current directory is dir_s2d2. */
1877		ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY));
1878	} else {
1879		/* The current directory is dir_s1d2. */
1880		ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY));
1881	}
1882
1883	if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) {
1884		/* Checks the root dir_s1d2. */
1885		ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY));
1886		ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY));
1887		ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY));
1888		ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY));
1889	}
1890
1891	if (rel != REL_CHROOT_CHDIR) {
1892		ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY));
1893		ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY));
1894		ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3",
1895					   O_RDONLY));
1896
1897		ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY));
1898		ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY));
1899		ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3",
1900					   O_RDONLY));
1901	}
1902
1903	if (rel == REL_OPEN)
1904		ASSERT_EQ(0, close(dirfd));
1905	ASSERT_EQ(0, close(ruleset_fd));
1906}
1907
1908TEST_F_FORK(layout1, relative_open)
1909{
1910	test_relative_path(_metadata, REL_OPEN);
1911}
1912
1913TEST_F_FORK(layout1, relative_chdir)
1914{
1915	test_relative_path(_metadata, REL_CHDIR);
1916}
1917
1918TEST_F_FORK(layout1, relative_chroot_only)
1919{
1920	test_relative_path(_metadata, REL_CHROOT_ONLY);
1921}
1922
1923TEST_F_FORK(layout1, relative_chroot_chdir)
1924{
1925	test_relative_path(_metadata, REL_CHROOT_CHDIR);
1926}
1927
1928static void copy_binary(struct __test_metadata *const _metadata,
1929			const char *const dst_path)
1930{
1931	int dst_fd, src_fd;
1932	struct stat statbuf;
1933
1934	dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC);
1935	ASSERT_LE(0, dst_fd)
1936	{
1937		TH_LOG("Failed to open \"%s\": %s", dst_path, strerror(errno));
1938	}
1939	src_fd = open(BINARY_PATH, O_RDONLY | O_CLOEXEC);
1940	ASSERT_LE(0, src_fd)
1941	{
1942		TH_LOG("Failed to open \"" BINARY_PATH "\": %s",
1943		       strerror(errno));
1944	}
1945	ASSERT_EQ(0, fstat(src_fd, &statbuf));
1946	ASSERT_EQ(statbuf.st_size,
1947		  sendfile(dst_fd, src_fd, 0, statbuf.st_size));
1948	ASSERT_EQ(0, close(src_fd));
1949	ASSERT_EQ(0, close(dst_fd));
1950}
1951
1952static void test_execute(struct __test_metadata *const _metadata, const int err,
1953			 const char *const path)
1954{
1955	int status;
1956	char *const argv[] = { (char *)path, NULL };
1957	const pid_t child = fork();
1958
1959	ASSERT_LE(0, child);
1960	if (child == 0) {
1961		ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL))
1962		{
1963			TH_LOG("Failed to execute \"%s\": %s", path,
1964			       strerror(errno));
1965		};
1966		ASSERT_EQ(err, errno);
1967		_exit(_metadata->passed ? 2 : 1);
1968		return;
1969	}
1970	ASSERT_EQ(child, waitpid(child, &status, 0));
1971	ASSERT_EQ(1, WIFEXITED(status));
1972	ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status))
1973	{
1974		TH_LOG("Unexpected return code for \"%s\": %s", path,
1975		       strerror(errno));
1976	};
1977}
1978
1979TEST_F_FORK(layout1, execute)
1980{
1981	const struct rule rules[] = {
1982		{
1983			.path = dir_s1d2,
1984			.access = LANDLOCK_ACCESS_FS_EXECUTE,
1985		},
1986		{},
1987	};
1988	const int ruleset_fd =
1989		create_ruleset(_metadata, rules[0].access, rules);
1990
1991	ASSERT_LE(0, ruleset_fd);
1992	copy_binary(_metadata, file1_s1d1);
1993	copy_binary(_metadata, file1_s1d2);
1994	copy_binary(_metadata, file1_s1d3);
1995
1996	enforce_ruleset(_metadata, ruleset_fd);
1997	ASSERT_EQ(0, close(ruleset_fd));
1998
1999	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
2000	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
2001	test_execute(_metadata, EACCES, file1_s1d1);
2002
2003	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
2004	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
2005	test_execute(_metadata, 0, file1_s1d2);
2006
2007	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
2008	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
2009	test_execute(_metadata, 0, file1_s1d3);
2010}
2011
2012TEST_F_FORK(layout1, link)
2013{
2014	const struct rule layer1[] = {
2015		{
2016			.path = dir_s1d2,
2017			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2018		},
2019		{},
2020	};
2021	const struct rule layer2[] = {
2022		{
2023			.path = dir_s1d3,
2024			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2025		},
2026		{},
2027	};
2028	int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
2029
2030	ASSERT_LE(0, ruleset_fd);
2031
2032	ASSERT_EQ(0, unlink(file1_s1d1));
2033	ASSERT_EQ(0, unlink(file1_s1d2));
2034	ASSERT_EQ(0, unlink(file1_s1d3));
2035
2036	enforce_ruleset(_metadata, ruleset_fd);
2037	ASSERT_EQ(0, close(ruleset_fd));
2038
2039	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
2040	ASSERT_EQ(EACCES, errno);
2041
2042	/* Denies linking because of reparenting. */
2043	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
2044	ASSERT_EQ(EXDEV, errno);
2045	ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
2046	ASSERT_EQ(EXDEV, errno);
2047	ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
2048	ASSERT_EQ(EXDEV, errno);
2049
2050	ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
2051	ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
2052
2053	/* Prepares for next unlinks. */
2054	ASSERT_EQ(0, unlink(file2_s1d2));
2055	ASSERT_EQ(0, unlink(file2_s1d3));
2056
2057	ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
2058	ASSERT_LE(0, ruleset_fd);
2059	enforce_ruleset(_metadata, ruleset_fd);
2060	ASSERT_EQ(0, close(ruleset_fd));
2061
2062	/* Checks that linkind doesn't require the ability to delete a file. */
2063	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
2064	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
2065}
2066
2067static int test_rename(const char *const oldpath, const char *const newpath)
2068{
2069	if (rename(oldpath, newpath))
2070		return errno;
2071	return 0;
2072}
2073
2074static int test_exchange(const char *const oldpath, const char *const newpath)
2075{
2076	if (renameat2(AT_FDCWD, oldpath, AT_FDCWD, newpath, RENAME_EXCHANGE))
2077		return errno;
2078	return 0;
2079}
2080
2081TEST_F_FORK(layout1, rename_file)
2082{
2083	const struct rule rules[] = {
2084		{
2085			.path = dir_s1d3,
2086			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2087		},
2088		{
2089			.path = dir_s2d2,
2090			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2091		},
2092		{},
2093	};
2094	const int ruleset_fd =
2095		create_ruleset(_metadata, rules[0].access, rules);
2096
2097	ASSERT_LE(0, ruleset_fd);
2098
2099	ASSERT_EQ(0, unlink(file1_s1d2));
2100
2101	enforce_ruleset(_metadata, ruleset_fd);
2102	ASSERT_EQ(0, close(ruleset_fd));
2103
2104	/*
2105	 * Tries to replace a file, from a directory that allows file removal,
2106	 * but to a different directory (which also allows file removal).
2107	 */
2108	ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3));
2109	ASSERT_EQ(EXDEV, errno);
2110	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3,
2111				RENAME_EXCHANGE));
2112	ASSERT_EQ(EXDEV, errno);
2113	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2114				RENAME_EXCHANGE));
2115	ASSERT_EQ(EXDEV, errno);
2116
2117	/*
2118	 * Tries to replace a file, from a directory that denies file removal,
2119	 * to a different directory (which allows file removal).
2120	 */
2121	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2122	ASSERT_EQ(EACCES, errno);
2123	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3,
2124				RENAME_EXCHANGE));
2125	ASSERT_EQ(EACCES, errno);
2126	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3,
2127				RENAME_EXCHANGE));
2128	ASSERT_EQ(EXDEV, errno);
2129
2130	/* Exchanges files and directories that partially allow removal. */
2131	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1,
2132				RENAME_EXCHANGE));
2133	ASSERT_EQ(EACCES, errno);
2134	/* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */
2135	ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1));
2136	ASSERT_EQ(EACCES, errno);
2137	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2,
2138				RENAME_EXCHANGE));
2139	ASSERT_EQ(EACCES, errno);
2140	/* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */
2141	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2142	ASSERT_EQ(EACCES, errno);
2143
2144	/* Renames files with different parents. */
2145	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2146	ASSERT_EQ(EXDEV, errno);
2147	ASSERT_EQ(0, unlink(file1_s1d3));
2148	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2149	ASSERT_EQ(EACCES, errno);
2150
2151	/* Exchanges and renames files with same parent. */
2152	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3,
2153			       RENAME_EXCHANGE));
2154	ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3));
2155
2156	/* Exchanges files and directories with same parent, twice. */
2157	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2158			       RENAME_EXCHANGE));
2159	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
2160			       RENAME_EXCHANGE));
2161}
2162
2163TEST_F_FORK(layout1, rename_dir)
2164{
2165	const struct rule rules[] = {
2166		{
2167			.path = dir_s1d2,
2168			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2169		},
2170		{
2171			.path = dir_s2d1,
2172			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
2173		},
2174		{},
2175	};
2176	const int ruleset_fd =
2177		create_ruleset(_metadata, rules[0].access, rules);
2178
2179	ASSERT_LE(0, ruleset_fd);
2180
2181	/* Empties dir_s1d3 to allow renaming. */
2182	ASSERT_EQ(0, unlink(file1_s1d3));
2183	ASSERT_EQ(0, unlink(file2_s1d3));
2184
2185	enforce_ruleset(_metadata, ruleset_fd);
2186	ASSERT_EQ(0, close(ruleset_fd));
2187
2188	/* Exchanges and renames directory to a different parent. */
2189	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
2190				RENAME_EXCHANGE));
2191	ASSERT_EQ(EXDEV, errno);
2192	ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3));
2193	ASSERT_EQ(EXDEV, errno);
2194	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
2195				RENAME_EXCHANGE));
2196	ASSERT_EQ(EXDEV, errno);
2197
2198	/*
2199	 * Exchanges directory to the same parent, which doesn't allow
2200	 * directory removal.
2201	 */
2202	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1,
2203				RENAME_EXCHANGE));
2204	ASSERT_EQ(EACCES, errno);
2205	/* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */
2206	ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1));
2207	ASSERT_EQ(EACCES, errno);
2208	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2,
2209				RENAME_EXCHANGE));
2210	ASSERT_EQ(EACCES, errno);
2211	/* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */
2212	ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
2213	ASSERT_EQ(EACCES, errno);
2214
2215	/*
2216	 * Exchanges and renames directory to the same parent, which allows
2217	 * directory removal.
2218	 */
2219	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2,
2220			       RENAME_EXCHANGE));
2221	ASSERT_EQ(0, unlink(dir_s1d3));
2222	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
2223	ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3));
2224	ASSERT_EQ(0, rmdir(dir_s1d3));
2225}
2226
2227TEST_F_FORK(layout1, reparent_refer)
2228{
2229	const struct rule layer1[] = {
2230		{
2231			.path = dir_s1d2,
2232			.access = LANDLOCK_ACCESS_FS_REFER,
2233		},
2234		{
2235			.path = dir_s2d2,
2236			.access = LANDLOCK_ACCESS_FS_REFER,
2237		},
2238		{},
2239	};
2240	int ruleset_fd =
2241		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1);
2242
2243	ASSERT_LE(0, ruleset_fd);
2244	enforce_ruleset(_metadata, ruleset_fd);
2245	ASSERT_EQ(0, close(ruleset_fd));
2246
2247	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d1));
2248	ASSERT_EQ(EXDEV, errno);
2249	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d2));
2250	ASSERT_EQ(EXDEV, errno);
2251	ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3));
2252	ASSERT_EQ(EXDEV, errno);
2253
2254	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d1));
2255	ASSERT_EQ(EXDEV, errno);
2256	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d2));
2257	ASSERT_EQ(EXDEV, errno);
2258	/*
2259	 * Moving should only be allowed when the source and the destination
2260	 * parent directory have REFER.
2261	 */
2262	ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d3));
2263	ASSERT_EQ(ENOTEMPTY, errno);
2264	ASSERT_EQ(0, unlink(file1_s2d3));
2265	ASSERT_EQ(0, unlink(file2_s2d3));
2266	ASSERT_EQ(0, rename(dir_s1d3, dir_s2d3));
2267}
2268
2269/* Checks renames beneath dir_s1d1. */
2270static void refer_denied_by_default(struct __test_metadata *const _metadata,
2271				    const struct rule layer1[],
2272				    const int layer1_err,
2273				    const struct rule layer2[])
2274{
2275	int ruleset_fd;
2276
2277	ASSERT_EQ(0, unlink(file1_s1d2));
2278
2279	ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
2280	ASSERT_LE(0, ruleset_fd);
2281	enforce_ruleset(_metadata, ruleset_fd);
2282	ASSERT_EQ(0, close(ruleset_fd));
2283
2284	/*
2285	 * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to
2286	 * layer1_err), then it allows some different-parent renames and links.
2287	 */
2288	ASSERT_EQ(layer1_err, test_rename(file1_s1d1, file1_s1d2));
2289	if (layer1_err == 0)
2290		ASSERT_EQ(layer1_err, test_rename(file1_s1d2, file1_s1d1));
2291	ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2));
2292	ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1));
2293
2294	ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
2295	ASSERT_LE(0, ruleset_fd);
2296	enforce_ruleset(_metadata, ruleset_fd);
2297	ASSERT_EQ(0, close(ruleset_fd));
2298
2299	/*
2300	 * Now, either the first or the second layer does not handle
2301	 * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent
2302	 * renames and links are denied, thus making the layer handling
2303	 * LANDLOCK_ACCESS_FS_REFER null and void.
2304	 */
2305	ASSERT_EQ(EXDEV, test_rename(file1_s1d1, file1_s1d2));
2306	ASSERT_EQ(EXDEV, test_exchange(file2_s1d1, file2_s1d2));
2307	ASSERT_EQ(EXDEV, test_exchange(file2_s1d2, file2_s1d1));
2308}
2309
2310const struct rule layer_dir_s1d1_refer[] = {
2311	{
2312		.path = dir_s1d1,
2313		.access = LANDLOCK_ACCESS_FS_REFER,
2314	},
2315	{},
2316};
2317
2318const struct rule layer_dir_s1d1_execute[] = {
2319	{
2320		/* Matches a parent directory. */
2321		.path = dir_s1d1,
2322		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2323	},
2324	{},
2325};
2326
2327const struct rule layer_dir_s2d1_execute[] = {
2328	{
2329		/* Does not match a parent directory. */
2330		.path = dir_s2d1,
2331		.access = LANDLOCK_ACCESS_FS_EXECUTE,
2332	},
2333	{},
2334};
2335
2336/*
2337 * Tests precedence over renames: denied by default for different parent
2338 * directories, *with* a rule matching a parent directory, but not directly
2339 * denying access (with MAKE_REG nor REMOVE).
2340 */
2341TEST_F_FORK(layout1, refer_denied_by_default1)
2342{
2343	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2344				layer_dir_s1d1_execute);
2345}
2346
2347/*
2348 * Same test but this time turning around the ABI version order: the first
2349 * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2350 */
2351TEST_F_FORK(layout1, refer_denied_by_default2)
2352{
2353	refer_denied_by_default(_metadata, layer_dir_s1d1_execute, EXDEV,
2354				layer_dir_s1d1_refer);
2355}
2356
2357/*
2358 * Tests precedence over renames: denied by default for different parent
2359 * directories, *without* a rule matching a parent directory, but not directly
2360 * denying access (with MAKE_REG nor REMOVE).
2361 */
2362TEST_F_FORK(layout1, refer_denied_by_default3)
2363{
2364	refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
2365				layer_dir_s2d1_execute);
2366}
2367
2368/*
2369 * Same test but this time turning around the ABI version order: the first
2370 * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2371 */
2372TEST_F_FORK(layout1, refer_denied_by_default4)
2373{
2374	refer_denied_by_default(_metadata, layer_dir_s2d1_execute, EXDEV,
2375				layer_dir_s1d1_refer);
2376}
2377
2378TEST_F_FORK(layout1, reparent_link)
2379{
2380	const struct rule layer1[] = {
2381		{
2382			.path = dir_s1d2,
2383			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2384		},
2385		{
2386			.path = dir_s1d3,
2387			.access = LANDLOCK_ACCESS_FS_REFER,
2388		},
2389		{
2390			.path = dir_s2d2,
2391			.access = LANDLOCK_ACCESS_FS_REFER,
2392		},
2393		{
2394			.path = dir_s2d3,
2395			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2396		},
2397		{},
2398	};
2399	const int ruleset_fd = create_ruleset(
2400		_metadata,
2401		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2402
2403	ASSERT_LE(0, ruleset_fd);
2404	enforce_ruleset(_metadata, ruleset_fd);
2405	ASSERT_EQ(0, close(ruleset_fd));
2406
2407	ASSERT_EQ(0, unlink(file1_s1d1));
2408	ASSERT_EQ(0, unlink(file1_s1d2));
2409	ASSERT_EQ(0, unlink(file1_s1d3));
2410
2411	/* Denies linking because of missing MAKE_REG. */
2412	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
2413	ASSERT_EQ(EACCES, errno);
2414	/* Denies linking because of missing source and destination REFER. */
2415	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
2416	ASSERT_EQ(EXDEV, errno);
2417	/* Denies linking because of missing source REFER. */
2418	ASSERT_EQ(-1, link(file1_s2d1, file1_s1d3));
2419	ASSERT_EQ(EXDEV, errno);
2420
2421	/* Denies linking because of missing MAKE_REG. */
2422	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d1));
2423	ASSERT_EQ(EACCES, errno);
2424	/* Denies linking because of missing destination REFER. */
2425	ASSERT_EQ(-1, link(file1_s2d2, file1_s1d2));
2426	ASSERT_EQ(EXDEV, errno);
2427
2428	/* Allows linking because of REFER and MAKE_REG. */
2429	ASSERT_EQ(0, link(file1_s2d2, file1_s1d3));
2430	ASSERT_EQ(0, unlink(file1_s2d2));
2431	/* Reverse linking denied because of missing MAKE_REG. */
2432	ASSERT_EQ(-1, link(file1_s1d3, file1_s2d2));
2433	ASSERT_EQ(EACCES, errno);
2434	ASSERT_EQ(0, unlink(file1_s2d3));
2435	/* Checks reverse linking. */
2436	ASSERT_EQ(0, link(file1_s1d3, file1_s2d3));
2437	ASSERT_EQ(0, unlink(file1_s1d3));
2438
2439	/*
2440	 * This is OK for a file link, but it should not be allowed for a
2441	 * directory rename (because of the superset of access rights.
2442	 */
2443	ASSERT_EQ(0, link(file1_s2d3, file1_s1d3));
2444	ASSERT_EQ(0, unlink(file1_s1d3));
2445
2446	ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
2447	ASSERT_EQ(EXDEV, errno);
2448	ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
2449	ASSERT_EQ(EXDEV, errno);
2450
2451	ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
2452	ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
2453}
2454
2455TEST_F_FORK(layout1, reparent_rename)
2456{
2457	/* Same rules as for reparent_link. */
2458	const struct rule layer1[] = {
2459		{
2460			.path = dir_s1d2,
2461			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2462		},
2463		{
2464			.path = dir_s1d3,
2465			.access = LANDLOCK_ACCESS_FS_REFER,
2466		},
2467		{
2468			.path = dir_s2d2,
2469			.access = LANDLOCK_ACCESS_FS_REFER,
2470		},
2471		{
2472			.path = dir_s2d3,
2473			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2474		},
2475		{},
2476	};
2477	const int ruleset_fd = create_ruleset(
2478		_metadata,
2479		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2480
2481	ASSERT_LE(0, ruleset_fd);
2482	enforce_ruleset(_metadata, ruleset_fd);
2483	ASSERT_EQ(0, close(ruleset_fd));
2484
2485	ASSERT_EQ(0, unlink(file1_s1d2));
2486	ASSERT_EQ(0, unlink(file1_s1d3));
2487
2488	/* Denies renaming because of missing MAKE_REG. */
2489	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s1d1,
2490				RENAME_EXCHANGE));
2491	ASSERT_EQ(EACCES, errno);
2492	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file2_s1d1,
2493				RENAME_EXCHANGE));
2494	ASSERT_EQ(EACCES, errno);
2495	ASSERT_EQ(0, unlink(file1_s1d1));
2496	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
2497	ASSERT_EQ(EACCES, errno);
2498	/* Even denies same file exchange. */
2499	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file2_s1d1,
2500				RENAME_EXCHANGE));
2501	ASSERT_EQ(EACCES, errno);
2502
2503	/* Denies renaming because of missing source and destination REFER. */
2504	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d2));
2505	ASSERT_EQ(EXDEV, errno);
2506	/*
2507	 * Denies renaming because of missing MAKE_REG, source and destination
2508	 * REFER.
2509	 */
2510	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d1,
2511				RENAME_EXCHANGE));
2512	ASSERT_EQ(EACCES, errno);
2513	ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s2d1,
2514				RENAME_EXCHANGE));
2515	ASSERT_EQ(EACCES, errno);
2516
2517	/* Denies renaming because of missing source REFER. */
2518	ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
2519	ASSERT_EQ(EXDEV, errno);
2520	/* Denies renaming because of missing MAKE_REG. */
2521	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d3,
2522				RENAME_EXCHANGE));
2523	ASSERT_EQ(EACCES, errno);
2524
2525	/* Denies renaming because of missing MAKE_REG. */
2526	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d1));
2527	ASSERT_EQ(EACCES, errno);
2528	/* Denies renaming because of missing destination REFER*/
2529	ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
2530	ASSERT_EQ(EXDEV, errno);
2531
2532	/* Denies exchange because of one missing MAKE_REG. */
2533	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, file2_s1d3,
2534				RENAME_EXCHANGE));
2535	ASSERT_EQ(EACCES, errno);
2536	/* Allows renaming because of REFER and MAKE_REG. */
2537	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d3));
2538
2539	/* Reverse renaming denied because of missing MAKE_REG. */
2540	ASSERT_EQ(-1, rename(file1_s1d3, file1_s2d2));
2541	ASSERT_EQ(EACCES, errno);
2542	ASSERT_EQ(0, unlink(file1_s2d3));
2543	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2544
2545	/* Tests reverse renaming. */
2546	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2547	ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s1d3,
2548			       RENAME_EXCHANGE));
2549	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2550
2551	/*
2552	 * This is OK for a file rename, but it should not be allowed for a
2553	 * directory rename (because of the superset of access rights).
2554	 */
2555	ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3));
2556	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2557
2558	/*
2559	 * Tests superset restrictions applied to directories.  Not only the
2560	 * dir_s2d3's parent (dir_s2d2) should be taken into account but also
2561	 * access rights tied to dir_s2d3. dir_s2d2 is missing one access right
2562	 * compared to dir_s1d3/file1_s1d3 (MAKE_REG) but it is provided
2563	 * directly by the moved dir_s2d3.
2564	 */
2565	ASSERT_EQ(0, rename(dir_s2d3, file1_s1d3));
2566	ASSERT_EQ(0, rename(file1_s1d3, dir_s2d3));
2567	/*
2568	 * The first rename is allowed but not the exchange because dir_s1d3's
2569	 * parent (dir_s1d2) doesn't have REFER.
2570	 */
2571	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
2572				RENAME_EXCHANGE));
2573	ASSERT_EQ(EXDEV, errno);
2574	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s2d3,
2575				RENAME_EXCHANGE));
2576	ASSERT_EQ(EXDEV, errno);
2577	ASSERT_EQ(-1, rename(file1_s2d3, dir_s1d3));
2578	ASSERT_EQ(EXDEV, errno);
2579
2580	ASSERT_EQ(-1, rename(file2_s1d2, file1_s1d3));
2581	ASSERT_EQ(EXDEV, errno);
2582	ASSERT_EQ(-1, rename(file2_s1d3, file1_s1d2));
2583	ASSERT_EQ(EXDEV, errno);
2584
2585	/* Renaming in the same directory is always allowed. */
2586	ASSERT_EQ(0, rename(file2_s1d2, file1_s1d2));
2587	ASSERT_EQ(0, rename(file2_s1d3, file1_s1d3));
2588
2589	ASSERT_EQ(0, unlink(file1_s1d2));
2590	/* Denies because of missing source MAKE_REG and destination REFER. */
2591	ASSERT_EQ(-1, rename(dir_s2d3, file1_s1d2));
2592	ASSERT_EQ(EXDEV, errno);
2593
2594	ASSERT_EQ(0, unlink(file1_s1d3));
2595	/* Denies because of missing source MAKE_REG and REFER. */
2596	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d3));
2597	ASSERT_EQ(EXDEV, errno);
2598}
2599
2600static void
2601reparent_exdev_layers_enforce1(struct __test_metadata *const _metadata)
2602{
2603	const struct rule layer1[] = {
2604		{
2605			.path = dir_s1d2,
2606			.access = LANDLOCK_ACCESS_FS_REFER,
2607		},
2608		{
2609			/* Interesting for the layer2 tests. */
2610			.path = dir_s1d3,
2611			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2612		},
2613		{
2614			.path = dir_s2d2,
2615			.access = LANDLOCK_ACCESS_FS_REFER,
2616		},
2617		{
2618			.path = dir_s2d3,
2619			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
2620		},
2621		{},
2622	};
2623	const int ruleset_fd = create_ruleset(
2624		_metadata,
2625		LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1);
2626
2627	ASSERT_LE(0, ruleset_fd);
2628	enforce_ruleset(_metadata, ruleset_fd);
2629	ASSERT_EQ(0, close(ruleset_fd));
2630}
2631
2632static void
2633reparent_exdev_layers_enforce2(struct __test_metadata *const _metadata)
2634{
2635	const struct rule layer2[] = {
2636		{
2637			.path = dir_s2d3,
2638			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
2639		},
2640		{},
2641	};
2642	/*
2643	 * Same checks as before but with a second layer and a new MAKE_DIR
2644	 * rule (and no explicit handling of REFER).
2645	 */
2646	const int ruleset_fd =
2647		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2);
2648
2649	ASSERT_LE(0, ruleset_fd);
2650	enforce_ruleset(_metadata, ruleset_fd);
2651	ASSERT_EQ(0, close(ruleset_fd));
2652}
2653
2654TEST_F_FORK(layout1, reparent_exdev_layers_rename1)
2655{
2656	ASSERT_EQ(0, unlink(file1_s2d2));
2657	ASSERT_EQ(0, unlink(file1_s2d3));
2658
2659	reparent_exdev_layers_enforce1(_metadata);
2660
2661	/*
2662	 * Moving the dir_s1d3 directory below dir_s2d2 is allowed by Landlock
2663	 * because it doesn't inherit new access rights.
2664	 */
2665	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
2666	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
2667
2668	/*
2669	 * Moving the dir_s1d3 directory below dir_s2d3 is allowed, even if it
2670	 * gets a new inherited access rights (MAKE_REG), because MAKE_REG is
2671	 * already allowed for dir_s1d3.
2672	 */
2673	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d3));
2674	ASSERT_EQ(0, rename(file1_s2d3, dir_s1d3));
2675
2676	/*
2677	 * However, moving the file1_s1d3 file below dir_s2d3 is allowed
2678	 * because it cannot inherit MAKE_REG right (which is dedicated to
2679	 * directories).
2680	 */
2681	ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3));
2682
2683	reparent_exdev_layers_enforce2(_metadata);
2684
2685	/*
2686	 * Moving the dir_s1d3 directory below dir_s2d2 is now denied because
2687	 * MAKE_DIR is not tied to dir_s2d2.
2688	 */
2689	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d2));
2690	ASSERT_EQ(EACCES, errno);
2691
2692	/*
2693	 * Moving the dir_s1d3 directory below dir_s2d3 is forbidden because it
2694	 * would grants MAKE_REG and MAKE_DIR rights to it.
2695	 */
2696	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
2697	ASSERT_EQ(EXDEV, errno);
2698
2699	/*
2700	 * Moving the file2_s1d3 file below dir_s2d3 is denied because the
2701	 * second layer does not handle REFER, which is always denied by
2702	 * default.
2703	 */
2704	ASSERT_EQ(-1, rename(file2_s1d3, file1_s2d3));
2705	ASSERT_EQ(EXDEV, errno);
2706}
2707
2708TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
2709{
2710	reparent_exdev_layers_enforce1(_metadata);
2711
2712	/* Checks EACCES predominance over EXDEV. */
2713	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
2714	ASSERT_EQ(EACCES, errno);
2715	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d2));
2716	ASSERT_EQ(EACCES, errno);
2717	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
2718	ASSERT_EQ(EXDEV, errno);
2719	/* Modify layout! */
2720	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d3));
2721
2722	/* Without REFER source. */
2723	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
2724	ASSERT_EQ(EXDEV, errno);
2725	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
2726	ASSERT_EQ(EXDEV, errno);
2727
2728	reparent_exdev_layers_enforce2(_metadata);
2729
2730	/* Checks EACCES predominance over EXDEV. */
2731	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2));
2732	ASSERT_EQ(EACCES, errno);
2733	/* Checks with actual file2_s1d2. */
2734	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d2));
2735	ASSERT_EQ(EACCES, errno);
2736	ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
2737	ASSERT_EQ(EXDEV, errno);
2738	/*
2739	 * Modifying the layout is now denied because the second layer does not
2740	 * handle REFER, which is always denied by default.
2741	 */
2742	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
2743	ASSERT_EQ(EXDEV, errno);
2744
2745	/* Without REFER source, EACCES wins over EXDEV. */
2746	ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
2747	ASSERT_EQ(EACCES, errno);
2748	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2));
2749	ASSERT_EQ(EACCES, errno);
2750}
2751
2752TEST_F_FORK(layout1, reparent_exdev_layers_exchange1)
2753{
2754	const char *const dir_file1_s1d2 = file1_s1d2, *const dir_file2_s2d3 =
2755							       file2_s2d3;
2756
2757	ASSERT_EQ(0, unlink(file1_s1d2));
2758	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
2759	ASSERT_EQ(0, unlink(file2_s2d3));
2760	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
2761
2762	reparent_exdev_layers_enforce1(_metadata);
2763
2764	/* Error predominance with file exchange: returns EXDEV and EACCES. */
2765	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
2766				RENAME_EXCHANGE));
2767	ASSERT_EQ(EACCES, errno);
2768	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
2769				RENAME_EXCHANGE));
2770	ASSERT_EQ(EACCES, errno);
2771
2772	/*
2773	 * Checks with directories which creation could be allowed, but denied
2774	 * because of access rights that would be inherited.
2775	 */
2776	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
2777				dir_file2_s2d3, RENAME_EXCHANGE));
2778	ASSERT_EQ(EXDEV, errno);
2779	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
2780				dir_file1_s1d2, RENAME_EXCHANGE));
2781	ASSERT_EQ(EXDEV, errno);
2782
2783	/* Checks with same access rights. */
2784	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
2785			       RENAME_EXCHANGE));
2786	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
2787			       RENAME_EXCHANGE));
2788
2789	/* Checks with different (child-only) access rights. */
2790	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
2791			       RENAME_EXCHANGE));
2792	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
2793			       RENAME_EXCHANGE));
2794
2795	/*
2796	 * Checks that exchange between file and directory are consistent.
2797	 *
2798	 * Moving a file (file1_s2d2) to a directory which only grants more
2799	 * directory-related access rights is allowed, and at the same time
2800	 * moving a directory (dir_file2_s2d3) to another directory which
2801	 * grants less access rights is allowed too.
2802	 *
2803	 * See layout1.reparent_exdev_layers_exchange3 for inverted arguments.
2804	 */
2805	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
2806			       RENAME_EXCHANGE));
2807	/*
2808	 * However, moving back the directory is denied because it would get
2809	 * more access rights than the current state and because file creation
2810	 * is forbidden (in dir_s2d2).
2811	 */
2812	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
2813				RENAME_EXCHANGE));
2814	ASSERT_EQ(EACCES, errno);
2815	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
2816				RENAME_EXCHANGE));
2817	ASSERT_EQ(EACCES, errno);
2818
2819	reparent_exdev_layers_enforce2(_metadata);
2820
2821	/* Error predominance with file exchange: returns EXDEV and EACCES. */
2822	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3,
2823				RENAME_EXCHANGE));
2824	ASSERT_EQ(EACCES, errno);
2825	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1,
2826				RENAME_EXCHANGE));
2827	ASSERT_EQ(EACCES, errno);
2828
2829	/* Checks with directories which creation is now denied. */
2830	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD,
2831				dir_file2_s2d3, RENAME_EXCHANGE));
2832	ASSERT_EQ(EACCES, errno);
2833	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD,
2834				dir_file1_s1d2, RENAME_EXCHANGE));
2835	ASSERT_EQ(EACCES, errno);
2836
2837	/* Checks with different (child-only) access rights. */
2838	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3,
2839				RENAME_EXCHANGE));
2840	/* Denied because of MAKE_DIR. */
2841	ASSERT_EQ(EACCES, errno);
2842	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
2843				RENAME_EXCHANGE));
2844	ASSERT_EQ(EACCES, errno);
2845
2846	/* Checks with different (child-only) access rights. */
2847	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2,
2848				RENAME_EXCHANGE));
2849	/* Denied because of MAKE_DIR. */
2850	ASSERT_EQ(EACCES, errno);
2851	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3,
2852				RENAME_EXCHANGE));
2853	ASSERT_EQ(EACCES, errno);
2854
2855	/* See layout1.reparent_exdev_layers_exchange2 for complement. */
2856}
2857
2858TEST_F_FORK(layout1, reparent_exdev_layers_exchange2)
2859{
2860	const char *const dir_file2_s2d3 = file2_s2d3;
2861
2862	ASSERT_EQ(0, unlink(file2_s2d3));
2863	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
2864
2865	reparent_exdev_layers_enforce1(_metadata);
2866	reparent_exdev_layers_enforce2(_metadata);
2867
2868	/* Checks that exchange between file and directory are consistent. */
2869	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
2870				RENAME_EXCHANGE));
2871	ASSERT_EQ(EACCES, errno);
2872	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
2873				RENAME_EXCHANGE));
2874	ASSERT_EQ(EACCES, errno);
2875}
2876
2877TEST_F_FORK(layout1, reparent_exdev_layers_exchange3)
2878{
2879	const char *const dir_file2_s2d3 = file2_s2d3;
2880
2881	ASSERT_EQ(0, unlink(file2_s2d3));
2882	ASSERT_EQ(0, mkdir(file2_s2d3, 0700));
2883
2884	reparent_exdev_layers_enforce1(_metadata);
2885
2886	/*
2887	 * Checks that exchange between file and directory are consistent,
2888	 * including with inverted arguments (see
2889	 * layout1.reparent_exdev_layers_exchange1).
2890	 */
2891	ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
2892			       RENAME_EXCHANGE));
2893	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3,
2894				RENAME_EXCHANGE));
2895	ASSERT_EQ(EACCES, errno);
2896	ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2,
2897				RENAME_EXCHANGE));
2898	ASSERT_EQ(EACCES, errno);
2899}
2900
2901TEST_F_FORK(layout1, reparent_remove)
2902{
2903	const struct rule layer1[] = {
2904		{
2905			.path = dir_s1d1,
2906			.access = LANDLOCK_ACCESS_FS_REFER |
2907				  LANDLOCK_ACCESS_FS_REMOVE_DIR,
2908		},
2909		{
2910			.path = dir_s1d2,
2911			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
2912		},
2913		{
2914			.path = dir_s2d1,
2915			.access = LANDLOCK_ACCESS_FS_REFER |
2916				  LANDLOCK_ACCESS_FS_REMOVE_FILE,
2917		},
2918		{},
2919	};
2920	const int ruleset_fd = create_ruleset(
2921		_metadata,
2922		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR |
2923			LANDLOCK_ACCESS_FS_REMOVE_FILE,
2924		layer1);
2925
2926	ASSERT_LE(0, ruleset_fd);
2927	enforce_ruleset(_metadata, ruleset_fd);
2928	ASSERT_EQ(0, close(ruleset_fd));
2929
2930	/* Access denied because of wrong/swapped remove file/dir. */
2931	ASSERT_EQ(-1, rename(file1_s1d1, dir_s2d2));
2932	ASSERT_EQ(EACCES, errno);
2933	ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d1));
2934	ASSERT_EQ(EACCES, errno);
2935	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d2,
2936				RENAME_EXCHANGE));
2937	ASSERT_EQ(EACCES, errno);
2938	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d3,
2939				RENAME_EXCHANGE));
2940	ASSERT_EQ(EACCES, errno);
2941
2942	/* Access allowed thanks to the matching rights. */
2943	ASSERT_EQ(-1, rename(file1_s2d1, dir_s1d2));
2944	ASSERT_EQ(EISDIR, errno);
2945	ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d1));
2946	ASSERT_EQ(ENOTDIR, errno);
2947	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
2948	ASSERT_EQ(ENOTDIR, errno);
2949	ASSERT_EQ(0, unlink(file1_s2d1));
2950	ASSERT_EQ(0, unlink(file1_s1d3));
2951	ASSERT_EQ(0, unlink(file2_s1d3));
2952	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d1));
2953
2954	/* Effectively removes a file and a directory by exchanging them. */
2955	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
2956	ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
2957			       RENAME_EXCHANGE));
2958	ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
2959				RENAME_EXCHANGE));
2960	ASSERT_EQ(EACCES, errno);
2961}
2962
2963TEST_F_FORK(layout1, reparent_dom_superset)
2964{
2965	const struct rule layer1[] = {
2966		{
2967			.path = dir_s1d2,
2968			.access = LANDLOCK_ACCESS_FS_REFER,
2969		},
2970		{
2971			.path = file1_s1d2,
2972			.access = LANDLOCK_ACCESS_FS_EXECUTE,
2973		},
2974		{
2975			.path = dir_s1d3,
2976			.access = LANDLOCK_ACCESS_FS_MAKE_SOCK |
2977				  LANDLOCK_ACCESS_FS_EXECUTE,
2978		},
2979		{
2980			.path = dir_s2d2,
2981			.access = LANDLOCK_ACCESS_FS_REFER |
2982				  LANDLOCK_ACCESS_FS_EXECUTE |
2983				  LANDLOCK_ACCESS_FS_MAKE_SOCK,
2984		},
2985		{
2986			.path = dir_s2d3,
2987			.access = LANDLOCK_ACCESS_FS_READ_FILE |
2988				  LANDLOCK_ACCESS_FS_MAKE_FIFO,
2989		},
2990		{},
2991	};
2992	int ruleset_fd = create_ruleset(_metadata,
2993					LANDLOCK_ACCESS_FS_REFER |
2994						LANDLOCK_ACCESS_FS_EXECUTE |
2995						LANDLOCK_ACCESS_FS_MAKE_SOCK |
2996						LANDLOCK_ACCESS_FS_READ_FILE |
2997						LANDLOCK_ACCESS_FS_MAKE_FIFO,
2998					layer1);
2999
3000	ASSERT_LE(0, ruleset_fd);
3001	enforce_ruleset(_metadata, ruleset_fd);
3002	ASSERT_EQ(0, close(ruleset_fd));
3003
3004	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d1));
3005	ASSERT_EQ(EXDEV, errno);
3006	/*
3007	 * Moving file1_s1d2 beneath dir_s2d3 would grant it the READ_FILE
3008	 * access right.
3009	 */
3010	ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d3));
3011	ASSERT_EQ(EXDEV, errno);
3012	/*
3013	 * Moving file1_s1d2 should be allowed even if dir_s2d2 grants a
3014	 * superset of access rights compared to dir_s1d2, because file1_s1d2
3015	 * already has these access rights anyway.
3016	 */
3017	ASSERT_EQ(0, rename(file1_s1d2, file1_s2d2));
3018	ASSERT_EQ(0, rename(file1_s2d2, file1_s1d2));
3019
3020	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1));
3021	ASSERT_EQ(EXDEV, errno);
3022	/*
3023	 * Moving dir_s1d3 beneath dir_s2d3 would grant it the MAKE_FIFO access
3024	 * right.
3025	 */
3026	ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3));
3027	ASSERT_EQ(EXDEV, errno);
3028	/*
3029	 * Moving dir_s1d3 should be allowed even if dir_s2d2 grants a superset
3030	 * of access rights compared to dir_s1d2, because dir_s1d3 already has
3031	 * these access rights anyway.
3032	 */
3033	ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2));
3034	ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3));
3035
3036	/*
3037	 * Moving file1_s2d3 beneath dir_s1d2 is allowed, but moving it back
3038	 * will be denied because the new inherited access rights from dir_s1d2
3039	 * will be less than the destination (original) dir_s2d3.  This is a
3040	 * sinkhole scenario where we cannot move back files or directories.
3041	 */
3042	ASSERT_EQ(0, rename(file1_s2d3, file2_s1d2));
3043	ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
3044	ASSERT_EQ(EXDEV, errno);
3045	ASSERT_EQ(0, unlink(file2_s1d2));
3046	ASSERT_EQ(0, unlink(file2_s2d3));
3047	/*
3048	 * Checks similar directory one-way move: dir_s2d3 loses EXECUTE and
3049	 * MAKE_SOCK which were inherited from dir_s1d3.
3050	 */
3051	ASSERT_EQ(0, rename(dir_s2d3, file2_s1d2));
3052	ASSERT_EQ(-1, rename(file2_s1d2, dir_s2d3));
3053	ASSERT_EQ(EXDEV, errno);
3054}
3055
3056TEST_F_FORK(layout1, remove_dir)
3057{
3058	const struct rule rules[] = {
3059		{
3060			.path = dir_s1d2,
3061			.access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
3062		},
3063		{},
3064	};
3065	const int ruleset_fd =
3066		create_ruleset(_metadata, rules[0].access, rules);
3067
3068	ASSERT_LE(0, ruleset_fd);
3069
3070	ASSERT_EQ(0, unlink(file1_s1d1));
3071	ASSERT_EQ(0, unlink(file1_s1d2));
3072	ASSERT_EQ(0, unlink(file1_s1d3));
3073	ASSERT_EQ(0, unlink(file2_s1d3));
3074
3075	enforce_ruleset(_metadata, ruleset_fd);
3076	ASSERT_EQ(0, close(ruleset_fd));
3077
3078	ASSERT_EQ(0, rmdir(dir_s1d3));
3079	ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
3080	ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
3081
3082	/* dir_s1d2 itself cannot be removed. */
3083	ASSERT_EQ(-1, rmdir(dir_s1d2));
3084	ASSERT_EQ(EACCES, errno);
3085	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR));
3086	ASSERT_EQ(EACCES, errno);
3087	ASSERT_EQ(-1, rmdir(dir_s1d1));
3088	ASSERT_EQ(EACCES, errno);
3089	ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR));
3090	ASSERT_EQ(EACCES, errno);
3091}
3092
3093TEST_F_FORK(layout1, remove_file)
3094{
3095	const struct rule rules[] = {
3096		{
3097			.path = dir_s1d2,
3098			.access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
3099		},
3100		{},
3101	};
3102	const int ruleset_fd =
3103		create_ruleset(_metadata, rules[0].access, rules);
3104
3105	ASSERT_LE(0, ruleset_fd);
3106	enforce_ruleset(_metadata, ruleset_fd);
3107	ASSERT_EQ(0, close(ruleset_fd));
3108
3109	ASSERT_EQ(-1, unlink(file1_s1d1));
3110	ASSERT_EQ(EACCES, errno);
3111	ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0));
3112	ASSERT_EQ(EACCES, errno);
3113	ASSERT_EQ(0, unlink(file1_s1d2));
3114	ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0));
3115}
3116
3117static void test_make_file(struct __test_metadata *const _metadata,
3118			   const __u64 access, const mode_t mode,
3119			   const dev_t dev)
3120{
3121	const struct rule rules[] = {
3122		{
3123			.path = dir_s1d2,
3124			.access = access,
3125		},
3126		{},
3127	};
3128	const int ruleset_fd = create_ruleset(_metadata, access, rules);
3129
3130	ASSERT_LE(0, ruleset_fd);
3131
3132	ASSERT_EQ(0, unlink(file1_s1d1));
3133	ASSERT_EQ(0, unlink(file2_s1d1));
3134	ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev))
3135	{
3136		TH_LOG("Failed to make file \"%s\": %s", file2_s1d1,
3137		       strerror(errno));
3138	};
3139
3140	ASSERT_EQ(0, unlink(file1_s1d2));
3141	ASSERT_EQ(0, unlink(file2_s1d2));
3142
3143	ASSERT_EQ(0, unlink(file1_s1d3));
3144	ASSERT_EQ(0, unlink(file2_s1d3));
3145
3146	enforce_ruleset(_metadata, ruleset_fd);
3147	ASSERT_EQ(0, close(ruleset_fd));
3148
3149	ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev));
3150	ASSERT_EQ(EACCES, errno);
3151	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3152	ASSERT_EQ(EACCES, errno);
3153	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3154	ASSERT_EQ(EACCES, errno);
3155
3156	ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev))
3157	{
3158		TH_LOG("Failed to make file \"%s\": %s", file1_s1d2,
3159		       strerror(errno));
3160	};
3161	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3162	ASSERT_EQ(0, unlink(file2_s1d2));
3163	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3164
3165	ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev));
3166	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3167	ASSERT_EQ(0, unlink(file2_s1d3));
3168	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3169}
3170
3171TEST_F_FORK(layout1, make_char)
3172{
3173	/* Creates a /dev/null device. */
3174	set_cap(_metadata, CAP_MKNOD);
3175	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR,
3176		       makedev(1, 3));
3177}
3178
3179TEST_F_FORK(layout1, make_block)
3180{
3181	/* Creates a /dev/loop0 device. */
3182	set_cap(_metadata, CAP_MKNOD);
3183	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK,
3184		       makedev(7, 0));
3185}
3186
3187TEST_F_FORK(layout1, make_reg_1)
3188{
3189	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
3190}
3191
3192TEST_F_FORK(layout1, make_reg_2)
3193{
3194	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
3195}
3196
3197TEST_F_FORK(layout1, make_sock)
3198{
3199	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
3200}
3201
3202TEST_F_FORK(layout1, make_fifo)
3203{
3204	test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
3205}
3206
3207TEST_F_FORK(layout1, make_sym)
3208{
3209	const struct rule rules[] = {
3210		{
3211			.path = dir_s1d2,
3212			.access = LANDLOCK_ACCESS_FS_MAKE_SYM,
3213		},
3214		{},
3215	};
3216	const int ruleset_fd =
3217		create_ruleset(_metadata, rules[0].access, rules);
3218
3219	ASSERT_LE(0, ruleset_fd);
3220
3221	ASSERT_EQ(0, unlink(file1_s1d1));
3222	ASSERT_EQ(0, unlink(file2_s1d1));
3223	ASSERT_EQ(0, symlink("none", file2_s1d1));
3224
3225	ASSERT_EQ(0, unlink(file1_s1d2));
3226	ASSERT_EQ(0, unlink(file2_s1d2));
3227
3228	ASSERT_EQ(0, unlink(file1_s1d3));
3229	ASSERT_EQ(0, unlink(file2_s1d3));
3230
3231	enforce_ruleset(_metadata, ruleset_fd);
3232	ASSERT_EQ(0, close(ruleset_fd));
3233
3234	ASSERT_EQ(-1, symlink("none", file1_s1d1));
3235	ASSERT_EQ(EACCES, errno);
3236	ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
3237	ASSERT_EQ(EACCES, errno);
3238	ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
3239	ASSERT_EQ(EACCES, errno);
3240
3241	ASSERT_EQ(0, symlink("none", file1_s1d2));
3242	ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
3243	ASSERT_EQ(0, unlink(file2_s1d2));
3244	ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
3245
3246	ASSERT_EQ(0, symlink("none", file1_s1d3));
3247	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
3248	ASSERT_EQ(0, unlink(file2_s1d3));
3249	ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
3250}
3251
3252TEST_F_FORK(layout1, make_dir)
3253{
3254	const struct rule rules[] = {
3255		{
3256			.path = dir_s1d2,
3257			.access = LANDLOCK_ACCESS_FS_MAKE_DIR,
3258		},
3259		{},
3260	};
3261	const int ruleset_fd =
3262		create_ruleset(_metadata, rules[0].access, rules);
3263
3264	ASSERT_LE(0, ruleset_fd);
3265
3266	ASSERT_EQ(0, unlink(file1_s1d1));
3267	ASSERT_EQ(0, unlink(file1_s1d2));
3268	ASSERT_EQ(0, unlink(file1_s1d3));
3269
3270	enforce_ruleset(_metadata, ruleset_fd);
3271	ASSERT_EQ(0, close(ruleset_fd));
3272
3273	/* Uses file_* as directory names. */
3274	ASSERT_EQ(-1, mkdir(file1_s1d1, 0700));
3275	ASSERT_EQ(EACCES, errno);
3276	ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
3277	ASSERT_EQ(0, mkdir(file1_s1d3, 0700));
3278}
3279
3280static int open_proc_fd(struct __test_metadata *const _metadata, const int fd,
3281			const int open_flags)
3282{
3283	static const char path_template[] = "/proc/self/fd/%d";
3284	char procfd_path[sizeof(path_template) + 10];
3285	const int procfd_path_size =
3286		snprintf(procfd_path, sizeof(procfd_path), path_template, fd);
3287
3288	ASSERT_LT(procfd_path_size, sizeof(procfd_path));
3289	return open(procfd_path, open_flags);
3290}
3291
3292TEST_F_FORK(layout1, proc_unlinked_file)
3293{
3294	const struct rule rules[] = {
3295		{
3296			.path = file1_s1d2,
3297			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3298		},
3299		{},
3300	};
3301	int reg_fd, proc_fd;
3302	const int ruleset_fd = create_ruleset(
3303		_metadata,
3304		LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE,
3305		rules);
3306
3307	ASSERT_LE(0, ruleset_fd);
3308	enforce_ruleset(_metadata, ruleset_fd);
3309	ASSERT_EQ(0, close(ruleset_fd));
3310
3311	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
3312	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
3313	reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC);
3314	ASSERT_LE(0, reg_fd);
3315	ASSERT_EQ(0, unlink(file1_s1d2));
3316
3317	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC);
3318	ASSERT_LE(0, proc_fd);
3319	ASSERT_EQ(0, close(proc_fd));
3320
3321	proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC);
3322	ASSERT_EQ(-1, proc_fd)
3323	{
3324		TH_LOG("Successfully opened /proc/self/fd/%d: %s", reg_fd,
3325		       strerror(errno));
3326	}
3327	ASSERT_EQ(EACCES, errno);
3328
3329	ASSERT_EQ(0, close(reg_fd));
3330}
3331
3332TEST_F_FORK(layout1, proc_pipe)
3333{
3334	int proc_fd;
3335	int pipe_fds[2];
3336	char buf = '\0';
3337	const struct rule rules[] = {
3338		{
3339			.path = dir_s1d2,
3340			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3341				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3342		},
3343		{},
3344	};
3345	/* Limits read and write access to files tied to the filesystem. */
3346	const int ruleset_fd =
3347		create_ruleset(_metadata, rules[0].access, rules);
3348
3349	ASSERT_LE(0, ruleset_fd);
3350	enforce_ruleset(_metadata, ruleset_fd);
3351	ASSERT_EQ(0, close(ruleset_fd));
3352
3353	/* Checks enforcement for normal files. */
3354	ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
3355	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
3356
3357	/* Checks access to pipes through FD. */
3358	ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC));
3359	ASSERT_EQ(1, write(pipe_fds[1], ".", 1))
3360	{
3361		TH_LOG("Failed to write in pipe: %s", strerror(errno));
3362	}
3363	ASSERT_EQ(1, read(pipe_fds[0], &buf, 1));
3364	ASSERT_EQ('.', buf);
3365
3366	/* Checks write access to pipe through /proc/self/fd . */
3367	proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC);
3368	ASSERT_LE(0, proc_fd);
3369	ASSERT_EQ(1, write(proc_fd, ".", 1))
3370	{
3371		TH_LOG("Failed to write through /proc/self/fd/%d: %s",
3372		       pipe_fds[1], strerror(errno));
3373	}
3374	ASSERT_EQ(0, close(proc_fd));
3375
3376	/* Checks read access to pipe through /proc/self/fd . */
3377	proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC);
3378	ASSERT_LE(0, proc_fd);
3379	buf = '\0';
3380	ASSERT_EQ(1, read(proc_fd, &buf, 1))
3381	{
3382		TH_LOG("Failed to read through /proc/self/fd/%d: %s",
3383		       pipe_fds[1], strerror(errno));
3384	}
3385	ASSERT_EQ(0, close(proc_fd));
3386
3387	ASSERT_EQ(0, close(pipe_fds[0]));
3388	ASSERT_EQ(0, close(pipe_fds[1]));
3389}
3390
3391/* Invokes truncate(2) and returns its errno or 0. */
3392static int test_truncate(const char *const path)
3393{
3394	if (truncate(path, 10) < 0)
3395		return errno;
3396	return 0;
3397}
3398
3399/*
3400 * Invokes creat(2) and returns its errno or 0.
3401 * Closes the opened file descriptor on success.
3402 */
3403static int test_creat(const char *const path)
3404{
3405	int fd = creat(path, 0600);
3406
3407	if (fd < 0)
3408		return errno;
3409
3410	/*
3411	 * Mixing error codes from close(2) and creat(2) should not lead to any
3412	 * (access type) confusion for this test.
3413	 */
3414	if (close(fd) < 0)
3415		return errno;
3416	return 0;
3417}
3418
3419/*
3420 * Exercises file truncation when it's not restricted,
3421 * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed.
3422 */
3423TEST_F_FORK(layout1, truncate_unhandled)
3424{
3425	const char *const file_r = file1_s1d1;
3426	const char *const file_w = file2_s1d1;
3427	const char *const file_none = file1_s1d2;
3428	const struct rule rules[] = {
3429		{
3430			.path = file_r,
3431			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3432		},
3433		{
3434			.path = file_w,
3435			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3436		},
3437		/* Implicitly: No rights for file_none. */
3438		{},
3439	};
3440
3441	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3442			      LANDLOCK_ACCESS_FS_WRITE_FILE;
3443	int ruleset_fd;
3444
3445	/* Enable Landlock. */
3446	ruleset_fd = create_ruleset(_metadata, handled, rules);
3447
3448	ASSERT_LE(0, ruleset_fd);
3449	enforce_ruleset(_metadata, ruleset_fd);
3450	ASSERT_EQ(0, close(ruleset_fd));
3451
3452	/*
3453	 * Checks read right: truncate and open with O_TRUNC work, unless the
3454	 * file is attempted to be opened for writing.
3455	 */
3456	EXPECT_EQ(0, test_truncate(file_r));
3457	EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC));
3458	EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC));
3459	EXPECT_EQ(EACCES, test_creat(file_r));
3460
3461	/*
3462	 * Checks write right: truncate and open with O_TRUNC work, unless the
3463	 * file is attempted to be opened for reading.
3464	 */
3465	EXPECT_EQ(0, test_truncate(file_w));
3466	EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC));
3467	EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC));
3468	EXPECT_EQ(0, test_creat(file_w));
3469
3470	/*
3471	 * Checks "no rights" case: truncate works but all open attempts fail,
3472	 * including creat.
3473	 */
3474	EXPECT_EQ(0, test_truncate(file_none));
3475	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3476	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3477	EXPECT_EQ(EACCES, test_creat(file_none));
3478}
3479
3480TEST_F_FORK(layout1, truncate)
3481{
3482	const char *const file_rwt = file1_s1d1;
3483	const char *const file_rw = file2_s1d1;
3484	const char *const file_rt = file1_s1d2;
3485	const char *const file_t = file2_s1d2;
3486	const char *const file_none = file1_s1d3;
3487	const char *const dir_t = dir_s2d1;
3488	const char *const file_in_dir_t = file1_s2d1;
3489	const char *const dir_w = dir_s3d1;
3490	const char *const file_in_dir_w = file1_s3d1;
3491	const struct rule rules[] = {
3492		{
3493			.path = file_rwt,
3494			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3495				  LANDLOCK_ACCESS_FS_WRITE_FILE |
3496				  LANDLOCK_ACCESS_FS_TRUNCATE,
3497		},
3498		{
3499			.path = file_rw,
3500			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3501				  LANDLOCK_ACCESS_FS_WRITE_FILE,
3502		},
3503		{
3504			.path = file_rt,
3505			.access = LANDLOCK_ACCESS_FS_READ_FILE |
3506				  LANDLOCK_ACCESS_FS_TRUNCATE,
3507		},
3508		{
3509			.path = file_t,
3510			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3511		},
3512		/* Implicitly: No access rights for file_none. */
3513		{
3514			.path = dir_t,
3515			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3516		},
3517		{
3518			.path = dir_w,
3519			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3520		},
3521		{},
3522	};
3523	const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
3524			      LANDLOCK_ACCESS_FS_WRITE_FILE |
3525			      LANDLOCK_ACCESS_FS_TRUNCATE;
3526	int ruleset_fd;
3527
3528	/* Enable Landlock. */
3529	ruleset_fd = create_ruleset(_metadata, handled, rules);
3530
3531	ASSERT_LE(0, ruleset_fd);
3532	enforce_ruleset(_metadata, ruleset_fd);
3533	ASSERT_EQ(0, close(ruleset_fd));
3534
3535	/* Checks read, write and truncate rights: truncation works. */
3536	EXPECT_EQ(0, test_truncate(file_rwt));
3537	EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC));
3538	EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC));
3539
3540	/* Checks read and write rights: no truncate variant works. */
3541	EXPECT_EQ(EACCES, test_truncate(file_rw));
3542	EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC));
3543	EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC));
3544
3545	/*
3546	 * Checks read and truncate rights: truncation works.
3547	 *
3548	 * Note: Files can get truncated using open() even with O_RDONLY.
3549	 */
3550	EXPECT_EQ(0, test_truncate(file_rt));
3551	EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC));
3552	EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC));
3553
3554	/* Checks truncate right: truncate works, but can't open file. */
3555	EXPECT_EQ(0, test_truncate(file_t));
3556	EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC));
3557	EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC));
3558
3559	/* Checks "no rights" case: No form of truncation works. */
3560	EXPECT_EQ(EACCES, test_truncate(file_none));
3561	EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC));
3562	EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC));
3563
3564	/*
3565	 * Checks truncate right on directory: truncate works on contained
3566	 * files.
3567	 */
3568	EXPECT_EQ(0, test_truncate(file_in_dir_t));
3569	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC));
3570	EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC));
3571
3572	/*
3573	 * Checks creat in dir_w: This requires the truncate right when
3574	 * overwriting an existing file, but does not require it when the file
3575	 * is new.
3576	 */
3577	EXPECT_EQ(EACCES, test_creat(file_in_dir_w));
3578
3579	ASSERT_EQ(0, unlink(file_in_dir_w));
3580	EXPECT_EQ(0, test_creat(file_in_dir_w));
3581}
3582
3583/* Invokes ftruncate(2) and returns its errno or 0. */
3584static int test_ftruncate(int fd)
3585{
3586	if (ftruncate(fd, 10) < 0)
3587		return errno;
3588	return 0;
3589}
3590
3591TEST_F_FORK(layout1, ftruncate)
3592{
3593	/*
3594	 * This test opens a new file descriptor at different stages of
3595	 * Landlock restriction:
3596	 *
3597	 * without restriction:                    ftruncate works
3598	 * something else but truncate restricted: ftruncate works
3599	 * truncate restricted and permitted:      ftruncate works
3600	 * truncate restricted and not permitted:  ftruncate fails
3601	 *
3602	 * Whether this works or not is expected to depend on the time when the
3603	 * FD was opened, not to depend on the time when ftruncate() was
3604	 * called.
3605	 */
3606	const char *const path = file1_s1d1;
3607	const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE |
3608			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3609	const struct rule layer1[] = {
3610		{
3611			.path = path,
3612			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3613		},
3614		{},
3615	};
3616	const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE;
3617	const struct rule layer2[] = {
3618		{
3619			.path = path,
3620			.access = LANDLOCK_ACCESS_FS_TRUNCATE,
3621		},
3622		{},
3623	};
3624	const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE |
3625			       LANDLOCK_ACCESS_FS_WRITE_FILE;
3626	const struct rule layer3[] = {
3627		{
3628			.path = path,
3629			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3630		},
3631		{},
3632	};
3633	int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd;
3634
3635	fd_layer0 = open(path, O_WRONLY);
3636	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3637
3638	ruleset_fd = create_ruleset(_metadata, handled1, layer1);
3639	ASSERT_LE(0, ruleset_fd);
3640	enforce_ruleset(_metadata, ruleset_fd);
3641	ASSERT_EQ(0, close(ruleset_fd));
3642
3643	fd_layer1 = open(path, O_WRONLY);
3644	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3645	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3646
3647	ruleset_fd = create_ruleset(_metadata, handled2, layer2);
3648	ASSERT_LE(0, ruleset_fd);
3649	enforce_ruleset(_metadata, ruleset_fd);
3650	ASSERT_EQ(0, close(ruleset_fd));
3651
3652	fd_layer2 = open(path, O_WRONLY);
3653	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3654	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3655	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3656
3657	ruleset_fd = create_ruleset(_metadata, handled3, layer3);
3658	ASSERT_LE(0, ruleset_fd);
3659	enforce_ruleset(_metadata, ruleset_fd);
3660	ASSERT_EQ(0, close(ruleset_fd));
3661
3662	fd_layer3 = open(path, O_WRONLY);
3663	EXPECT_EQ(0, test_ftruncate(fd_layer0));
3664	EXPECT_EQ(0, test_ftruncate(fd_layer1));
3665	EXPECT_EQ(0, test_ftruncate(fd_layer2));
3666	EXPECT_EQ(EACCES, test_ftruncate(fd_layer3));
3667
3668	ASSERT_EQ(0, close(fd_layer0));
3669	ASSERT_EQ(0, close(fd_layer1));
3670	ASSERT_EQ(0, close(fd_layer2));
3671	ASSERT_EQ(0, close(fd_layer3));
3672}
3673
3674/* clang-format off */
3675FIXTURE(ftruncate) {};
3676/* clang-format on */
3677
3678FIXTURE_SETUP(ftruncate)
3679{
3680	prepare_layout(_metadata);
3681	create_file(_metadata, file1_s1d1);
3682}
3683
3684FIXTURE_TEARDOWN(ftruncate)
3685{
3686	EXPECT_EQ(0, remove_path(file1_s1d1));
3687	cleanup_layout(_metadata);
3688}
3689
3690FIXTURE_VARIANT(ftruncate)
3691{
3692	const __u64 handled;
3693	const __u64 allowed;
3694	const int expected_open_result;
3695	const int expected_ftruncate_result;
3696};
3697
3698/* clang-format off */
3699FIXTURE_VARIANT_ADD(ftruncate, w_w) {
3700	/* clang-format on */
3701	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE,
3702	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
3703	.expected_open_result = 0,
3704	.expected_ftruncate_result = 0,
3705};
3706
3707/* clang-format off */
3708FIXTURE_VARIANT_ADD(ftruncate, t_t) {
3709	/* clang-format on */
3710	.handled = LANDLOCK_ACCESS_FS_TRUNCATE,
3711	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
3712	.expected_open_result = 0,
3713	.expected_ftruncate_result = 0,
3714};
3715
3716/* clang-format off */
3717FIXTURE_VARIANT_ADD(ftruncate, wt_w) {
3718	/* clang-format on */
3719	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3720	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE,
3721	.expected_open_result = 0,
3722	.expected_ftruncate_result = EACCES,
3723};
3724
3725/* clang-format off */
3726FIXTURE_VARIANT_ADD(ftruncate, wt_wt) {
3727	/* clang-format on */
3728	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3729	.allowed = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3730	.expected_open_result = 0,
3731	.expected_ftruncate_result = 0,
3732};
3733
3734/* clang-format off */
3735FIXTURE_VARIANT_ADD(ftruncate, wt_t) {
3736	/* clang-format on */
3737	.handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE,
3738	.allowed = LANDLOCK_ACCESS_FS_TRUNCATE,
3739	.expected_open_result = EACCES,
3740};
3741
3742TEST_F_FORK(ftruncate, open_and_ftruncate)
3743{
3744	const char *const path = file1_s1d1;
3745	const struct rule rules[] = {
3746		{
3747			.path = path,
3748			.access = variant->allowed,
3749		},
3750		{},
3751	};
3752	int fd, ruleset_fd;
3753
3754	/* Enable Landlock. */
3755	ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
3756	ASSERT_LE(0, ruleset_fd);
3757	enforce_ruleset(_metadata, ruleset_fd);
3758	ASSERT_EQ(0, close(ruleset_fd));
3759
3760	fd = open(path, O_WRONLY);
3761	EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
3762	if (fd >= 0) {
3763		EXPECT_EQ(variant->expected_ftruncate_result,
3764			  test_ftruncate(fd));
3765		ASSERT_EQ(0, close(fd));
3766	}
3767}
3768
3769TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
3770{
3771	int child, fd, status;
3772	int socket_fds[2];
3773
3774	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
3775				socket_fds));
3776
3777	child = fork();
3778	ASSERT_LE(0, child);
3779	if (child == 0) {
3780		/*
3781		 * Enables Landlock in the child process, open a file descriptor
3782		 * where truncation is forbidden and send it to the
3783		 * non-landlocked parent process.
3784		 */
3785		const char *const path = file1_s1d1;
3786		const struct rule rules[] = {
3787			{
3788				.path = path,
3789				.access = variant->allowed,
3790			},
3791			{},
3792		};
3793		int fd, ruleset_fd;
3794
3795		ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
3796		ASSERT_LE(0, ruleset_fd);
3797		enforce_ruleset(_metadata, ruleset_fd);
3798		ASSERT_EQ(0, close(ruleset_fd));
3799
3800		fd = open(path, O_WRONLY);
3801		ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0));
3802
3803		if (fd >= 0) {
3804			ASSERT_EQ(0, send_fd(socket_fds[0], fd));
3805			ASSERT_EQ(0, close(fd));
3806		}
3807
3808		ASSERT_EQ(0, close(socket_fds[0]));
3809
3810		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
3811		return;
3812	}
3813
3814	if (variant->expected_open_result == 0) {
3815		fd = recv_fd(socket_fds[1]);
3816		ASSERT_LE(0, fd);
3817
3818		EXPECT_EQ(variant->expected_ftruncate_result,
3819			  test_ftruncate(fd));
3820		ASSERT_EQ(0, close(fd));
3821	}
3822
3823	ASSERT_EQ(child, waitpid(child, &status, 0));
3824	ASSERT_EQ(1, WIFEXITED(status));
3825	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
3826
3827	ASSERT_EQ(0, close(socket_fds[0]));
3828	ASSERT_EQ(0, close(socket_fds[1]));
3829}
3830
3831TEST(memfd_ftruncate)
3832{
3833	int fd;
3834
3835	fd = memfd_create("name", MFD_CLOEXEC);
3836	ASSERT_LE(0, fd);
3837
3838	/*
3839	 * Checks that ftruncate is permitted on file descriptors that are
3840	 * created in ways other than open(2).
3841	 */
3842	EXPECT_EQ(0, test_ftruncate(fd));
3843
3844	ASSERT_EQ(0, close(fd));
3845}
3846
3847/* clang-format off */
3848FIXTURE(layout1_bind) {};
3849/* clang-format on */
3850
3851FIXTURE_SETUP(layout1_bind)
3852{
3853	prepare_layout(_metadata);
3854
3855	create_layout1(_metadata);
3856
3857	set_cap(_metadata, CAP_SYS_ADMIN);
3858	ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL));
3859	clear_cap(_metadata, CAP_SYS_ADMIN);
3860}
3861
3862FIXTURE_TEARDOWN(layout1_bind)
3863{
3864	set_cap(_metadata, CAP_SYS_ADMIN);
3865	EXPECT_EQ(0, umount(dir_s2d2));
3866	clear_cap(_metadata, CAP_SYS_ADMIN);
3867
3868	remove_layout1(_metadata);
3869
3870	cleanup_layout(_metadata);
3871}
3872
3873static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
3874static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
3875
3876/*
3877 * layout1_bind hierarchy:
3878 *
3879 * tmp
3880 * ├── s1d1
3881 * │   ├── f1
3882 * │   ├── f2
3883 * │   └── s1d2
3884 * │       ├── f1
3885 * │       ├── f2
3886 * │       └── s1d3
3887 * │           ├── f1
3888 * │           └── f2
3889 * ├── s2d1
3890 * │   ├── f1
3891 * │   └── s2d2
3892 * │       ├── f1
3893 * │       ├── f2
3894 * │       └── s1d3
3895 * │           ├── f1
3896 * │           └── f2
3897 * └── s3d1
3898 *     └── s3d2
3899 *         └── s3d3
3900 */
3901
3902TEST_F_FORK(layout1_bind, no_restriction)
3903{
3904	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
3905	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
3906	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
3907	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
3908	ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
3909	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
3910
3911	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
3912	ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
3913	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
3914	ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
3915	ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY));
3916	ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY));
3917
3918	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY));
3919	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
3920
3921	ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
3922}
3923
3924TEST_F_FORK(layout1_bind, same_content_same_file)
3925{
3926	/*
3927	 * Sets access right on parent directories of both source and
3928	 * destination mount points.
3929	 */
3930	const struct rule layer1_parent[] = {
3931		{
3932			.path = dir_s1d1,
3933			.access = ACCESS_RO,
3934		},
3935		{
3936			.path = dir_s2d1,
3937			.access = ACCESS_RW,
3938		},
3939		{},
3940	};
3941	/*
3942	 * Sets access rights on the same bind-mounted directories.  The result
3943	 * should be ACCESS_RW for both directories, but not both hierarchies
3944	 * because of the first layer.
3945	 */
3946	const struct rule layer2_mount_point[] = {
3947		{
3948			.path = dir_s1d2,
3949			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3950		},
3951		{
3952			.path = dir_s2d2,
3953			.access = ACCESS_RW,
3954		},
3955		{},
3956	};
3957	/* Only allow read-access to the s1d3 hierarchies. */
3958	const struct rule layer3_source[] = {
3959		{
3960			.path = dir_s1d3,
3961			.access = LANDLOCK_ACCESS_FS_READ_FILE,
3962		},
3963		{},
3964	};
3965	/* Removes all access rights. */
3966	const struct rule layer4_destination[] = {
3967		{
3968			.path = bind_file1_s1d3,
3969			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
3970		},
3971		{},
3972	};
3973	int ruleset_fd;
3974
3975	/* Sets rules for the parent directories. */
3976	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent);
3977	ASSERT_LE(0, ruleset_fd);
3978	enforce_ruleset(_metadata, ruleset_fd);
3979	ASSERT_EQ(0, close(ruleset_fd));
3980
3981	/* Checks source hierarchy. */
3982	ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
3983	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
3984	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
3985
3986	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
3987	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
3988	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
3989
3990	/* Checks destination hierarchy. */
3991	ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR));
3992	ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
3993
3994	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
3995	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
3996
3997	/* Sets rules for the mount points. */
3998	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point);
3999	ASSERT_LE(0, ruleset_fd);
4000	enforce_ruleset(_metadata, ruleset_fd);
4001	ASSERT_EQ(0, close(ruleset_fd));
4002
4003	/* Checks source hierarchy. */
4004	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
4005	ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
4006	ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
4007
4008	ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
4009	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4010	ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4011
4012	/* Checks destination hierarchy. */
4013	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY));
4014	ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY));
4015	ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
4016
4017	ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
4018	ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4019	ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4020
4021	/* Sets a (shared) rule only on the source. */
4022	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source);
4023	ASSERT_LE(0, ruleset_fd);
4024	enforce_ruleset(_metadata, ruleset_fd);
4025	ASSERT_EQ(0, close(ruleset_fd));
4026
4027	/* Checks source hierarchy. */
4028	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
4029	ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
4030	ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
4031
4032	ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
4033	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4034	ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
4035
4036	/* Checks destination hierarchy. */
4037	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY));
4038	ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY));
4039	ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
4040
4041	ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
4042	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4043	ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
4044
4045	/* Sets a (shared) rule only on the destination. */
4046	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination);
4047	ASSERT_LE(0, ruleset_fd);
4048	enforce_ruleset(_metadata, ruleset_fd);
4049	ASSERT_EQ(0, close(ruleset_fd));
4050
4051	/* Checks source hierarchy. */
4052	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
4053	ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
4054
4055	/* Checks destination hierarchy. */
4056	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY));
4057	ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
4058}
4059
4060TEST_F_FORK(layout1_bind, reparent_cross_mount)
4061{
4062	const struct rule layer1[] = {
4063		{
4064			/* dir_s2d1 is beneath the dir_s2d2 mount point. */
4065			.path = dir_s2d1,
4066			.access = LANDLOCK_ACCESS_FS_REFER,
4067		},
4068		{
4069			.path = bind_dir_s1d3,
4070			.access = LANDLOCK_ACCESS_FS_EXECUTE,
4071		},
4072		{},
4073	};
4074	int ruleset_fd = create_ruleset(
4075		_metadata,
4076		LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1);
4077
4078	ASSERT_LE(0, ruleset_fd);
4079	enforce_ruleset(_metadata, ruleset_fd);
4080	ASSERT_EQ(0, close(ruleset_fd));
4081
4082	/* Checks basic denied move. */
4083	ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2));
4084	ASSERT_EQ(EXDEV, errno);
4085
4086	/* Checks real cross-mount move (Landlock is not involved). */
4087	ASSERT_EQ(-1, rename(file1_s2d1, file1_s2d2));
4088	ASSERT_EQ(EXDEV, errno);
4089
4090	/* Checks move that will give more accesses. */
4091	ASSERT_EQ(-1, rename(file1_s2d2, bind_file1_s1d3));
4092	ASSERT_EQ(EXDEV, errno);
4093
4094	/* Checks legitimate downgrade move. */
4095	ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2));
4096}
4097
4098#define LOWER_BASE TMP_DIR "/lower"
4099#define LOWER_DATA LOWER_BASE "/data"
4100static const char lower_fl1[] = LOWER_DATA "/fl1";
4101static const char lower_dl1[] = LOWER_DATA "/dl1";
4102static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
4103static const char lower_fo1[] = LOWER_DATA "/fo1";
4104static const char lower_do1[] = LOWER_DATA "/do1";
4105static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
4106static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
4107
4108static const char (*lower_base_files[])[] = {
4109	&lower_fl1,
4110	&lower_fo1,
4111	NULL,
4112};
4113static const char (*lower_base_directories[])[] = {
4114	&lower_dl1,
4115	&lower_do1,
4116	NULL,
4117};
4118static const char (*lower_sub_files[])[] = {
4119	&lower_dl1_fl2,
4120	&lower_do1_fo2,
4121	&lower_do1_fl3,
4122	NULL,
4123};
4124
4125#define UPPER_BASE TMP_DIR "/upper"
4126#define UPPER_DATA UPPER_BASE "/data"
4127#define UPPER_WORK UPPER_BASE "/work"
4128static const char upper_fu1[] = UPPER_DATA "/fu1";
4129static const char upper_du1[] = UPPER_DATA "/du1";
4130static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
4131static const char upper_fo1[] = UPPER_DATA "/fo1";
4132static const char upper_do1[] = UPPER_DATA "/do1";
4133static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
4134static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
4135
4136static const char (*upper_base_files[])[] = {
4137	&upper_fu1,
4138	&upper_fo1,
4139	NULL,
4140};
4141static const char (*upper_base_directories[])[] = {
4142	&upper_du1,
4143	&upper_do1,
4144	NULL,
4145};
4146static const char (*upper_sub_files[])[] = {
4147	&upper_du1_fu2,
4148	&upper_do1_fo2,
4149	&upper_do1_fu3,
4150	NULL,
4151};
4152
4153#define MERGE_BASE TMP_DIR "/merge"
4154#define MERGE_DATA MERGE_BASE "/data"
4155static const char merge_fl1[] = MERGE_DATA "/fl1";
4156static const char merge_dl1[] = MERGE_DATA "/dl1";
4157static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
4158static const char merge_fu1[] = MERGE_DATA "/fu1";
4159static const char merge_du1[] = MERGE_DATA "/du1";
4160static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
4161static const char merge_fo1[] = MERGE_DATA "/fo1";
4162static const char merge_do1[] = MERGE_DATA "/do1";
4163static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
4164static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
4165static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
4166
4167static const char (*merge_base_files[])[] = {
4168	&merge_fl1,
4169	&merge_fu1,
4170	&merge_fo1,
4171	NULL,
4172};
4173static const char (*merge_base_directories[])[] = {
4174	&merge_dl1,
4175	&merge_du1,
4176	&merge_do1,
4177	NULL,
4178};
4179static const char (*merge_sub_files[])[] = {
4180	&merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2,
4181	&merge_do1_fl3, &merge_do1_fu3, NULL,
4182};
4183
4184/*
4185 * layout2_overlay hierarchy:
4186 *
4187 * tmp
4188 * ├── lower
4189 * │   └── data
4190 * │       ├── dl1
4191 * │       │   └── fl2
4192 * │       ├── do1
4193 * │       │   ├── fl3
4194 * │       │   └── fo2
4195 * │       ├── fl1
4196 * │       └── fo1
4197 * ├── merge
4198 * │   └── data
4199 * │       ├── dl1
4200 * │       │   └── fl2
4201 * │       ├── do1
4202 * │       │   ├── fl3
4203 * │       │   ├── fo2
4204 * │       │   └── fu3
4205 * │       ├── du1
4206 * │       │   └── fu2
4207 * │       ├── fl1
4208 * │       ├── fo1
4209 * │       └── fu1
4210 * └── upper
4211 *     ├── data
4212 *     │   ├── do1
4213 *     │   │   ├── fo2
4214 *     │   │   └── fu3
4215 *     │   ├── du1
4216 *     │   │   └── fu2
4217 *     │   ├── fo1
4218 *     │   └── fu1
4219 *     └── work
4220 *         └── work
4221 */
4222
4223FIXTURE(layout2_overlay)
4224{
4225	bool skip_test;
4226};
4227
4228FIXTURE_SETUP(layout2_overlay)
4229{
4230	if (!supports_filesystem("overlay")) {
4231		self->skip_test = true;
4232		SKIP(return, "overlayfs is not supported (setup)");
4233	}
4234
4235	prepare_layout(_metadata);
4236
4237	create_directory(_metadata, LOWER_BASE);
4238	set_cap(_metadata, CAP_SYS_ADMIN);
4239	/* Creates tmpfs mount points to get deterministic overlayfs. */
4240	ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE));
4241	clear_cap(_metadata, CAP_SYS_ADMIN);
4242	create_file(_metadata, lower_fl1);
4243	create_file(_metadata, lower_dl1_fl2);
4244	create_file(_metadata, lower_fo1);
4245	create_file(_metadata, lower_do1_fo2);
4246	create_file(_metadata, lower_do1_fl3);
4247
4248	create_directory(_metadata, UPPER_BASE);
4249	set_cap(_metadata, CAP_SYS_ADMIN);
4250	ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE));
4251	clear_cap(_metadata, CAP_SYS_ADMIN);
4252	create_file(_metadata, upper_fu1);
4253	create_file(_metadata, upper_du1_fu2);
4254	create_file(_metadata, upper_fo1);
4255	create_file(_metadata, upper_do1_fo2);
4256	create_file(_metadata, upper_do1_fu3);
4257	ASSERT_EQ(0, mkdir(UPPER_WORK, 0700));
4258
4259	create_directory(_metadata, MERGE_DATA);
4260	set_cap(_metadata, CAP_SYS_ADMIN);
4261	set_cap(_metadata, CAP_DAC_OVERRIDE);
4262	ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0,
4263			   "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA
4264			   ",workdir=" UPPER_WORK));
4265	clear_cap(_metadata, CAP_DAC_OVERRIDE);
4266	clear_cap(_metadata, CAP_SYS_ADMIN);
4267}
4268
4269FIXTURE_TEARDOWN(layout2_overlay)
4270{
4271	if (self->skip_test)
4272		SKIP(return, "overlayfs is not supported (teardown)");
4273
4274	EXPECT_EQ(0, remove_path(lower_do1_fl3));
4275	EXPECT_EQ(0, remove_path(lower_dl1_fl2));
4276	EXPECT_EQ(0, remove_path(lower_fl1));
4277	EXPECT_EQ(0, remove_path(lower_do1_fo2));
4278	EXPECT_EQ(0, remove_path(lower_fo1));
4279	set_cap(_metadata, CAP_SYS_ADMIN);
4280	EXPECT_EQ(0, umount(LOWER_BASE));
4281	clear_cap(_metadata, CAP_SYS_ADMIN);
4282	EXPECT_EQ(0, remove_path(LOWER_BASE));
4283
4284	EXPECT_EQ(0, remove_path(upper_do1_fu3));
4285	EXPECT_EQ(0, remove_path(upper_du1_fu2));
4286	EXPECT_EQ(0, remove_path(upper_fu1));
4287	EXPECT_EQ(0, remove_path(upper_do1_fo2));
4288	EXPECT_EQ(0, remove_path(upper_fo1));
4289	EXPECT_EQ(0, remove_path(UPPER_WORK "/work"));
4290	set_cap(_metadata, CAP_SYS_ADMIN);
4291	EXPECT_EQ(0, umount(UPPER_BASE));
4292	clear_cap(_metadata, CAP_SYS_ADMIN);
4293	EXPECT_EQ(0, remove_path(UPPER_BASE));
4294
4295	set_cap(_metadata, CAP_SYS_ADMIN);
4296	EXPECT_EQ(0, umount(MERGE_DATA));
4297	clear_cap(_metadata, CAP_SYS_ADMIN);
4298	EXPECT_EQ(0, remove_path(MERGE_DATA));
4299
4300	cleanup_layout(_metadata);
4301}
4302
4303TEST_F_FORK(layout2_overlay, no_restriction)
4304{
4305	if (self->skip_test)
4306		SKIP(return, "overlayfs is not supported (test)");
4307
4308	ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
4309	ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
4310	ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY));
4311	ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY));
4312	ASSERT_EQ(0, test_open(lower_do1, O_RDONLY));
4313	ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY));
4314	ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY));
4315
4316	ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY));
4317	ASSERT_EQ(0, test_open(upper_du1, O_RDONLY));
4318	ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY));
4319	ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY));
4320	ASSERT_EQ(0, test_open(upper_do1, O_RDONLY));
4321	ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY));
4322	ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY));
4323
4324	ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY));
4325	ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY));
4326	ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY));
4327	ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY));
4328	ASSERT_EQ(0, test_open(merge_du1, O_RDONLY));
4329	ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY));
4330	ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY));
4331	ASSERT_EQ(0, test_open(merge_do1, O_RDONLY));
4332	ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY));
4333	ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY));
4334	ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY));
4335}
4336
4337#define for_each_path(path_list, path_entry, i)               \
4338	for (i = 0, path_entry = *path_list[i]; path_list[i]; \
4339	     path_entry = *path_list[++i])
4340
4341TEST_F_FORK(layout2_overlay, same_content_different_file)
4342{
4343	/* Sets access right on parent directories of both layers. */
4344	const struct rule layer1_base[] = {
4345		{
4346			.path = LOWER_BASE,
4347			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4348		},
4349		{
4350			.path = UPPER_BASE,
4351			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4352		},
4353		{
4354			.path = MERGE_BASE,
4355			.access = ACCESS_RW,
4356		},
4357		{},
4358	};
4359	const struct rule layer2_data[] = {
4360		{
4361			.path = LOWER_DATA,
4362			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4363		},
4364		{
4365			.path = UPPER_DATA,
4366			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4367		},
4368		{
4369			.path = MERGE_DATA,
4370			.access = ACCESS_RW,
4371		},
4372		{},
4373	};
4374	/* Sets access right on directories inside both layers. */
4375	const struct rule layer3_subdirs[] = {
4376		{
4377			.path = lower_dl1,
4378			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4379		},
4380		{
4381			.path = lower_do1,
4382			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4383		},
4384		{
4385			.path = upper_du1,
4386			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4387		},
4388		{
4389			.path = upper_do1,
4390			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4391		},
4392		{
4393			.path = merge_dl1,
4394			.access = ACCESS_RW,
4395		},
4396		{
4397			.path = merge_du1,
4398			.access = ACCESS_RW,
4399		},
4400		{
4401			.path = merge_do1,
4402			.access = ACCESS_RW,
4403		},
4404		{},
4405	};
4406	/* Tighten access rights to the files. */
4407	const struct rule layer4_files[] = {
4408		{
4409			.path = lower_dl1_fl2,
4410			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4411		},
4412		{
4413			.path = lower_do1_fo2,
4414			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4415		},
4416		{
4417			.path = lower_do1_fl3,
4418			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4419		},
4420		{
4421			.path = upper_du1_fu2,
4422			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4423		},
4424		{
4425			.path = upper_do1_fo2,
4426			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4427		},
4428		{
4429			.path = upper_do1_fu3,
4430			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4431		},
4432		{
4433			.path = merge_dl1_fl2,
4434			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4435				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4436		},
4437		{
4438			.path = merge_du1_fu2,
4439			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4440				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4441		},
4442		{
4443			.path = merge_do1_fo2,
4444			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4445				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4446		},
4447		{
4448			.path = merge_do1_fl3,
4449			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4450				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4451		},
4452		{
4453			.path = merge_do1_fu3,
4454			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4455				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4456		},
4457		{},
4458	};
4459	const struct rule layer5_merge_only[] = {
4460		{
4461			.path = MERGE_DATA,
4462			.access = LANDLOCK_ACCESS_FS_READ_FILE |
4463				  LANDLOCK_ACCESS_FS_WRITE_FILE,
4464		},
4465		{},
4466	};
4467	int ruleset_fd;
4468	size_t i;
4469	const char *path_entry;
4470
4471	if (self->skip_test)
4472		SKIP(return, "overlayfs is not supported (test)");
4473
4474	/* Sets rules on base directories (i.e. outside overlay scope). */
4475	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
4476	ASSERT_LE(0, ruleset_fd);
4477	enforce_ruleset(_metadata, ruleset_fd);
4478	ASSERT_EQ(0, close(ruleset_fd));
4479
4480	/* Checks lower layer. */
4481	for_each_path(lower_base_files, path_entry, i) {
4482		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4483		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4484	}
4485	for_each_path(lower_base_directories, path_entry, i) {
4486		ASSERT_EQ(EACCES,
4487			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
4488	}
4489	for_each_path(lower_sub_files, path_entry, i) {
4490		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4491		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4492	}
4493	/* Checks upper layer. */
4494	for_each_path(upper_base_files, path_entry, i) {
4495		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4496		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4497	}
4498	for_each_path(upper_base_directories, path_entry, i) {
4499		ASSERT_EQ(EACCES,
4500			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
4501	}
4502	for_each_path(upper_sub_files, path_entry, i) {
4503		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4504		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4505	}
4506	/*
4507	 * Checks that access rights are independent from the lower and upper
4508	 * layers: write access to upper files viewed through the merge point
4509	 * is still allowed, and write access to lower file viewed (and copied)
4510	 * through the merge point is still allowed.
4511	 */
4512	for_each_path(merge_base_files, path_entry, i) {
4513		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4514	}
4515	for_each_path(merge_base_directories, path_entry, i) {
4516		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
4517	}
4518	for_each_path(merge_sub_files, path_entry, i) {
4519		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4520	}
4521
4522	/* Sets rules on data directories (i.e. inside overlay scope). */
4523	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data);
4524	ASSERT_LE(0, ruleset_fd);
4525	enforce_ruleset(_metadata, ruleset_fd);
4526	ASSERT_EQ(0, close(ruleset_fd));
4527
4528	/* Checks merge. */
4529	for_each_path(merge_base_files, path_entry, i) {
4530		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4531	}
4532	for_each_path(merge_base_directories, path_entry, i) {
4533		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
4534	}
4535	for_each_path(merge_sub_files, path_entry, i) {
4536		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4537	}
4538
4539	/* Same checks with tighter rules. */
4540	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs);
4541	ASSERT_LE(0, ruleset_fd);
4542	enforce_ruleset(_metadata, ruleset_fd);
4543	ASSERT_EQ(0, close(ruleset_fd));
4544
4545	/* Checks changes for lower layer. */
4546	for_each_path(lower_base_files, path_entry, i) {
4547		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
4548	}
4549	/* Checks changes for upper layer. */
4550	for_each_path(upper_base_files, path_entry, i) {
4551		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
4552	}
4553	/* Checks all merge accesses. */
4554	for_each_path(merge_base_files, path_entry, i) {
4555		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
4556	}
4557	for_each_path(merge_base_directories, path_entry, i) {
4558		ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
4559	}
4560	for_each_path(merge_sub_files, path_entry, i) {
4561		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4562	}
4563
4564	/* Sets rules directly on overlayed files. */
4565	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files);
4566	ASSERT_LE(0, ruleset_fd);
4567	enforce_ruleset(_metadata, ruleset_fd);
4568	ASSERT_EQ(0, close(ruleset_fd));
4569
4570	/* Checks unchanged accesses on lower layer. */
4571	for_each_path(lower_sub_files, path_entry, i) {
4572		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4573		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4574	}
4575	/* Checks unchanged accesses on upper layer. */
4576	for_each_path(upper_sub_files, path_entry, i) {
4577		ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
4578		ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
4579	}
4580	/* Checks all merge accesses. */
4581	for_each_path(merge_base_files, path_entry, i) {
4582		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
4583	}
4584	for_each_path(merge_base_directories, path_entry, i) {
4585		ASSERT_EQ(EACCES,
4586			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
4587	}
4588	for_each_path(merge_sub_files, path_entry, i) {
4589		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4590	}
4591
4592	/* Only allowes access to the merge hierarchy. */
4593	ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only);
4594	ASSERT_LE(0, ruleset_fd);
4595	enforce_ruleset(_metadata, ruleset_fd);
4596	ASSERT_EQ(0, close(ruleset_fd));
4597
4598	/* Checks new accesses on lower layer. */
4599	for_each_path(lower_sub_files, path_entry, i) {
4600		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
4601	}
4602	/* Checks new accesses on upper layer. */
4603	for_each_path(upper_sub_files, path_entry, i) {
4604		ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
4605	}
4606	/* Checks all merge accesses. */
4607	for_each_path(merge_base_files, path_entry, i) {
4608		ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
4609	}
4610	for_each_path(merge_base_directories, path_entry, i) {
4611		ASSERT_EQ(EACCES,
4612			  test_open(path_entry, O_RDONLY | O_DIRECTORY));
4613	}
4614	for_each_path(merge_sub_files, path_entry, i) {
4615		ASSERT_EQ(0, test_open(path_entry, O_RDWR));
4616	}
4617}
4618
4619FIXTURE(layout3_fs)
4620{
4621	bool has_created_dir;
4622	bool has_created_file;
4623	char *dir_path;
4624	bool skip_test;
4625};
4626
4627FIXTURE_VARIANT(layout3_fs)
4628{
4629	const struct mnt_opt mnt;
4630	const char *const file_path;
4631	unsigned int cwd_fs_magic;
4632};
4633
4634/* clang-format off */
4635FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
4636	/* clang-format on */
4637	.mnt = {
4638		.type = "tmpfs",
4639		.data = MNT_TMP_DATA,
4640	},
4641	.file_path = file1_s1d1,
4642};
4643
4644FIXTURE_VARIANT_ADD(layout3_fs, ramfs) {
4645	.mnt = {
4646		.type = "ramfs",
4647		.data = "mode=700",
4648	},
4649	.file_path = TMP_DIR "/dir/file",
4650};
4651
4652FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) {
4653	.mnt = {
4654		.type = "cgroup2",
4655	},
4656	.file_path = TMP_DIR "/test/cgroup.procs",
4657};
4658
4659FIXTURE_VARIANT_ADD(layout3_fs, proc) {
4660	.mnt = {
4661		.type = "proc",
4662	},
4663	.file_path = TMP_DIR "/self/status",
4664};
4665
4666FIXTURE_VARIANT_ADD(layout3_fs, sysfs) {
4667	.mnt = {
4668		.type = "sysfs",
4669	},
4670	.file_path = TMP_DIR "/kernel/notes",
4671};
4672
4673FIXTURE_VARIANT_ADD(layout3_fs, hostfs) {
4674	.mnt = {
4675		.source = TMP_DIR,
4676		.flags = MS_BIND,
4677	},
4678	.file_path = TMP_DIR "/dir/file",
4679	.cwd_fs_magic = HOSTFS_SUPER_MAGIC,
4680};
4681
4682FIXTURE_SETUP(layout3_fs)
4683{
4684	struct stat statbuf;
4685	const char *slash;
4686	size_t dir_len;
4687
4688	if (!supports_filesystem(variant->mnt.type) ||
4689	    !cwd_matches_fs(variant->cwd_fs_magic)) {
4690		self->skip_test = true;
4691		SKIP(return, "this filesystem is not supported (setup)");
4692	}
4693
4694	slash = strrchr(variant->file_path, '/');
4695	ASSERT_NE(slash, NULL);
4696	dir_len = (size_t)slash - (size_t)variant->file_path;
4697	ASSERT_LT(0, dir_len);
4698	self->dir_path = malloc(dir_len + 1);
4699	self->dir_path[dir_len] = '\0';
4700	strncpy(self->dir_path, variant->file_path, dir_len);
4701
4702	prepare_layout_opt(_metadata, &variant->mnt);
4703
4704	/* Creates directory when required. */
4705	if (stat(self->dir_path, &statbuf)) {
4706		set_cap(_metadata, CAP_DAC_OVERRIDE);
4707		EXPECT_EQ(0, mkdir(self->dir_path, 0700))
4708		{
4709			TH_LOG("Failed to create directory \"%s\": %s",
4710			       self->dir_path, strerror(errno));
4711			free(self->dir_path);
4712			self->dir_path = NULL;
4713		}
4714		self->has_created_dir = true;
4715		clear_cap(_metadata, CAP_DAC_OVERRIDE);
4716	}
4717
4718	/* Creates file when required. */
4719	if (stat(variant->file_path, &statbuf)) {
4720		int fd;
4721
4722		set_cap(_metadata, CAP_DAC_OVERRIDE);
4723		fd = creat(variant->file_path, 0600);
4724		EXPECT_LE(0, fd)
4725		{
4726			TH_LOG("Failed to create file \"%s\": %s",
4727			       variant->file_path, strerror(errno));
4728		}
4729		EXPECT_EQ(0, close(fd));
4730		self->has_created_file = true;
4731		clear_cap(_metadata, CAP_DAC_OVERRIDE);
4732	}
4733}
4734
4735FIXTURE_TEARDOWN(layout3_fs)
4736{
4737	if (self->skip_test)
4738		SKIP(return, "this filesystem is not supported (teardown)");
4739
4740	if (self->has_created_file) {
4741		set_cap(_metadata, CAP_DAC_OVERRIDE);
4742		/*
4743		 * Don't check for error because the file might already
4744		 * have been removed (cf. release_inode test).
4745		 */
4746		unlink(variant->file_path);
4747		clear_cap(_metadata, CAP_DAC_OVERRIDE);
4748	}
4749
4750	if (self->has_created_dir) {
4751		set_cap(_metadata, CAP_DAC_OVERRIDE);
4752		/*
4753		 * Don't check for error because the directory might already
4754		 * have been removed (cf. release_inode test).
4755		 */
4756		rmdir(self->dir_path);
4757		clear_cap(_metadata, CAP_DAC_OVERRIDE);
4758	}
4759	free(self->dir_path);
4760	self->dir_path = NULL;
4761
4762	cleanup_layout(_metadata);
4763}
4764
4765static void layer3_fs_tag_inode(struct __test_metadata *const _metadata,
4766				FIXTURE_DATA(layout3_fs) * self,
4767				const FIXTURE_VARIANT(layout3_fs) * variant,
4768				const char *const rule_path)
4769{
4770	const struct rule layer1_allow_read_file[] = {
4771		{
4772			.path = rule_path,
4773			.access = LANDLOCK_ACCESS_FS_READ_FILE,
4774		},
4775		{},
4776	};
4777	const struct landlock_ruleset_attr layer2_deny_everything_attr = {
4778		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
4779	};
4780	const char *const dev_null_path = "/dev/null";
4781	int ruleset_fd;
4782
4783	if (self->skip_test)
4784		SKIP(return, "this filesystem is not supported (test)");
4785
4786	/* Checks without Landlock. */
4787	EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
4788	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
4789
4790	ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
4791				    layer1_allow_read_file);
4792	EXPECT_LE(0, ruleset_fd);
4793	enforce_ruleset(_metadata, ruleset_fd);
4794	EXPECT_EQ(0, close(ruleset_fd));
4795
4796	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
4797	EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
4798
4799	/* Forbids directory reading. */
4800	ruleset_fd =
4801		landlock_create_ruleset(&layer2_deny_everything_attr,
4802					sizeof(layer2_deny_everything_attr), 0);
4803	EXPECT_LE(0, ruleset_fd);
4804	enforce_ruleset(_metadata, ruleset_fd);
4805	EXPECT_EQ(0, close(ruleset_fd));
4806
4807	/* Checks with Landlock and forbidden access. */
4808	EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
4809	EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
4810}
4811
4812/* Matrix of tests to check file hierarchy evaluation. */
4813
4814TEST_F_FORK(layout3_fs, tag_inode_dir_parent)
4815{
4816	/* The current directory must not be the root for this test. */
4817	layer3_fs_tag_inode(_metadata, self, variant, ".");
4818}
4819
4820TEST_F_FORK(layout3_fs, tag_inode_dir_mnt)
4821{
4822	layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR);
4823}
4824
4825TEST_F_FORK(layout3_fs, tag_inode_dir_child)
4826{
4827	layer3_fs_tag_inode(_metadata, self, variant, self->dir_path);
4828}
4829
4830TEST_F_FORK(layout3_fs, tag_inode_file)
4831{
4832	layer3_fs_tag_inode(_metadata, self, variant, variant->file_path);
4833}
4834
4835/* Light version of layout1.release_inodes */
4836TEST_F_FORK(layout3_fs, release_inodes)
4837{
4838	const struct rule layer1[] = {
4839		{
4840			.path = TMP_DIR,
4841			.access = LANDLOCK_ACCESS_FS_READ_DIR,
4842		},
4843		{},
4844	};
4845	int ruleset_fd;
4846
4847	if (self->skip_test)
4848		SKIP(return, "this filesystem is not supported (test)");
4849
4850	/* Clean up for the teardown to not fail. */
4851	if (self->has_created_file)
4852		EXPECT_EQ(0, remove_path(variant->file_path));
4853
4854	if (self->has_created_dir)
4855		/* Don't check for error because of cgroup specificities. */
4856		remove_path(self->dir_path);
4857
4858	ruleset_fd =
4859		create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
4860	ASSERT_LE(0, ruleset_fd);
4861
4862	/* Unmount the filesystem while it is being used by a ruleset. */
4863	set_cap(_metadata, CAP_SYS_ADMIN);
4864	ASSERT_EQ(0, umount(TMP_DIR));
4865	clear_cap(_metadata, CAP_SYS_ADMIN);
4866
4867	/* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */
4868	set_cap(_metadata, CAP_SYS_ADMIN);
4869	ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR));
4870	clear_cap(_metadata, CAP_SYS_ADMIN);
4871
4872	enforce_ruleset(_metadata, ruleset_fd);
4873	ASSERT_EQ(0, close(ruleset_fd));
4874
4875	/* Checks that access to the new mount point is denied. */
4876	ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY));
4877}
4878
4879TEST_HARNESS_MAIN