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