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