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