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 29 int 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) */ 45 static const char dir_s1d1[] = TMP_DIR "/s1d1"; 46 static const char file1_s1d1[] = TMP_DIR "/s1d1/f1"; 47 static const char file2_s1d1[] = TMP_DIR "/s1d1/f2"; 48 static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2"; 49 static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1"; 50 static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2"; 51 static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3"; 52 static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1"; 53 static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2"; 54 55 static const char dir_s2d1[] = TMP_DIR "/s2d1"; 56 static const char file1_s2d1[] = TMP_DIR "/s2d1/f1"; 57 static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2"; 58 static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1"; 59 static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3"; 60 static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1"; 61 static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2"; 62 63 static const char dir_s3d1[] = TMP_DIR "/s3d1"; 64 static const char file1_s3d1[] = TMP_DIR "/s3d1/f1"; 65 /* dir_s3d2 is a mount point. */ 66 static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2"; 67 static 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 95 static 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 112 static 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 137 out: 138 fclose(inf); 139 return res; 140 } 141 142 static 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 155 static 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 181 static 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 192 static 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 203 static 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 232 out: 233 free(walker); 234 return err; 235 } 236 237 struct 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 246 static const struct mnt_opt mnt_tmp = { 247 .type = "tmpfs", 248 .data = MNT_TMP_DATA, 249 }; 250 251 static 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 257 static 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 286 static void prepare_layout(struct __test_metadata *const _metadata) 287 { 288 prepare_layout_opt(_metadata, &mnt_tmp); 289 } 290 291 static 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 */ 300 FIXTURE(layout0) {}; 301 /* clang-format on */ 302 303 FIXTURE_SETUP(layout0) 304 { 305 prepare_layout(_metadata); 306 } 307 308 FIXTURE_TEARDOWN(layout0) 309 { 310 cleanup_layout(_metadata); 311 } 312 313 static 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 336 static 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 */ 361 FIXTURE(layout1) {}; 362 /* clang-format on */ 363 364 FIXTURE_SETUP(layout1) 365 { 366 prepare_layout(_metadata); 367 368 create_layout1(_metadata); 369 } 370 371 FIXTURE_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 */ 382 static 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 400 static int test_open(const char *const path, const int flags) 401 { 402 return test_open_rel(AT_FDCWD, path, flags); 403 } 404 405 TEST_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 428 TEST_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 550 TEST_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 594 TEST_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 610 TEST_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 637 TEST_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 671 static 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 694 struct 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 711 static 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 743 TEST_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 792 TEST_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 815 TEST_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 873 TEST_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 900 TEST_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 941 TEST_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 1048 TEST_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 1097 TEST_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 1282 TEST_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 1399 TEST_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 1436 TEST_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 1460 TEST_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 1494 TEST_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 1523 TEST_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 */ 1556 TEST_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 1586 TEST_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 1606 TEST_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 1634 TEST_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 1657 TEST_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 1691 TEST_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 1718 TEST_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 1750 TEST_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 1784 enum relative_access { 1785 REL_OPEN, 1786 REL_CHDIR, 1787 REL_CHROOT_ONLY, 1788 REL_CHROOT_CHDIR, 1789 }; 1790 1791 static 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 1908 TEST_F_FORK(layout1, relative_open) 1909 { 1910 test_relative_path(_metadata, REL_OPEN); 1911 } 1912 1913 TEST_F_FORK(layout1, relative_chdir) 1914 { 1915 test_relative_path(_metadata, REL_CHDIR); 1916 } 1917 1918 TEST_F_FORK(layout1, relative_chroot_only) 1919 { 1920 test_relative_path(_metadata, REL_CHROOT_ONLY); 1921 } 1922 1923 TEST_F_FORK(layout1, relative_chroot_chdir) 1924 { 1925 test_relative_path(_metadata, REL_CHROOT_CHDIR); 1926 } 1927 1928 static 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 1952 static 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 1979 TEST_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 2012 TEST_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 2067 static 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 2074 static 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 2081 TEST_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 2163 TEST_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 2227 TEST_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. */ 2270 static 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 2310 const struct rule layer_dir_s1d1_refer[] = { 2311 { 2312 .path = dir_s1d1, 2313 .access = LANDLOCK_ACCESS_FS_REFER, 2314 }, 2315 {}, 2316 }; 2317 2318 const 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 2327 const 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 */ 2341 TEST_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 */ 2351 TEST_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 */ 2362 TEST_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 */ 2372 TEST_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 2378 TEST_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 2455 TEST_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 2600 static void 2601 reparent_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 2632 static void 2633 reparent_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 2654 TEST_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 2708 TEST_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 2752 TEST_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 2858 TEST_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 2877 TEST_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 2901 TEST_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 2963 TEST_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 3056 TEST_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 3093 TEST_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 3117 static 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 3171 TEST_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 3179 TEST_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 3187 TEST_F_FORK(layout1, make_reg_1) 3188 { 3189 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0); 3190 } 3191 3192 TEST_F_FORK(layout1, make_reg_2) 3193 { 3194 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0); 3195 } 3196 3197 TEST_F_FORK(layout1, make_sock) 3198 { 3199 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0); 3200 } 3201 3202 TEST_F_FORK(layout1, make_fifo) 3203 { 3204 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0); 3205 } 3206 3207 TEST_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 3252 TEST_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 3280 static 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 3292 TEST_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 3332 TEST_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. */ 3392 static 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 */ 3403 static 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 */ 3423 TEST_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 3480 TEST_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. */ 3584 static int test_ftruncate(int fd) 3585 { 3586 if (ftruncate(fd, 10) < 0) 3587 return errno; 3588 return 0; 3589 } 3590 3591 TEST_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 */ 3675 FIXTURE(ftruncate) {}; 3676 /* clang-format on */ 3677 3678 FIXTURE_SETUP(ftruncate) 3679 { 3680 prepare_layout(_metadata); 3681 create_file(_metadata, file1_s1d1); 3682 } 3683 3684 FIXTURE_TEARDOWN(ftruncate) 3685 { 3686 EXPECT_EQ(0, remove_path(file1_s1d1)); 3687 cleanup_layout(_metadata); 3688 } 3689 3690 FIXTURE_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 */ 3699 FIXTURE_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 */ 3708 FIXTURE_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 */ 3717 FIXTURE_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 */ 3726 FIXTURE_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 */ 3735 FIXTURE_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 3742 TEST_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 3769 TEST_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 3831 TEST(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 */ 3848 FIXTURE(layout1_bind) {}; 3849 /* clang-format on */ 3850 3851 FIXTURE_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 3862 FIXTURE_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 3873 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; 3874 static 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 3902 TEST_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 3924 TEST_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 4060 TEST_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" 4100 static const char lower_fl1[] = LOWER_DATA "/fl1"; 4101 static const char lower_dl1[] = LOWER_DATA "/dl1"; 4102 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; 4103 static const char lower_fo1[] = LOWER_DATA "/fo1"; 4104 static const char lower_do1[] = LOWER_DATA "/do1"; 4105 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; 4106 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; 4107 4108 static const char (*lower_base_files[])[] = { 4109 &lower_fl1, 4110 &lower_fo1, 4111 NULL, 4112 }; 4113 static const char (*lower_base_directories[])[] = { 4114 &lower_dl1, 4115 &lower_do1, 4116 NULL, 4117 }; 4118 static 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" 4128 static const char upper_fu1[] = UPPER_DATA "/fu1"; 4129 static const char upper_du1[] = UPPER_DATA "/du1"; 4130 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; 4131 static const char upper_fo1[] = UPPER_DATA "/fo1"; 4132 static const char upper_do1[] = UPPER_DATA "/do1"; 4133 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; 4134 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; 4135 4136 static const char (*upper_base_files[])[] = { 4137 &upper_fu1, 4138 &upper_fo1, 4139 NULL, 4140 }; 4141 static const char (*upper_base_directories[])[] = { 4142 &upper_du1, 4143 &upper_do1, 4144 NULL, 4145 }; 4146 static 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" 4155 static const char merge_fl1[] = MERGE_DATA "/fl1"; 4156 static const char merge_dl1[] = MERGE_DATA "/dl1"; 4157 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; 4158 static const char merge_fu1[] = MERGE_DATA "/fu1"; 4159 static const char merge_du1[] = MERGE_DATA "/du1"; 4160 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; 4161 static const char merge_fo1[] = MERGE_DATA "/fo1"; 4162 static const char merge_do1[] = MERGE_DATA "/do1"; 4163 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; 4164 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; 4165 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; 4166 4167 static const char (*merge_base_files[])[] = { 4168 &merge_fl1, 4169 &merge_fu1, 4170 &merge_fo1, 4171 NULL, 4172 }; 4173 static const char (*merge_base_directories[])[] = { 4174 &merge_dl1, 4175 &merge_du1, 4176 &merge_do1, 4177 NULL, 4178 }; 4179 static 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 4223 FIXTURE(layout2_overlay) 4224 { 4225 bool skip_test; 4226 }; 4227 4228 FIXTURE_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 4269 FIXTURE_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 4303 TEST_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 4341 TEST_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 4619 FIXTURE(layout3_fs) 4620 { 4621 bool has_created_dir; 4622 bool has_created_file; 4623 char *dir_path; 4624 bool skip_test; 4625 }; 4626 4627 FIXTURE_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 */ 4635 FIXTURE_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 4644 FIXTURE_VARIANT_ADD(layout3_fs, ramfs) { 4645 .mnt = { 4646 .type = "ramfs", 4647 .data = "mode=700", 4648 }, 4649 .file_path = TMP_DIR "/dir/file", 4650 }; 4651 4652 FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) { 4653 .mnt = { 4654 .type = "cgroup2", 4655 }, 4656 .file_path = TMP_DIR "/test/cgroup.procs", 4657 }; 4658 4659 FIXTURE_VARIANT_ADD(layout3_fs, proc) { 4660 .mnt = { 4661 .type = "proc", 4662 }, 4663 .file_path = TMP_DIR "/self/status", 4664 }; 4665 4666 FIXTURE_VARIANT_ADD(layout3_fs, sysfs) { 4667 .mnt = { 4668 .type = "sysfs", 4669 }, 4670 .file_path = TMP_DIR "/kernel/notes", 4671 }; 4672 4673 FIXTURE_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 4682 FIXTURE_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 4735 FIXTURE_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 4765 static 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 4814 TEST_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 4820 TEST_F_FORK(layout3_fs, tag_inode_dir_mnt) 4821 { 4822 layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR); 4823 } 4824 4825 TEST_F_FORK(layout3_fs, tag_inode_dir_child) 4826 { 4827 layer3_fs_tag_inode(_metadata, self, variant, self->dir_path); 4828 } 4829 4830 TEST_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 */ 4836 TEST_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 4879 TEST_HARNESS_MAIN 4880