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-2021 Microsoft Corporation 8 */ 9 10 #define _GNU_SOURCE 11 #include <fcntl.h> 12 #include <linux/landlock.h> 13 #include <sched.h> 14 #include <string.h> 15 #include <sys/capability.h> 16 #include <sys/mount.h> 17 #include <sys/prctl.h> 18 #include <sys/sendfile.h> 19 #include <sys/stat.h> 20 #include <sys/sysmacros.h> 21 #include <unistd.h> 22 23 #include "common.h" 24 25 #ifndef renameat2 26 int renameat2(int olddirfd, const char *oldpath, int newdirfd, 27 const char *newpath, unsigned int flags) 28 { 29 return syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, 30 flags); 31 } 32 #endif 33 34 #ifndef RENAME_EXCHANGE 35 #define RENAME_EXCHANGE (1 << 1) 36 #endif 37 38 #define TMP_DIR "tmp" 39 #define BINARY_PATH "./true" 40 41 /* Paths (sibling number and depth) */ 42 static const char dir_s1d1[] = TMP_DIR "/s1d1"; 43 static const char file1_s1d1[] = TMP_DIR "/s1d1/f1"; 44 static const char file2_s1d1[] = TMP_DIR "/s1d1/f2"; 45 static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2"; 46 static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1"; 47 static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2"; 48 static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3"; 49 static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1"; 50 static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2"; 51 52 static const char dir_s2d1[] = TMP_DIR "/s2d1"; 53 static const char file1_s2d1[] = TMP_DIR "/s2d1/f1"; 54 static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2"; 55 static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1"; 56 static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3"; 57 static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1"; 58 static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2"; 59 60 static const char dir_s3d1[] = TMP_DIR "/s3d1"; 61 /* dir_s3d2 is a mount point. */ 62 static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2"; 63 static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3"; 64 65 /* 66 * layout1 hierarchy: 67 * 68 * tmp 69 * ├── s1d1 70 * │ ├── f1 71 * │ ├── f2 72 * │ └── s1d2 73 * │ ├── f1 74 * │ ├── f2 75 * │ └── s1d3 76 * │ ├── f1 77 * │ └── f2 78 * ├── s2d1 79 * │ ├── f1 80 * │ └── s2d2 81 * │ ├── f1 82 * │ └── s2d3 83 * │ ├── f1 84 * │ └── f2 85 * └── s3d1 86 * └── s3d2 87 * └── s3d3 88 */ 89 90 static void mkdir_parents(struct __test_metadata *const _metadata, 91 const char *const path) 92 { 93 char *walker; 94 const char *parent; 95 int i, err; 96 97 ASSERT_NE(path[0], '\0'); 98 walker = strdup(path); 99 ASSERT_NE(NULL, walker); 100 parent = walker; 101 for (i = 1; walker[i]; i++) { 102 if (walker[i] != '/') 103 continue; 104 walker[i] = '\0'; 105 err = mkdir(parent, 0700); 106 ASSERT_FALSE(err && errno != EEXIST) 107 { 108 TH_LOG("Failed to create directory \"%s\": %s", parent, 109 strerror(errno)); 110 } 111 walker[i] = '/'; 112 } 113 free(walker); 114 } 115 116 static void create_directory(struct __test_metadata *const _metadata, 117 const char *const path) 118 { 119 mkdir_parents(_metadata, path); 120 ASSERT_EQ(0, mkdir(path, 0700)) 121 { 122 TH_LOG("Failed to create directory \"%s\": %s", path, 123 strerror(errno)); 124 } 125 } 126 127 static void create_file(struct __test_metadata *const _metadata, 128 const char *const path) 129 { 130 mkdir_parents(_metadata, path); 131 ASSERT_EQ(0, mknod(path, S_IFREG | 0700, 0)) 132 { 133 TH_LOG("Failed to create file \"%s\": %s", path, 134 strerror(errno)); 135 } 136 } 137 138 static int remove_path(const char *const path) 139 { 140 char *walker; 141 int i, ret, err = 0; 142 143 walker = strdup(path); 144 if (!walker) { 145 err = ENOMEM; 146 goto out; 147 } 148 if (unlink(path) && rmdir(path)) { 149 if (errno != ENOENT) 150 err = errno; 151 goto out; 152 } 153 for (i = strlen(walker); i > 0; i--) { 154 if (walker[i] != '/') 155 continue; 156 walker[i] = '\0'; 157 ret = rmdir(walker); 158 if (ret) { 159 if (errno != ENOTEMPTY && errno != EBUSY) 160 err = errno; 161 goto out; 162 } 163 if (strcmp(walker, TMP_DIR) == 0) 164 goto out; 165 } 166 167 out: 168 free(walker); 169 return err; 170 } 171 172 static void prepare_layout(struct __test_metadata *const _metadata) 173 { 174 disable_caps(_metadata); 175 umask(0077); 176 create_directory(_metadata, TMP_DIR); 177 178 /* 179 * Do not pollute the rest of the system: creates a private mount point 180 * for tests relying on pivot_root(2) and move_mount(2). 181 */ 182 set_cap(_metadata, CAP_SYS_ADMIN); 183 ASSERT_EQ(0, unshare(CLONE_NEWNS)); 184 ASSERT_EQ(0, mount("tmp", TMP_DIR, "tmpfs", 0, "size=4m,mode=700")); 185 ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL)); 186 clear_cap(_metadata, CAP_SYS_ADMIN); 187 } 188 189 static void cleanup_layout(struct __test_metadata *const _metadata) 190 { 191 set_cap(_metadata, CAP_SYS_ADMIN); 192 EXPECT_EQ(0, umount(TMP_DIR)); 193 clear_cap(_metadata, CAP_SYS_ADMIN); 194 EXPECT_EQ(0, remove_path(TMP_DIR)); 195 } 196 197 static void create_layout1(struct __test_metadata *const _metadata) 198 { 199 create_file(_metadata, file1_s1d1); 200 create_file(_metadata, file1_s1d2); 201 create_file(_metadata, file1_s1d3); 202 create_file(_metadata, file2_s1d1); 203 create_file(_metadata, file2_s1d2); 204 create_file(_metadata, file2_s1d3); 205 206 create_file(_metadata, file1_s2d1); 207 create_file(_metadata, file1_s2d2); 208 create_file(_metadata, file1_s2d3); 209 create_file(_metadata, file2_s2d3); 210 211 create_directory(_metadata, dir_s3d2); 212 set_cap(_metadata, CAP_SYS_ADMIN); 213 ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700")); 214 clear_cap(_metadata, CAP_SYS_ADMIN); 215 216 ASSERT_EQ(0, mkdir(dir_s3d3, 0700)); 217 } 218 219 static void remove_layout1(struct __test_metadata *const _metadata) 220 { 221 EXPECT_EQ(0, remove_path(file2_s1d3)); 222 EXPECT_EQ(0, remove_path(file2_s1d2)); 223 EXPECT_EQ(0, remove_path(file2_s1d1)); 224 EXPECT_EQ(0, remove_path(file1_s1d3)); 225 EXPECT_EQ(0, remove_path(file1_s1d2)); 226 EXPECT_EQ(0, remove_path(file1_s1d1)); 227 228 EXPECT_EQ(0, remove_path(file2_s2d3)); 229 EXPECT_EQ(0, remove_path(file1_s2d3)); 230 EXPECT_EQ(0, remove_path(file1_s2d2)); 231 EXPECT_EQ(0, remove_path(file1_s2d1)); 232 233 EXPECT_EQ(0, remove_path(dir_s3d3)); 234 set_cap(_metadata, CAP_SYS_ADMIN); 235 umount(dir_s3d2); 236 clear_cap(_metadata, CAP_SYS_ADMIN); 237 EXPECT_EQ(0, remove_path(dir_s3d2)); 238 } 239 240 /* clang-format off */ 241 FIXTURE(layout1) {}; 242 /* clang-format on */ 243 244 FIXTURE_SETUP(layout1) 245 { 246 prepare_layout(_metadata); 247 248 create_layout1(_metadata); 249 } 250 251 FIXTURE_TEARDOWN(layout1) 252 { 253 remove_layout1(_metadata); 254 255 cleanup_layout(_metadata); 256 } 257 258 /* 259 * This helper enables to use the ASSERT_* macros and print the line number 260 * pointing to the test caller. 261 */ 262 static int test_open_rel(const int dirfd, const char *const path, 263 const int flags) 264 { 265 int fd; 266 267 /* Works with file and directories. */ 268 fd = openat(dirfd, path, flags | O_CLOEXEC); 269 if (fd < 0) 270 return errno; 271 /* 272 * Mixing error codes from close(2) and open(2) should not lead to any 273 * (access type) confusion for this test. 274 */ 275 if (close(fd) != 0) 276 return errno; 277 return 0; 278 } 279 280 static int test_open(const char *const path, const int flags) 281 { 282 return test_open_rel(AT_FDCWD, path, flags); 283 } 284 285 TEST_F_FORK(layout1, no_restriction) 286 { 287 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 288 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 289 ASSERT_EQ(0, test_open(file2_s1d1, O_RDONLY)); 290 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 291 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 292 ASSERT_EQ(0, test_open(file2_s1d2, O_RDONLY)); 293 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 294 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 295 296 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY)); 297 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY)); 298 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY)); 299 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 300 ASSERT_EQ(0, test_open(dir_s2d3, O_RDONLY)); 301 ASSERT_EQ(0, test_open(file1_s2d3, O_RDONLY)); 302 303 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 304 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 305 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 306 } 307 308 TEST_F_FORK(layout1, inval) 309 { 310 struct landlock_path_beneath_attr path_beneath = { 311 .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | 312 LANDLOCK_ACCESS_FS_WRITE_FILE, 313 .parent_fd = -1, 314 }; 315 struct landlock_ruleset_attr ruleset_attr = { 316 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE | 317 LANDLOCK_ACCESS_FS_WRITE_FILE, 318 }; 319 int ruleset_fd; 320 321 path_beneath.parent_fd = 322 open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC); 323 ASSERT_LE(0, path_beneath.parent_fd); 324 325 ruleset_fd = open(dir_s1d1, O_PATH | O_DIRECTORY | O_CLOEXEC); 326 ASSERT_LE(0, ruleset_fd); 327 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 328 &path_beneath, 0)); 329 /* Returns EBADF because ruleset_fd is not a landlock-ruleset FD. */ 330 ASSERT_EQ(EBADF, errno); 331 ASSERT_EQ(0, close(ruleset_fd)); 332 333 ruleset_fd = open(dir_s1d1, O_DIRECTORY | O_CLOEXEC); 334 ASSERT_LE(0, ruleset_fd); 335 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 336 &path_beneath, 0)); 337 /* Returns EBADFD because ruleset_fd is not a valid ruleset. */ 338 ASSERT_EQ(EBADFD, errno); 339 ASSERT_EQ(0, close(ruleset_fd)); 340 341 /* Gets a real ruleset. */ 342 ruleset_fd = 343 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 344 ASSERT_LE(0, ruleset_fd); 345 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 346 &path_beneath, 0)); 347 ASSERT_EQ(0, close(path_beneath.parent_fd)); 348 349 /* Tests without O_PATH. */ 350 path_beneath.parent_fd = open(dir_s1d2, O_DIRECTORY | O_CLOEXEC); 351 ASSERT_LE(0, path_beneath.parent_fd); 352 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 353 &path_beneath, 0)); 354 ASSERT_EQ(0, close(path_beneath.parent_fd)); 355 356 /* Tests with a ruleset FD. */ 357 path_beneath.parent_fd = ruleset_fd; 358 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 359 &path_beneath, 0)); 360 ASSERT_EQ(EBADFD, errno); 361 362 /* Checks unhandled allowed_access. */ 363 path_beneath.parent_fd = 364 open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC); 365 ASSERT_LE(0, path_beneath.parent_fd); 366 367 /* Test with legitimate values. */ 368 path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_EXECUTE; 369 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 370 &path_beneath, 0)); 371 ASSERT_EQ(EINVAL, errno); 372 path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE; 373 374 /* Test with unknown (64-bits) value. */ 375 path_beneath.allowed_access |= (1ULL << 60); 376 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 377 &path_beneath, 0)); 378 ASSERT_EQ(EINVAL, errno); 379 path_beneath.allowed_access &= ~(1ULL << 60); 380 381 /* Test with no access. */ 382 path_beneath.allowed_access = 0; 383 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 384 &path_beneath, 0)); 385 ASSERT_EQ(ENOMSG, errno); 386 path_beneath.allowed_access &= ~(1ULL << 60); 387 388 ASSERT_EQ(0, close(path_beneath.parent_fd)); 389 390 /* Enforces the ruleset. */ 391 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 392 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 393 394 ASSERT_EQ(0, close(ruleset_fd)); 395 } 396 397 /* clang-format off */ 398 399 #define ACCESS_FILE ( \ 400 LANDLOCK_ACCESS_FS_EXECUTE | \ 401 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 402 LANDLOCK_ACCESS_FS_READ_FILE) 403 404 #define ACCESS_LAST LANDLOCK_ACCESS_FS_MAKE_SYM 405 406 #define ACCESS_ALL ( \ 407 ACCESS_FILE | \ 408 LANDLOCK_ACCESS_FS_READ_DIR | \ 409 LANDLOCK_ACCESS_FS_REMOVE_DIR | \ 410 LANDLOCK_ACCESS_FS_REMOVE_FILE | \ 411 LANDLOCK_ACCESS_FS_MAKE_CHAR | \ 412 LANDLOCK_ACCESS_FS_MAKE_DIR | \ 413 LANDLOCK_ACCESS_FS_MAKE_REG | \ 414 LANDLOCK_ACCESS_FS_MAKE_SOCK | \ 415 LANDLOCK_ACCESS_FS_MAKE_FIFO | \ 416 LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ 417 ACCESS_LAST) 418 419 /* clang-format on */ 420 421 TEST_F_FORK(layout1, file_and_dir_access_rights) 422 { 423 __u64 access; 424 int err; 425 struct landlock_path_beneath_attr path_beneath_file = {}, 426 path_beneath_dir = {}; 427 struct landlock_ruleset_attr ruleset_attr = { 428 .handled_access_fs = ACCESS_ALL, 429 }; 430 const int ruleset_fd = 431 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 432 433 ASSERT_LE(0, ruleset_fd); 434 435 /* Tests access rights for files. */ 436 path_beneath_file.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC); 437 ASSERT_LE(0, path_beneath_file.parent_fd); 438 439 /* Tests access rights for directories. */ 440 path_beneath_dir.parent_fd = 441 open(dir_s1d2, O_PATH | O_DIRECTORY | O_CLOEXEC); 442 ASSERT_LE(0, path_beneath_dir.parent_fd); 443 444 for (access = 1; access <= ACCESS_LAST; access <<= 1) { 445 path_beneath_dir.allowed_access = access; 446 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, 447 LANDLOCK_RULE_PATH_BENEATH, 448 &path_beneath_dir, 0)); 449 450 path_beneath_file.allowed_access = access; 451 err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 452 &path_beneath_file, 0); 453 if (access & ACCESS_FILE) { 454 ASSERT_EQ(0, err); 455 } else { 456 ASSERT_EQ(-1, err); 457 ASSERT_EQ(EINVAL, errno); 458 } 459 } 460 ASSERT_EQ(0, close(path_beneath_file.parent_fd)); 461 ASSERT_EQ(0, close(path_beneath_dir.parent_fd)); 462 ASSERT_EQ(0, close(ruleset_fd)); 463 } 464 465 TEST_F_FORK(layout1, unknown_access_rights) 466 { 467 __u64 access_mask; 468 469 for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST; 470 access_mask >>= 1) { 471 struct landlock_ruleset_attr ruleset_attr = { 472 .handled_access_fs = access_mask, 473 }; 474 475 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 476 sizeof(ruleset_attr), 0)); 477 ASSERT_EQ(EINVAL, errno); 478 } 479 } 480 481 static void add_path_beneath(struct __test_metadata *const _metadata, 482 const int ruleset_fd, const __u64 allowed_access, 483 const char *const path) 484 { 485 struct landlock_path_beneath_attr path_beneath = { 486 .allowed_access = allowed_access, 487 }; 488 489 path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC); 490 ASSERT_LE(0, path_beneath.parent_fd) 491 { 492 TH_LOG("Failed to open directory \"%s\": %s", path, 493 strerror(errno)); 494 } 495 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 496 &path_beneath, 0)) 497 { 498 TH_LOG("Failed to update the ruleset with \"%s\": %s", path, 499 strerror(errno)); 500 } 501 ASSERT_EQ(0, close(path_beneath.parent_fd)); 502 } 503 504 struct rule { 505 const char *path; 506 __u64 access; 507 }; 508 509 /* clang-format off */ 510 511 #define ACCESS_RO ( \ 512 LANDLOCK_ACCESS_FS_READ_FILE | \ 513 LANDLOCK_ACCESS_FS_READ_DIR) 514 515 #define ACCESS_RW ( \ 516 ACCESS_RO | \ 517 LANDLOCK_ACCESS_FS_WRITE_FILE) 518 519 /* clang-format on */ 520 521 static int create_ruleset(struct __test_metadata *const _metadata, 522 const __u64 handled_access_fs, 523 const struct rule rules[]) 524 { 525 int ruleset_fd, i; 526 struct landlock_ruleset_attr ruleset_attr = { 527 .handled_access_fs = handled_access_fs, 528 }; 529 530 ASSERT_NE(NULL, rules) 531 { 532 TH_LOG("No rule list"); 533 } 534 ASSERT_NE(NULL, rules[0].path) 535 { 536 TH_LOG("Empty rule list"); 537 } 538 539 ruleset_fd = 540 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 541 ASSERT_LE(0, ruleset_fd) 542 { 543 TH_LOG("Failed to create a ruleset: %s", strerror(errno)); 544 } 545 546 for (i = 0; rules[i].path; i++) { 547 add_path_beneath(_metadata, ruleset_fd, rules[i].access, 548 rules[i].path); 549 } 550 return ruleset_fd; 551 } 552 553 static void enforce_ruleset(struct __test_metadata *const _metadata, 554 const int ruleset_fd) 555 { 556 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 557 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) 558 { 559 TH_LOG("Failed to enforce ruleset: %s", strerror(errno)); 560 } 561 } 562 563 TEST_F_FORK(layout1, proc_nsfs) 564 { 565 const struct rule rules[] = { 566 { 567 .path = "/dev/null", 568 .access = LANDLOCK_ACCESS_FS_READ_FILE | 569 LANDLOCK_ACCESS_FS_WRITE_FILE, 570 }, 571 {}, 572 }; 573 struct landlock_path_beneath_attr path_beneath; 574 const int ruleset_fd = create_ruleset( 575 _metadata, rules[0].access | LANDLOCK_ACCESS_FS_READ_DIR, 576 rules); 577 578 ASSERT_LE(0, ruleset_fd); 579 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY)); 580 581 enforce_ruleset(_metadata, ruleset_fd); 582 583 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 584 ASSERT_EQ(EACCES, test_open("/dev", O_RDONLY)); 585 ASSERT_EQ(0, test_open("/dev/null", O_RDONLY)); 586 ASSERT_EQ(EACCES, test_open("/dev/full", O_RDONLY)); 587 588 ASSERT_EQ(EACCES, test_open("/proc", O_RDONLY)); 589 ASSERT_EQ(EACCES, test_open("/proc/self", O_RDONLY)); 590 ASSERT_EQ(EACCES, test_open("/proc/self/ns", O_RDONLY)); 591 /* 592 * Because nsfs is an internal filesystem, /proc/self/ns/mnt is a 593 * disconnected path. Such path cannot be identified and must then be 594 * allowed. 595 */ 596 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY)); 597 598 /* 599 * Checks that it is not possible to add nsfs-like filesystem 600 * references to a ruleset. 601 */ 602 path_beneath.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | 603 LANDLOCK_ACCESS_FS_WRITE_FILE, 604 path_beneath.parent_fd = open("/proc/self/ns/mnt", O_PATH | O_CLOEXEC); 605 ASSERT_LE(0, path_beneath.parent_fd); 606 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 607 &path_beneath, 0)); 608 ASSERT_EQ(EBADFD, errno); 609 ASSERT_EQ(0, close(path_beneath.parent_fd)); 610 } 611 612 TEST_F_FORK(layout1, unpriv) 613 { 614 const struct rule rules[] = { 615 { 616 .path = dir_s1d2, 617 .access = ACCESS_RO, 618 }, 619 {}, 620 }; 621 int ruleset_fd; 622 623 drop_caps(_metadata); 624 625 ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules); 626 ASSERT_LE(0, ruleset_fd); 627 ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0)); 628 ASSERT_EQ(EPERM, errno); 629 630 /* enforce_ruleset() calls prctl(no_new_privs). */ 631 enforce_ruleset(_metadata, ruleset_fd); 632 ASSERT_EQ(0, close(ruleset_fd)); 633 } 634 635 TEST_F_FORK(layout1, effective_access) 636 { 637 const struct rule rules[] = { 638 { 639 .path = dir_s1d2, 640 .access = ACCESS_RO, 641 }, 642 { 643 .path = file1_s2d2, 644 .access = LANDLOCK_ACCESS_FS_READ_FILE | 645 LANDLOCK_ACCESS_FS_WRITE_FILE, 646 }, 647 {}, 648 }; 649 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 650 char buf; 651 int reg_fd; 652 653 ASSERT_LE(0, ruleset_fd); 654 enforce_ruleset(_metadata, ruleset_fd); 655 ASSERT_EQ(0, close(ruleset_fd)); 656 657 /* Tests on a directory (with or without O_PATH). */ 658 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 659 ASSERT_EQ(0, test_open("/", O_RDONLY | O_PATH)); 660 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 661 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_PATH)); 662 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 663 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY | O_PATH)); 664 665 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 666 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 667 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 668 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 669 670 /* Tests on a file (with or without O_PATH). */ 671 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY)); 672 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_PATH)); 673 674 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 675 676 /* Checks effective read and write actions. */ 677 reg_fd = open(file1_s2d2, O_RDWR | O_CLOEXEC); 678 ASSERT_LE(0, reg_fd); 679 ASSERT_EQ(1, write(reg_fd, ".", 1)); 680 ASSERT_LE(0, lseek(reg_fd, 0, SEEK_SET)); 681 ASSERT_EQ(1, read(reg_fd, &buf, 1)); 682 ASSERT_EQ('.', buf); 683 ASSERT_EQ(0, close(reg_fd)); 684 685 /* Just in case, double-checks effective actions. */ 686 reg_fd = open(file1_s2d2, O_RDONLY | O_CLOEXEC); 687 ASSERT_LE(0, reg_fd); 688 ASSERT_EQ(-1, write(reg_fd, &buf, 1)); 689 ASSERT_EQ(EBADF, errno); 690 ASSERT_EQ(0, close(reg_fd)); 691 } 692 693 TEST_F_FORK(layout1, unhandled_access) 694 { 695 const struct rule rules[] = { 696 { 697 .path = dir_s1d2, 698 .access = ACCESS_RO, 699 }, 700 {}, 701 }; 702 /* Here, we only handle read accesses, not write accesses. */ 703 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules); 704 705 ASSERT_LE(0, ruleset_fd); 706 enforce_ruleset(_metadata, ruleset_fd); 707 ASSERT_EQ(0, close(ruleset_fd)); 708 709 /* 710 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE, 711 * opening for write-only should be allowed, but not read-write. 712 */ 713 ASSERT_EQ(0, test_open(file1_s1d1, O_WRONLY)); 714 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 715 716 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY)); 717 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 718 } 719 720 TEST_F_FORK(layout1, ruleset_overlap) 721 { 722 const struct rule rules[] = { 723 /* These rules should be ORed among them. */ 724 { 725 .path = dir_s1d2, 726 .access = LANDLOCK_ACCESS_FS_READ_FILE | 727 LANDLOCK_ACCESS_FS_WRITE_FILE, 728 }, 729 { 730 .path = dir_s1d2, 731 .access = LANDLOCK_ACCESS_FS_READ_FILE | 732 LANDLOCK_ACCESS_FS_READ_DIR, 733 }, 734 {}, 735 }; 736 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 737 738 ASSERT_LE(0, ruleset_fd); 739 enforce_ruleset(_metadata, ruleset_fd); 740 ASSERT_EQ(0, close(ruleset_fd)); 741 742 /* Checks s1d1 hierarchy. */ 743 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 744 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 745 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 746 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 747 748 /* Checks s1d2 hierarchy. */ 749 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 750 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY)); 751 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 752 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 753 754 /* Checks s1d3 hierarchy. */ 755 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 756 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY)); 757 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 758 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 759 } 760 761 TEST_F_FORK(layout1, layer_rule_unions) 762 { 763 const struct rule layer1[] = { 764 { 765 .path = dir_s1d2, 766 .access = LANDLOCK_ACCESS_FS_READ_FILE, 767 }, 768 /* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */ 769 { 770 .path = dir_s1d3, 771 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 772 }, 773 {}, 774 }; 775 const struct rule layer2[] = { 776 /* Doesn't change anything from layer1. */ 777 { 778 .path = dir_s1d2, 779 .access = LANDLOCK_ACCESS_FS_READ_FILE | 780 LANDLOCK_ACCESS_FS_WRITE_FILE, 781 }, 782 {}, 783 }; 784 const struct rule layer3[] = { 785 /* Only allows write (but not read) to dir_s1d3. */ 786 { 787 .path = dir_s1d2, 788 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 789 }, 790 {}, 791 }; 792 int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1); 793 794 ASSERT_LE(0, ruleset_fd); 795 enforce_ruleset(_metadata, ruleset_fd); 796 ASSERT_EQ(0, close(ruleset_fd)); 797 798 /* Checks s1d1 hierarchy with layer1. */ 799 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 800 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 801 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 802 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 803 804 /* Checks s1d2 hierarchy with layer1. */ 805 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 806 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 807 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 808 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 809 810 /* Checks s1d3 hierarchy with layer1. */ 811 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 812 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY)); 813 /* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */ 814 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 815 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 816 817 /* Doesn't change anything from layer1. */ 818 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2); 819 ASSERT_LE(0, ruleset_fd); 820 enforce_ruleset(_metadata, ruleset_fd); 821 ASSERT_EQ(0, close(ruleset_fd)); 822 823 /* Checks s1d1 hierarchy with layer2. */ 824 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 825 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 826 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 827 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 828 829 /* Checks s1d2 hierarchy with layer2. */ 830 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 831 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 832 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 833 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 834 835 /* Checks s1d3 hierarchy with layer2. */ 836 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 837 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY)); 838 /* dir_s1d3 should allow READ_FILE and WRITE_FILE (O_RDWR). */ 839 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 840 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 841 842 /* Only allows write (but not read) to dir_s1d3. */ 843 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3); 844 ASSERT_LE(0, ruleset_fd); 845 enforce_ruleset(_metadata, ruleset_fd); 846 ASSERT_EQ(0, close(ruleset_fd)); 847 848 /* Checks s1d1 hierarchy with layer3. */ 849 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 850 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 851 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 852 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 853 854 /* Checks s1d2 hierarchy with layer3. */ 855 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY)); 856 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 857 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 858 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 859 860 /* Checks s1d3 hierarchy with layer3. */ 861 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 862 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY)); 863 /* dir_s1d3 should now deny READ_FILE and WRITE_FILE (O_RDWR). */ 864 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDWR)); 865 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 866 } 867 868 TEST_F_FORK(layout1, non_overlapping_accesses) 869 { 870 const struct rule layer1[] = { 871 { 872 .path = dir_s1d2, 873 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 874 }, 875 {}, 876 }; 877 const struct rule layer2[] = { 878 { 879 .path = dir_s1d3, 880 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 881 }, 882 {}, 883 }; 884 int ruleset_fd; 885 886 ASSERT_EQ(0, unlink(file1_s1d1)); 887 ASSERT_EQ(0, unlink(file1_s1d2)); 888 889 ruleset_fd = 890 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, layer1); 891 ASSERT_LE(0, ruleset_fd); 892 enforce_ruleset(_metadata, ruleset_fd); 893 ASSERT_EQ(0, close(ruleset_fd)); 894 895 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); 896 ASSERT_EQ(EACCES, errno); 897 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0)); 898 ASSERT_EQ(0, unlink(file1_s1d2)); 899 900 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE, 901 layer2); 902 ASSERT_LE(0, ruleset_fd); 903 enforce_ruleset(_metadata, ruleset_fd); 904 ASSERT_EQ(0, close(ruleset_fd)); 905 906 /* Unchanged accesses for file creation. */ 907 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); 908 ASSERT_EQ(EACCES, errno); 909 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0)); 910 911 /* Checks file removing. */ 912 ASSERT_EQ(-1, unlink(file1_s1d2)); 913 ASSERT_EQ(EACCES, errno); 914 ASSERT_EQ(0, unlink(file1_s1d3)); 915 } 916 917 TEST_F_FORK(layout1, interleaved_masked_accesses) 918 { 919 /* 920 * Checks overly restrictive rules: 921 * layer 1: allows R s1d1/s1d2/s1d3/file1 922 * layer 2: allows RW s1d1/s1d2/s1d3 923 * allows W s1d1/s1d2 924 * denies R s1d1/s1d2 925 * layer 3: allows R s1d1 926 * layer 4: allows R s1d1/s1d2 927 * denies W s1d1/s1d2 928 * layer 5: allows R s1d1/s1d2 929 * layer 6: allows X ---- 930 * layer 7: allows W s1d1/s1d2 931 * denies R s1d1/s1d2 932 */ 933 const struct rule layer1_read[] = { 934 /* Allows read access to file1_s1d3 with the first layer. */ 935 { 936 .path = file1_s1d3, 937 .access = LANDLOCK_ACCESS_FS_READ_FILE, 938 }, 939 {}, 940 }; 941 /* First rule with write restrictions. */ 942 const struct rule layer2_read_write[] = { 943 /* Start by granting read-write access via its parent directory... */ 944 { 945 .path = dir_s1d3, 946 .access = LANDLOCK_ACCESS_FS_READ_FILE | 947 LANDLOCK_ACCESS_FS_WRITE_FILE, 948 }, 949 /* ...but also denies read access via its grandparent directory. */ 950 { 951 .path = dir_s1d2, 952 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 953 }, 954 {}, 955 }; 956 const struct rule layer3_read[] = { 957 /* Allows read access via its great-grandparent directory. */ 958 { 959 .path = dir_s1d1, 960 .access = LANDLOCK_ACCESS_FS_READ_FILE, 961 }, 962 {}, 963 }; 964 const struct rule layer4_read_write[] = { 965 /* 966 * Try to confuse the deny access by denying write (but not 967 * read) access via its grandparent directory. 968 */ 969 { 970 .path = dir_s1d2, 971 .access = LANDLOCK_ACCESS_FS_READ_FILE, 972 }, 973 {}, 974 }; 975 const struct rule layer5_read[] = { 976 /* 977 * Try to override layer2's deny read access by explicitly 978 * allowing read access via file1_s1d3's grandparent. 979 */ 980 { 981 .path = dir_s1d2, 982 .access = LANDLOCK_ACCESS_FS_READ_FILE, 983 }, 984 {}, 985 }; 986 const struct rule layer6_execute[] = { 987 /* 988 * Restricts an unrelated file hierarchy with a new access 989 * (non-overlapping) type. 990 */ 991 { 992 .path = dir_s2d1, 993 .access = LANDLOCK_ACCESS_FS_EXECUTE, 994 }, 995 {}, 996 }; 997 const struct rule layer7_read_write[] = { 998 /* 999 * Finally, denies read access to file1_s1d3 via its 1000 * grandparent. 1001 */ 1002 { 1003 .path = dir_s1d2, 1004 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 1005 }, 1006 {}, 1007 }; 1008 int ruleset_fd; 1009 1010 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1011 layer1_read); 1012 ASSERT_LE(0, ruleset_fd); 1013 enforce_ruleset(_metadata, ruleset_fd); 1014 ASSERT_EQ(0, close(ruleset_fd)); 1015 1016 /* Checks that read access is granted for file1_s1d3 with layer 1. */ 1017 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 1018 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1019 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1020 1021 ruleset_fd = create_ruleset(_metadata, 1022 LANDLOCK_ACCESS_FS_READ_FILE | 1023 LANDLOCK_ACCESS_FS_WRITE_FILE, 1024 layer2_read_write); 1025 ASSERT_LE(0, ruleset_fd); 1026 enforce_ruleset(_metadata, ruleset_fd); 1027 ASSERT_EQ(0, close(ruleset_fd)); 1028 1029 /* Checks that previous access rights are unchanged with layer 2. */ 1030 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 1031 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1032 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1033 1034 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1035 layer3_read); 1036 ASSERT_LE(0, ruleset_fd); 1037 enforce_ruleset(_metadata, ruleset_fd); 1038 ASSERT_EQ(0, close(ruleset_fd)); 1039 1040 /* Checks that previous access rights are unchanged with layer 3. */ 1041 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 1042 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1043 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1044 1045 /* This time, denies write access for the file hierarchy. */ 1046 ruleset_fd = create_ruleset(_metadata, 1047 LANDLOCK_ACCESS_FS_READ_FILE | 1048 LANDLOCK_ACCESS_FS_WRITE_FILE, 1049 layer4_read_write); 1050 ASSERT_LE(0, ruleset_fd); 1051 enforce_ruleset(_metadata, ruleset_fd); 1052 ASSERT_EQ(0, close(ruleset_fd)); 1053 1054 /* 1055 * Checks that the only change with layer 4 is that write access is 1056 * denied. 1057 */ 1058 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1059 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1060 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1061 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1062 1063 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1064 layer5_read); 1065 ASSERT_LE(0, ruleset_fd); 1066 enforce_ruleset(_metadata, ruleset_fd); 1067 ASSERT_EQ(0, close(ruleset_fd)); 1068 1069 /* Checks that previous access rights are unchanged with layer 5. */ 1070 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1071 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1072 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1073 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1074 1075 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, 1076 layer6_execute); 1077 ASSERT_LE(0, ruleset_fd); 1078 enforce_ruleset(_metadata, ruleset_fd); 1079 ASSERT_EQ(0, close(ruleset_fd)); 1080 1081 /* Checks that previous access rights are unchanged with layer 6. */ 1082 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1083 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1084 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1085 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1086 1087 ruleset_fd = create_ruleset(_metadata, 1088 LANDLOCK_ACCESS_FS_READ_FILE | 1089 LANDLOCK_ACCESS_FS_WRITE_FILE, 1090 layer7_read_write); 1091 ASSERT_LE(0, ruleset_fd); 1092 enforce_ruleset(_metadata, ruleset_fd); 1093 ASSERT_EQ(0, close(ruleset_fd)); 1094 1095 /* Checks read access is now denied with layer 7. */ 1096 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 1097 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1098 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1099 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1100 } 1101 1102 TEST_F_FORK(layout1, inherit_subset) 1103 { 1104 const struct rule rules[] = { 1105 { 1106 .path = dir_s1d2, 1107 .access = LANDLOCK_ACCESS_FS_READ_FILE | 1108 LANDLOCK_ACCESS_FS_READ_DIR, 1109 }, 1110 {}, 1111 }; 1112 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1113 1114 ASSERT_LE(0, ruleset_fd); 1115 enforce_ruleset(_metadata, ruleset_fd); 1116 1117 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 1118 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1119 1120 /* Write access is forbidden. */ 1121 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 1122 /* Readdir access is allowed. */ 1123 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1124 1125 /* Write access is forbidden. */ 1126 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1127 /* Readdir access is allowed. */ 1128 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1129 1130 /* 1131 * Tests shared rule extension: the following rules should not grant 1132 * any new access, only remove some. Once enforced, these rules are 1133 * ANDed with the previous ones. 1134 */ 1135 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE, 1136 dir_s1d2); 1137 /* 1138 * According to ruleset_fd, dir_s1d2 should now have the 1139 * LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE 1140 * access rights (even if this directory is opened a second time). 1141 * However, when enforcing this updated ruleset, the ruleset tied to 1142 * the current process (i.e. its domain) will still only have the 1143 * dir_s1d2 with LANDLOCK_ACCESS_FS_READ_FILE and 1144 * LANDLOCK_ACCESS_FS_READ_DIR accesses, but 1145 * LANDLOCK_ACCESS_FS_WRITE_FILE must not be allowed because it would 1146 * be a privilege escalation. 1147 */ 1148 enforce_ruleset(_metadata, ruleset_fd); 1149 1150 /* Same tests and results as above. */ 1151 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 1152 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1153 1154 /* It is still forbidden to write in file1_s1d2. */ 1155 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 1156 /* Readdir access is still allowed. */ 1157 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1158 1159 /* It is still forbidden to write in file1_s1d3. */ 1160 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1161 /* Readdir access is still allowed. */ 1162 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1163 1164 /* 1165 * Try to get more privileges by adding new access rights to the parent 1166 * directory: dir_s1d1. 1167 */ 1168 add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1); 1169 enforce_ruleset(_metadata, ruleset_fd); 1170 1171 /* Same tests and results as above. */ 1172 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 1173 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1174 1175 /* It is still forbidden to write in file1_s1d2. */ 1176 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 1177 /* Readdir access is still allowed. */ 1178 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1179 1180 /* It is still forbidden to write in file1_s1d3. */ 1181 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1182 /* Readdir access is still allowed. */ 1183 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1184 1185 /* 1186 * Now, dir_s1d3 get a new rule tied to it, only allowing 1187 * LANDLOCK_ACCESS_FS_WRITE_FILE. The (kernel internal) difference is 1188 * that there was no rule tied to it before. 1189 */ 1190 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE, 1191 dir_s1d3); 1192 enforce_ruleset(_metadata, ruleset_fd); 1193 ASSERT_EQ(0, close(ruleset_fd)); 1194 1195 /* 1196 * Same tests and results as above, except for open(dir_s1d3) which is 1197 * now denied because the new rule mask the rule previously inherited 1198 * from dir_s1d2. 1199 */ 1200 1201 /* Same tests and results as above. */ 1202 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 1203 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1204 1205 /* It is still forbidden to write in file1_s1d2. */ 1206 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 1207 /* Readdir access is still allowed. */ 1208 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1209 1210 /* It is still forbidden to write in file1_s1d3. */ 1211 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1212 /* 1213 * Readdir of dir_s1d3 is still allowed because of the OR policy inside 1214 * the same layer. 1215 */ 1216 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1217 } 1218 1219 TEST_F_FORK(layout1, inherit_superset) 1220 { 1221 const struct rule rules[] = { 1222 { 1223 .path = dir_s1d3, 1224 .access = ACCESS_RO, 1225 }, 1226 {}, 1227 }; 1228 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1229 1230 ASSERT_LE(0, ruleset_fd); 1231 enforce_ruleset(_metadata, ruleset_fd); 1232 1233 /* Readdir access is denied for dir_s1d2. */ 1234 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1235 /* Readdir access is allowed for dir_s1d3. */ 1236 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1237 /* File access is allowed for file1_s1d3. */ 1238 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1239 1240 /* Now dir_s1d2, parent of dir_s1d3, gets a new rule tied to it. */ 1241 add_path_beneath(_metadata, ruleset_fd, 1242 LANDLOCK_ACCESS_FS_READ_FILE | 1243 LANDLOCK_ACCESS_FS_READ_DIR, 1244 dir_s1d2); 1245 enforce_ruleset(_metadata, ruleset_fd); 1246 ASSERT_EQ(0, close(ruleset_fd)); 1247 1248 /* Readdir access is still denied for dir_s1d2. */ 1249 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1250 /* Readdir access is still allowed for dir_s1d3. */ 1251 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1252 /* File access is still allowed for file1_s1d3. */ 1253 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1254 } 1255 1256 TEST_F_FORK(layout1, max_layers) 1257 { 1258 int i, err; 1259 const struct rule rules[] = { 1260 { 1261 .path = dir_s1d2, 1262 .access = ACCESS_RO, 1263 }, 1264 {}, 1265 }; 1266 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1267 1268 ASSERT_LE(0, ruleset_fd); 1269 for (i = 0; i < 16; i++) 1270 enforce_ruleset(_metadata, ruleset_fd); 1271 1272 for (i = 0; i < 2; i++) { 1273 err = landlock_restrict_self(ruleset_fd, 0); 1274 ASSERT_EQ(-1, err); 1275 ASSERT_EQ(E2BIG, errno); 1276 } 1277 ASSERT_EQ(0, close(ruleset_fd)); 1278 } 1279 1280 TEST_F_FORK(layout1, empty_or_same_ruleset) 1281 { 1282 struct landlock_ruleset_attr ruleset_attr = {}; 1283 int ruleset_fd; 1284 1285 /* Tests empty handled_access_fs. */ 1286 ruleset_fd = 1287 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1288 ASSERT_LE(-1, ruleset_fd); 1289 ASSERT_EQ(ENOMSG, errno); 1290 1291 /* Enforces policy which deny read access to all files. */ 1292 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE; 1293 ruleset_fd = 1294 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1295 ASSERT_LE(0, ruleset_fd); 1296 enforce_ruleset(_metadata, ruleset_fd); 1297 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1298 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1299 1300 /* Nests a policy which deny read access to all directories. */ 1301 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR; 1302 ruleset_fd = 1303 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1304 ASSERT_LE(0, ruleset_fd); 1305 enforce_ruleset(_metadata, ruleset_fd); 1306 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1307 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1308 1309 /* Enforces a second time with the same ruleset. */ 1310 enforce_ruleset(_metadata, ruleset_fd); 1311 ASSERT_EQ(0, close(ruleset_fd)); 1312 } 1313 1314 TEST_F_FORK(layout1, rule_on_mountpoint) 1315 { 1316 const struct rule rules[] = { 1317 { 1318 .path = dir_s1d1, 1319 .access = ACCESS_RO, 1320 }, 1321 { 1322 /* dir_s3d2 is a mount point. */ 1323 .path = dir_s3d2, 1324 .access = ACCESS_RO, 1325 }, 1326 {}, 1327 }; 1328 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1329 1330 ASSERT_LE(0, ruleset_fd); 1331 enforce_ruleset(_metadata, ruleset_fd); 1332 ASSERT_EQ(0, close(ruleset_fd)); 1333 1334 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1335 1336 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY)); 1337 1338 ASSERT_EQ(EACCES, test_open(dir_s3d1, O_RDONLY)); 1339 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 1340 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 1341 } 1342 1343 TEST_F_FORK(layout1, rule_over_mountpoint) 1344 { 1345 const struct rule rules[] = { 1346 { 1347 .path = dir_s1d1, 1348 .access = ACCESS_RO, 1349 }, 1350 { 1351 /* dir_s3d2 is a mount point. */ 1352 .path = dir_s3d1, 1353 .access = ACCESS_RO, 1354 }, 1355 {}, 1356 }; 1357 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1358 1359 ASSERT_LE(0, ruleset_fd); 1360 enforce_ruleset(_metadata, ruleset_fd); 1361 ASSERT_EQ(0, close(ruleset_fd)); 1362 1363 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1364 1365 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY)); 1366 1367 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 1368 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 1369 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 1370 } 1371 1372 /* 1373 * This test verifies that we can apply a landlock rule on the root directory 1374 * (which might require special handling). 1375 */ 1376 TEST_F_FORK(layout1, rule_over_root_allow_then_deny) 1377 { 1378 struct rule rules[] = { 1379 { 1380 .path = "/", 1381 .access = ACCESS_RO, 1382 }, 1383 {}, 1384 }; 1385 int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1386 1387 ASSERT_LE(0, ruleset_fd); 1388 enforce_ruleset(_metadata, ruleset_fd); 1389 ASSERT_EQ(0, close(ruleset_fd)); 1390 1391 /* Checks allowed access. */ 1392 ASSERT_EQ(0, test_open("/", O_RDONLY)); 1393 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1394 1395 rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE; 1396 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1397 ASSERT_LE(0, ruleset_fd); 1398 enforce_ruleset(_metadata, ruleset_fd); 1399 ASSERT_EQ(0, close(ruleset_fd)); 1400 1401 /* Checks denied access (on a directory). */ 1402 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1403 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1404 } 1405 1406 TEST_F_FORK(layout1, rule_over_root_deny) 1407 { 1408 const struct rule rules[] = { 1409 { 1410 .path = "/", 1411 .access = LANDLOCK_ACCESS_FS_READ_FILE, 1412 }, 1413 {}, 1414 }; 1415 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1416 1417 ASSERT_LE(0, ruleset_fd); 1418 enforce_ruleset(_metadata, ruleset_fd); 1419 ASSERT_EQ(0, close(ruleset_fd)); 1420 1421 /* Checks denied access (on a directory). */ 1422 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1423 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1424 } 1425 1426 TEST_F_FORK(layout1, rule_inside_mount_ns) 1427 { 1428 const struct rule rules[] = { 1429 { 1430 .path = "s3d3", 1431 .access = ACCESS_RO, 1432 }, 1433 {}, 1434 }; 1435 int ruleset_fd; 1436 1437 set_cap(_metadata, CAP_SYS_ADMIN); 1438 ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)) 1439 { 1440 TH_LOG("Failed to pivot root: %s", strerror(errno)); 1441 }; 1442 ASSERT_EQ(0, chdir("/")); 1443 clear_cap(_metadata, CAP_SYS_ADMIN); 1444 1445 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1446 ASSERT_LE(0, ruleset_fd); 1447 enforce_ruleset(_metadata, ruleset_fd); 1448 ASSERT_EQ(0, close(ruleset_fd)); 1449 1450 ASSERT_EQ(0, test_open("s3d3", O_RDONLY)); 1451 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1452 } 1453 1454 TEST_F_FORK(layout1, mount_and_pivot) 1455 { 1456 const struct rule rules[] = { 1457 { 1458 .path = dir_s3d2, 1459 .access = ACCESS_RO, 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 set_cap(_metadata, CAP_SYS_ADMIN); 1470 ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL)); 1471 ASSERT_EQ(EPERM, errno); 1472 ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)); 1473 ASSERT_EQ(EPERM, errno); 1474 clear_cap(_metadata, CAP_SYS_ADMIN); 1475 } 1476 1477 TEST_F_FORK(layout1, move_mount) 1478 { 1479 const struct rule rules[] = { 1480 { 1481 .path = dir_s3d2, 1482 .access = ACCESS_RO, 1483 }, 1484 {}, 1485 }; 1486 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1487 1488 ASSERT_LE(0, ruleset_fd); 1489 1490 set_cap(_metadata, CAP_SYS_ADMIN); 1491 ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1492 dir_s1d2, 0)) 1493 { 1494 TH_LOG("Failed to move mount: %s", strerror(errno)); 1495 } 1496 1497 ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD, 1498 dir_s3d2, 0)); 1499 clear_cap(_metadata, CAP_SYS_ADMIN); 1500 1501 enforce_ruleset(_metadata, ruleset_fd); 1502 ASSERT_EQ(0, close(ruleset_fd)); 1503 1504 set_cap(_metadata, CAP_SYS_ADMIN); 1505 ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1506 dir_s1d2, 0)); 1507 ASSERT_EQ(EPERM, errno); 1508 clear_cap(_metadata, CAP_SYS_ADMIN); 1509 } 1510 1511 TEST_F_FORK(layout1, release_inodes) 1512 { 1513 const struct rule rules[] = { 1514 { 1515 .path = dir_s1d1, 1516 .access = ACCESS_RO, 1517 }, 1518 { 1519 .path = dir_s3d2, 1520 .access = ACCESS_RO, 1521 }, 1522 { 1523 .path = dir_s3d3, 1524 .access = ACCESS_RO, 1525 }, 1526 {}, 1527 }; 1528 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1529 1530 ASSERT_LE(0, ruleset_fd); 1531 /* Unmount a file hierarchy while it is being used by a ruleset. */ 1532 set_cap(_metadata, CAP_SYS_ADMIN); 1533 ASSERT_EQ(0, umount(dir_s3d2)); 1534 clear_cap(_metadata, CAP_SYS_ADMIN); 1535 1536 enforce_ruleset(_metadata, ruleset_fd); 1537 ASSERT_EQ(0, close(ruleset_fd)); 1538 1539 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 1540 ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY)); 1541 /* This dir_s3d3 would not be allowed and does not exist anyway. */ 1542 ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY)); 1543 } 1544 1545 enum relative_access { 1546 REL_OPEN, 1547 REL_CHDIR, 1548 REL_CHROOT_ONLY, 1549 REL_CHROOT_CHDIR, 1550 }; 1551 1552 static void test_relative_path(struct __test_metadata *const _metadata, 1553 const enum relative_access rel) 1554 { 1555 /* 1556 * Common layer to check that chroot doesn't ignore it (i.e. a chroot 1557 * is not a disconnected root directory). 1558 */ 1559 const struct rule layer1_base[] = { 1560 { 1561 .path = TMP_DIR, 1562 .access = ACCESS_RO, 1563 }, 1564 {}, 1565 }; 1566 const struct rule layer2_subs[] = { 1567 { 1568 .path = dir_s1d2, 1569 .access = ACCESS_RO, 1570 }, 1571 { 1572 .path = dir_s2d2, 1573 .access = ACCESS_RO, 1574 }, 1575 {}, 1576 }; 1577 int dirfd, ruleset_fd; 1578 1579 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 1580 ASSERT_LE(0, ruleset_fd); 1581 enforce_ruleset(_metadata, ruleset_fd); 1582 ASSERT_EQ(0, close(ruleset_fd)); 1583 1584 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs); 1585 1586 ASSERT_LE(0, ruleset_fd); 1587 switch (rel) { 1588 case REL_OPEN: 1589 case REL_CHDIR: 1590 break; 1591 case REL_CHROOT_ONLY: 1592 ASSERT_EQ(0, chdir(dir_s2d2)); 1593 break; 1594 case REL_CHROOT_CHDIR: 1595 ASSERT_EQ(0, chdir(dir_s1d2)); 1596 break; 1597 default: 1598 ASSERT_TRUE(false); 1599 return; 1600 } 1601 1602 set_cap(_metadata, CAP_SYS_CHROOT); 1603 enforce_ruleset(_metadata, ruleset_fd); 1604 1605 switch (rel) { 1606 case REL_OPEN: 1607 dirfd = open(dir_s1d2, O_DIRECTORY); 1608 ASSERT_LE(0, dirfd); 1609 break; 1610 case REL_CHDIR: 1611 ASSERT_EQ(0, chdir(dir_s1d2)); 1612 dirfd = AT_FDCWD; 1613 break; 1614 case REL_CHROOT_ONLY: 1615 /* Do chroot into dir_s1d2 (relative to dir_s2d2). */ 1616 ASSERT_EQ(0, chroot("../../s1d1/s1d2")) 1617 { 1618 TH_LOG("Failed to chroot: %s", strerror(errno)); 1619 } 1620 dirfd = AT_FDCWD; 1621 break; 1622 case REL_CHROOT_CHDIR: 1623 /* Do chroot into dir_s1d2. */ 1624 ASSERT_EQ(0, chroot(".")) 1625 { 1626 TH_LOG("Failed to chroot: %s", strerror(errno)); 1627 } 1628 dirfd = AT_FDCWD; 1629 break; 1630 } 1631 1632 ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES, 1633 test_open_rel(dirfd, "..", O_RDONLY)); 1634 ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY)); 1635 1636 if (rel == REL_CHROOT_ONLY) { 1637 /* The current directory is dir_s2d2. */ 1638 ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY)); 1639 } else { 1640 /* The current directory is dir_s1d2. */ 1641 ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY)); 1642 } 1643 1644 if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) { 1645 /* Checks the root dir_s1d2. */ 1646 ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY)); 1647 ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY)); 1648 ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY)); 1649 ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY)); 1650 } 1651 1652 if (rel != REL_CHROOT_CHDIR) { 1653 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY)); 1654 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY)); 1655 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3", 1656 O_RDONLY)); 1657 1658 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY)); 1659 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY)); 1660 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3", 1661 O_RDONLY)); 1662 } 1663 1664 if (rel == REL_OPEN) 1665 ASSERT_EQ(0, close(dirfd)); 1666 ASSERT_EQ(0, close(ruleset_fd)); 1667 } 1668 1669 TEST_F_FORK(layout1, relative_open) 1670 { 1671 test_relative_path(_metadata, REL_OPEN); 1672 } 1673 1674 TEST_F_FORK(layout1, relative_chdir) 1675 { 1676 test_relative_path(_metadata, REL_CHDIR); 1677 } 1678 1679 TEST_F_FORK(layout1, relative_chroot_only) 1680 { 1681 test_relative_path(_metadata, REL_CHROOT_ONLY); 1682 } 1683 1684 TEST_F_FORK(layout1, relative_chroot_chdir) 1685 { 1686 test_relative_path(_metadata, REL_CHROOT_CHDIR); 1687 } 1688 1689 static void copy_binary(struct __test_metadata *const _metadata, 1690 const char *const dst_path) 1691 { 1692 int dst_fd, src_fd; 1693 struct stat statbuf; 1694 1695 dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC); 1696 ASSERT_LE(0, dst_fd) 1697 { 1698 TH_LOG("Failed to open \"%s\": %s", dst_path, strerror(errno)); 1699 } 1700 src_fd = open(BINARY_PATH, O_RDONLY | O_CLOEXEC); 1701 ASSERT_LE(0, src_fd) 1702 { 1703 TH_LOG("Failed to open \"" BINARY_PATH "\": %s", 1704 strerror(errno)); 1705 } 1706 ASSERT_EQ(0, fstat(src_fd, &statbuf)); 1707 ASSERT_EQ(statbuf.st_size, 1708 sendfile(dst_fd, src_fd, 0, statbuf.st_size)); 1709 ASSERT_EQ(0, close(src_fd)); 1710 ASSERT_EQ(0, close(dst_fd)); 1711 } 1712 1713 static void test_execute(struct __test_metadata *const _metadata, const int err, 1714 const char *const path) 1715 { 1716 int status; 1717 char *const argv[] = { (char *)path, NULL }; 1718 const pid_t child = fork(); 1719 1720 ASSERT_LE(0, child); 1721 if (child == 0) { 1722 ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL)) 1723 { 1724 TH_LOG("Failed to execute \"%s\": %s", path, 1725 strerror(errno)); 1726 }; 1727 ASSERT_EQ(err, errno); 1728 _exit(_metadata->passed ? 2 : 1); 1729 return; 1730 } 1731 ASSERT_EQ(child, waitpid(child, &status, 0)); 1732 ASSERT_EQ(1, WIFEXITED(status)); 1733 ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status)) 1734 { 1735 TH_LOG("Unexpected return code for \"%s\": %s", path, 1736 strerror(errno)); 1737 }; 1738 } 1739 1740 TEST_F_FORK(layout1, execute) 1741 { 1742 const struct rule rules[] = { 1743 { 1744 .path = dir_s1d2, 1745 .access = LANDLOCK_ACCESS_FS_EXECUTE, 1746 }, 1747 {}, 1748 }; 1749 const int ruleset_fd = 1750 create_ruleset(_metadata, rules[0].access, rules); 1751 1752 ASSERT_LE(0, ruleset_fd); 1753 copy_binary(_metadata, file1_s1d1); 1754 copy_binary(_metadata, file1_s1d2); 1755 copy_binary(_metadata, file1_s1d3); 1756 1757 enforce_ruleset(_metadata, ruleset_fd); 1758 ASSERT_EQ(0, close(ruleset_fd)); 1759 1760 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1761 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 1762 test_execute(_metadata, EACCES, file1_s1d1); 1763 1764 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 1765 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 1766 test_execute(_metadata, 0, file1_s1d2); 1767 1768 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 1769 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1770 test_execute(_metadata, 0, file1_s1d3); 1771 } 1772 1773 TEST_F_FORK(layout1, link) 1774 { 1775 const struct rule layer1[] = { 1776 { 1777 .path = dir_s1d2, 1778 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 1779 }, 1780 {}, 1781 }; 1782 const struct rule layer2[] = { 1783 { 1784 .path = dir_s1d3, 1785 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1786 }, 1787 {}, 1788 }; 1789 int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1); 1790 1791 ASSERT_LE(0, ruleset_fd); 1792 1793 ASSERT_EQ(0, unlink(file1_s1d1)); 1794 ASSERT_EQ(0, unlink(file1_s1d2)); 1795 ASSERT_EQ(0, unlink(file1_s1d3)); 1796 1797 enforce_ruleset(_metadata, ruleset_fd); 1798 ASSERT_EQ(0, close(ruleset_fd)); 1799 1800 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 1801 ASSERT_EQ(EACCES, errno); 1802 1803 /* Denies linking because of reparenting. */ 1804 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2)); 1805 ASSERT_EQ(EXDEV, errno); 1806 ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3)); 1807 ASSERT_EQ(EXDEV, errno); 1808 ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2)); 1809 ASSERT_EQ(EXDEV, errno); 1810 1811 ASSERT_EQ(0, link(file2_s1d2, file1_s1d2)); 1812 ASSERT_EQ(0, link(file2_s1d3, file1_s1d3)); 1813 1814 /* Prepares for next unlinks. */ 1815 ASSERT_EQ(0, unlink(file2_s1d2)); 1816 ASSERT_EQ(0, unlink(file2_s1d3)); 1817 1818 ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2); 1819 ASSERT_LE(0, ruleset_fd); 1820 enforce_ruleset(_metadata, ruleset_fd); 1821 ASSERT_EQ(0, close(ruleset_fd)); 1822 1823 /* Checks that linkind doesn't require the ability to delete a file. */ 1824 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 1825 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 1826 } 1827 1828 TEST_F_FORK(layout1, rename_file) 1829 { 1830 const struct rule rules[] = { 1831 { 1832 .path = dir_s1d3, 1833 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1834 }, 1835 { 1836 .path = dir_s2d2, 1837 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1838 }, 1839 {}, 1840 }; 1841 const int ruleset_fd = 1842 create_ruleset(_metadata, rules[0].access, rules); 1843 1844 ASSERT_LE(0, ruleset_fd); 1845 1846 ASSERT_EQ(0, unlink(file1_s1d2)); 1847 1848 enforce_ruleset(_metadata, ruleset_fd); 1849 ASSERT_EQ(0, close(ruleset_fd)); 1850 1851 /* 1852 * Tries to replace a file, from a directory that allows file removal, 1853 * but to a different directory (which also allows file removal). 1854 */ 1855 ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3)); 1856 ASSERT_EQ(EXDEV, errno); 1857 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3, 1858 RENAME_EXCHANGE)); 1859 ASSERT_EQ(EXDEV, errno); 1860 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3, 1861 RENAME_EXCHANGE)); 1862 ASSERT_EQ(EXDEV, errno); 1863 1864 /* 1865 * Tries to replace a file, from a directory that denies file removal, 1866 * to a different directory (which allows file removal). 1867 */ 1868 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 1869 ASSERT_EQ(EXDEV, errno); 1870 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3, 1871 RENAME_EXCHANGE)); 1872 ASSERT_EQ(EXDEV, errno); 1873 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3, 1874 RENAME_EXCHANGE)); 1875 ASSERT_EQ(EXDEV, errno); 1876 1877 /* Exchanges files and directories that partially allow removal. */ 1878 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1, 1879 RENAME_EXCHANGE)); 1880 ASSERT_EQ(EACCES, errno); 1881 /* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */ 1882 ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1)); 1883 ASSERT_EQ(EACCES, errno); 1884 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2, 1885 RENAME_EXCHANGE)); 1886 ASSERT_EQ(EACCES, errno); 1887 /* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */ 1888 ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2)); 1889 ASSERT_EQ(EACCES, errno); 1890 1891 /* Renames files with different parents. */ 1892 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2)); 1893 ASSERT_EQ(EXDEV, errno); 1894 ASSERT_EQ(0, unlink(file1_s1d3)); 1895 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 1896 ASSERT_EQ(EXDEV, errno); 1897 1898 /* Exchanges and renames files with same parent. */ 1899 ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3, 1900 RENAME_EXCHANGE)); 1901 ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3)); 1902 1903 /* Exchanges files and directories with same parent, twice. */ 1904 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 1905 RENAME_EXCHANGE)); 1906 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 1907 RENAME_EXCHANGE)); 1908 } 1909 1910 TEST_F_FORK(layout1, rename_dir) 1911 { 1912 const struct rule rules[] = { 1913 { 1914 .path = dir_s1d2, 1915 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1916 }, 1917 { 1918 .path = dir_s2d1, 1919 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1920 }, 1921 {}, 1922 }; 1923 const int ruleset_fd = 1924 create_ruleset(_metadata, rules[0].access, rules); 1925 1926 ASSERT_LE(0, ruleset_fd); 1927 1928 /* Empties dir_s1d3 to allow renaming. */ 1929 ASSERT_EQ(0, unlink(file1_s1d3)); 1930 ASSERT_EQ(0, unlink(file2_s1d3)); 1931 1932 enforce_ruleset(_metadata, ruleset_fd); 1933 ASSERT_EQ(0, close(ruleset_fd)); 1934 1935 /* Exchanges and renames directory to a different parent. */ 1936 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, 1937 RENAME_EXCHANGE)); 1938 ASSERT_EQ(EXDEV, errno); 1939 ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3)); 1940 ASSERT_EQ(EXDEV, errno); 1941 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3, 1942 RENAME_EXCHANGE)); 1943 ASSERT_EQ(EXDEV, errno); 1944 1945 /* 1946 * Exchanges directory to the same parent, which doesn't allow 1947 * directory removal. 1948 */ 1949 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1, 1950 RENAME_EXCHANGE)); 1951 ASSERT_EQ(EACCES, errno); 1952 /* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */ 1953 ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1)); 1954 ASSERT_EQ(EACCES, errno); 1955 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2, 1956 RENAME_EXCHANGE)); 1957 ASSERT_EQ(EACCES, errno); 1958 /* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */ 1959 ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2)); 1960 ASSERT_EQ(EACCES, errno); 1961 1962 /* 1963 * Exchanges and renames directory to the same parent, which allows 1964 * directory removal. 1965 */ 1966 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2, 1967 RENAME_EXCHANGE)); 1968 ASSERT_EQ(0, unlink(dir_s1d3)); 1969 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 1970 ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3)); 1971 ASSERT_EQ(0, rmdir(dir_s1d3)); 1972 } 1973 1974 TEST_F_FORK(layout1, remove_dir) 1975 { 1976 const struct rule rules[] = { 1977 { 1978 .path = dir_s1d2, 1979 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1980 }, 1981 {}, 1982 }; 1983 const int ruleset_fd = 1984 create_ruleset(_metadata, rules[0].access, rules); 1985 1986 ASSERT_LE(0, ruleset_fd); 1987 1988 ASSERT_EQ(0, unlink(file1_s1d1)); 1989 ASSERT_EQ(0, unlink(file1_s1d2)); 1990 ASSERT_EQ(0, unlink(file1_s1d3)); 1991 ASSERT_EQ(0, unlink(file2_s1d3)); 1992 1993 enforce_ruleset(_metadata, ruleset_fd); 1994 ASSERT_EQ(0, close(ruleset_fd)); 1995 1996 ASSERT_EQ(0, rmdir(dir_s1d3)); 1997 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 1998 ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR)); 1999 2000 /* dir_s1d2 itself cannot be removed. */ 2001 ASSERT_EQ(-1, rmdir(dir_s1d2)); 2002 ASSERT_EQ(EACCES, errno); 2003 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR)); 2004 ASSERT_EQ(EACCES, errno); 2005 ASSERT_EQ(-1, rmdir(dir_s1d1)); 2006 ASSERT_EQ(EACCES, errno); 2007 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR)); 2008 ASSERT_EQ(EACCES, errno); 2009 } 2010 2011 TEST_F_FORK(layout1, remove_file) 2012 { 2013 const struct rule rules[] = { 2014 { 2015 .path = dir_s1d2, 2016 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 2017 }, 2018 {}, 2019 }; 2020 const int ruleset_fd = 2021 create_ruleset(_metadata, rules[0].access, rules); 2022 2023 ASSERT_LE(0, ruleset_fd); 2024 enforce_ruleset(_metadata, ruleset_fd); 2025 ASSERT_EQ(0, close(ruleset_fd)); 2026 2027 ASSERT_EQ(-1, unlink(file1_s1d1)); 2028 ASSERT_EQ(EACCES, errno); 2029 ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0)); 2030 ASSERT_EQ(EACCES, errno); 2031 ASSERT_EQ(0, unlink(file1_s1d2)); 2032 ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0)); 2033 } 2034 2035 static void test_make_file(struct __test_metadata *const _metadata, 2036 const __u64 access, const mode_t mode, 2037 const dev_t dev) 2038 { 2039 const struct rule rules[] = { 2040 { 2041 .path = dir_s1d2, 2042 .access = access, 2043 }, 2044 {}, 2045 }; 2046 const int ruleset_fd = create_ruleset(_metadata, access, rules); 2047 2048 ASSERT_LE(0, ruleset_fd); 2049 2050 ASSERT_EQ(0, unlink(file1_s1d1)); 2051 ASSERT_EQ(0, unlink(file2_s1d1)); 2052 ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev)) 2053 { 2054 TH_LOG("Failed to make file \"%s\": %s", file2_s1d1, 2055 strerror(errno)); 2056 }; 2057 2058 ASSERT_EQ(0, unlink(file1_s1d2)); 2059 ASSERT_EQ(0, unlink(file2_s1d2)); 2060 2061 ASSERT_EQ(0, unlink(file1_s1d3)); 2062 ASSERT_EQ(0, unlink(file2_s1d3)); 2063 2064 enforce_ruleset(_metadata, ruleset_fd); 2065 ASSERT_EQ(0, close(ruleset_fd)); 2066 2067 ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev)); 2068 ASSERT_EQ(EACCES, errno); 2069 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 2070 ASSERT_EQ(EACCES, errno); 2071 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 2072 ASSERT_EQ(EACCES, errno); 2073 2074 ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev)) 2075 { 2076 TH_LOG("Failed to make file \"%s\": %s", file1_s1d2, 2077 strerror(errno)); 2078 }; 2079 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 2080 ASSERT_EQ(0, unlink(file2_s1d2)); 2081 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 2082 2083 ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev)); 2084 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 2085 ASSERT_EQ(0, unlink(file2_s1d3)); 2086 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 2087 } 2088 2089 TEST_F_FORK(layout1, make_char) 2090 { 2091 /* Creates a /dev/null device. */ 2092 set_cap(_metadata, CAP_MKNOD); 2093 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR, 2094 makedev(1, 3)); 2095 } 2096 2097 TEST_F_FORK(layout1, make_block) 2098 { 2099 /* Creates a /dev/loop0 device. */ 2100 set_cap(_metadata, CAP_MKNOD); 2101 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK, 2102 makedev(7, 0)); 2103 } 2104 2105 TEST_F_FORK(layout1, make_reg_1) 2106 { 2107 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0); 2108 } 2109 2110 TEST_F_FORK(layout1, make_reg_2) 2111 { 2112 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0); 2113 } 2114 2115 TEST_F_FORK(layout1, make_sock) 2116 { 2117 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0); 2118 } 2119 2120 TEST_F_FORK(layout1, make_fifo) 2121 { 2122 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0); 2123 } 2124 2125 TEST_F_FORK(layout1, make_sym) 2126 { 2127 const struct rule rules[] = { 2128 { 2129 .path = dir_s1d2, 2130 .access = LANDLOCK_ACCESS_FS_MAKE_SYM, 2131 }, 2132 {}, 2133 }; 2134 const int ruleset_fd = 2135 create_ruleset(_metadata, rules[0].access, rules); 2136 2137 ASSERT_LE(0, ruleset_fd); 2138 2139 ASSERT_EQ(0, unlink(file1_s1d1)); 2140 ASSERT_EQ(0, unlink(file2_s1d1)); 2141 ASSERT_EQ(0, symlink("none", file2_s1d1)); 2142 2143 ASSERT_EQ(0, unlink(file1_s1d2)); 2144 ASSERT_EQ(0, unlink(file2_s1d2)); 2145 2146 ASSERT_EQ(0, unlink(file1_s1d3)); 2147 ASSERT_EQ(0, unlink(file2_s1d3)); 2148 2149 enforce_ruleset(_metadata, ruleset_fd); 2150 ASSERT_EQ(0, close(ruleset_fd)); 2151 2152 ASSERT_EQ(-1, symlink("none", file1_s1d1)); 2153 ASSERT_EQ(EACCES, errno); 2154 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 2155 ASSERT_EQ(EACCES, errno); 2156 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 2157 ASSERT_EQ(EACCES, errno); 2158 2159 ASSERT_EQ(0, symlink("none", file1_s1d2)); 2160 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 2161 ASSERT_EQ(0, unlink(file2_s1d2)); 2162 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 2163 2164 ASSERT_EQ(0, symlink("none", file1_s1d3)); 2165 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 2166 ASSERT_EQ(0, unlink(file2_s1d3)); 2167 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 2168 } 2169 2170 TEST_F_FORK(layout1, make_dir) 2171 { 2172 const struct rule rules[] = { 2173 { 2174 .path = dir_s1d2, 2175 .access = LANDLOCK_ACCESS_FS_MAKE_DIR, 2176 }, 2177 {}, 2178 }; 2179 const int ruleset_fd = 2180 create_ruleset(_metadata, rules[0].access, rules); 2181 2182 ASSERT_LE(0, ruleset_fd); 2183 2184 ASSERT_EQ(0, unlink(file1_s1d1)); 2185 ASSERT_EQ(0, unlink(file1_s1d2)); 2186 ASSERT_EQ(0, unlink(file1_s1d3)); 2187 2188 enforce_ruleset(_metadata, ruleset_fd); 2189 ASSERT_EQ(0, close(ruleset_fd)); 2190 2191 /* Uses file_* as directory names. */ 2192 ASSERT_EQ(-1, mkdir(file1_s1d1, 0700)); 2193 ASSERT_EQ(EACCES, errno); 2194 ASSERT_EQ(0, mkdir(file1_s1d2, 0700)); 2195 ASSERT_EQ(0, mkdir(file1_s1d3, 0700)); 2196 } 2197 2198 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd, 2199 const int open_flags) 2200 { 2201 static const char path_template[] = "/proc/self/fd/%d"; 2202 char procfd_path[sizeof(path_template) + 10]; 2203 const int procfd_path_size = 2204 snprintf(procfd_path, sizeof(procfd_path), path_template, fd); 2205 2206 ASSERT_LT(procfd_path_size, sizeof(procfd_path)); 2207 return open(procfd_path, open_flags); 2208 } 2209 2210 TEST_F_FORK(layout1, proc_unlinked_file) 2211 { 2212 const struct rule rules[] = { 2213 { 2214 .path = file1_s1d2, 2215 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2216 }, 2217 {}, 2218 }; 2219 int reg_fd, proc_fd; 2220 const int ruleset_fd = create_ruleset( 2221 _metadata, 2222 LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 2223 rules); 2224 2225 ASSERT_LE(0, ruleset_fd); 2226 enforce_ruleset(_metadata, ruleset_fd); 2227 ASSERT_EQ(0, close(ruleset_fd)); 2228 2229 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 2230 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2231 reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC); 2232 ASSERT_LE(0, reg_fd); 2233 ASSERT_EQ(0, unlink(file1_s1d2)); 2234 2235 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC); 2236 ASSERT_LE(0, proc_fd); 2237 ASSERT_EQ(0, close(proc_fd)); 2238 2239 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC); 2240 ASSERT_EQ(-1, proc_fd) 2241 { 2242 TH_LOG("Successfully opened /proc/self/fd/%d: %s", reg_fd, 2243 strerror(errno)); 2244 } 2245 ASSERT_EQ(EACCES, errno); 2246 2247 ASSERT_EQ(0, close(reg_fd)); 2248 } 2249 2250 TEST_F_FORK(layout1, proc_pipe) 2251 { 2252 int proc_fd; 2253 int pipe_fds[2]; 2254 char buf = '\0'; 2255 const struct rule rules[] = { 2256 { 2257 .path = dir_s1d2, 2258 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2259 LANDLOCK_ACCESS_FS_WRITE_FILE, 2260 }, 2261 {}, 2262 }; 2263 /* Limits read and write access to files tied to the filesystem. */ 2264 const int ruleset_fd = 2265 create_ruleset(_metadata, rules[0].access, rules); 2266 2267 ASSERT_LE(0, ruleset_fd); 2268 enforce_ruleset(_metadata, ruleset_fd); 2269 ASSERT_EQ(0, close(ruleset_fd)); 2270 2271 /* Checks enforcement for normal files. */ 2272 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 2273 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 2274 2275 /* Checks access to pipes through FD. */ 2276 ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC)); 2277 ASSERT_EQ(1, write(pipe_fds[1], ".", 1)) 2278 { 2279 TH_LOG("Failed to write in pipe: %s", strerror(errno)); 2280 } 2281 ASSERT_EQ(1, read(pipe_fds[0], &buf, 1)); 2282 ASSERT_EQ('.', buf); 2283 2284 /* Checks write access to pipe through /proc/self/fd . */ 2285 proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC); 2286 ASSERT_LE(0, proc_fd); 2287 ASSERT_EQ(1, write(proc_fd, ".", 1)) 2288 { 2289 TH_LOG("Failed to write through /proc/self/fd/%d: %s", 2290 pipe_fds[1], strerror(errno)); 2291 } 2292 ASSERT_EQ(0, close(proc_fd)); 2293 2294 /* Checks read access to pipe through /proc/self/fd . */ 2295 proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC); 2296 ASSERT_LE(0, proc_fd); 2297 buf = '\0'; 2298 ASSERT_EQ(1, read(proc_fd, &buf, 1)) 2299 { 2300 TH_LOG("Failed to read through /proc/self/fd/%d: %s", 2301 pipe_fds[1], strerror(errno)); 2302 } 2303 ASSERT_EQ(0, close(proc_fd)); 2304 2305 ASSERT_EQ(0, close(pipe_fds[0])); 2306 ASSERT_EQ(0, close(pipe_fds[1])); 2307 } 2308 2309 /* clang-format off */ 2310 FIXTURE(layout1_bind) {}; 2311 /* clang-format on */ 2312 2313 FIXTURE_SETUP(layout1_bind) 2314 { 2315 prepare_layout(_metadata); 2316 2317 create_layout1(_metadata); 2318 2319 set_cap(_metadata, CAP_SYS_ADMIN); 2320 ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL)); 2321 clear_cap(_metadata, CAP_SYS_ADMIN); 2322 } 2323 2324 FIXTURE_TEARDOWN(layout1_bind) 2325 { 2326 set_cap(_metadata, CAP_SYS_ADMIN); 2327 EXPECT_EQ(0, umount(dir_s2d2)); 2328 clear_cap(_metadata, CAP_SYS_ADMIN); 2329 2330 remove_layout1(_metadata); 2331 2332 cleanup_layout(_metadata); 2333 } 2334 2335 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; 2336 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; 2337 2338 /* 2339 * layout1_bind hierarchy: 2340 * 2341 * tmp 2342 * ├── s1d1 2343 * │ ├── f1 2344 * │ ├── f2 2345 * │ └── s1d2 2346 * │ ├── f1 2347 * │ ├── f2 2348 * │ └── s1d3 2349 * │ ├── f1 2350 * │ └── f2 2351 * ├── s2d1 2352 * │ ├── f1 2353 * │ └── s2d2 2354 * │ ├── f1 2355 * │ ├── f2 2356 * │ └── s1d3 2357 * │ ├── f1 2358 * │ └── f2 2359 * └── s3d1 2360 * └── s3d2 2361 * └── s3d3 2362 */ 2363 2364 TEST_F_FORK(layout1_bind, no_restriction) 2365 { 2366 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 2367 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 2368 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 2369 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2370 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 2371 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 2372 2373 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY)); 2374 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY)); 2375 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY)); 2376 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 2377 ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY)); 2378 ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY)); 2379 2380 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY)); 2381 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 2382 2383 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 2384 } 2385 2386 TEST_F_FORK(layout1_bind, same_content_same_file) 2387 { 2388 /* 2389 * Sets access right on parent directories of both source and 2390 * destination mount points. 2391 */ 2392 const struct rule layer1_parent[] = { 2393 { 2394 .path = dir_s1d1, 2395 .access = ACCESS_RO, 2396 }, 2397 { 2398 .path = dir_s2d1, 2399 .access = ACCESS_RW, 2400 }, 2401 {}, 2402 }; 2403 /* 2404 * Sets access rights on the same bind-mounted directories. The result 2405 * should be ACCESS_RW for both directories, but not both hierarchies 2406 * because of the first layer. 2407 */ 2408 const struct rule layer2_mount_point[] = { 2409 { 2410 .path = dir_s1d2, 2411 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2412 }, 2413 { 2414 .path = dir_s2d2, 2415 .access = ACCESS_RW, 2416 }, 2417 {}, 2418 }; 2419 /* Only allow read-access to the s1d3 hierarchies. */ 2420 const struct rule layer3_source[] = { 2421 { 2422 .path = dir_s1d3, 2423 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2424 }, 2425 {}, 2426 }; 2427 /* Removes all access rights. */ 2428 const struct rule layer4_destination[] = { 2429 { 2430 .path = bind_file1_s1d3, 2431 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 2432 }, 2433 {}, 2434 }; 2435 int ruleset_fd; 2436 2437 /* Sets rules for the parent directories. */ 2438 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent); 2439 ASSERT_LE(0, ruleset_fd); 2440 enforce_ruleset(_metadata, ruleset_fd); 2441 ASSERT_EQ(0, close(ruleset_fd)); 2442 2443 /* Checks source hierarchy. */ 2444 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 2445 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 2446 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 2447 2448 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2449 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2450 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2451 2452 /* Checks destination hierarchy. */ 2453 ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR)); 2454 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 2455 2456 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 2457 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2458 2459 /* Sets rules for the mount points. */ 2460 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point); 2461 ASSERT_LE(0, ruleset_fd); 2462 enforce_ruleset(_metadata, ruleset_fd); 2463 ASSERT_EQ(0, close(ruleset_fd)); 2464 2465 /* Checks source hierarchy. */ 2466 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 2467 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 2468 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 2469 2470 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2471 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2472 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2473 2474 /* Checks destination hierarchy. */ 2475 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY)); 2476 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY)); 2477 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 2478 2479 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 2480 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2481 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 2482 2483 /* Sets a (shared) rule only on the source. */ 2484 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source); 2485 ASSERT_LE(0, ruleset_fd); 2486 enforce_ruleset(_metadata, ruleset_fd); 2487 ASSERT_EQ(0, close(ruleset_fd)); 2488 2489 /* Checks source hierarchy. */ 2490 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY)); 2491 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2492 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2493 2494 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 2495 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 2496 ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 2497 2498 /* Checks destination hierarchy. */ 2499 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY)); 2500 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY)); 2501 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2502 2503 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 2504 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 2505 ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 2506 2507 /* Sets a (shared) rule only on the destination. */ 2508 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination); 2509 ASSERT_LE(0, ruleset_fd); 2510 enforce_ruleset(_metadata, ruleset_fd); 2511 ASSERT_EQ(0, close(ruleset_fd)); 2512 2513 /* Checks source hierarchy. */ 2514 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 2515 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 2516 2517 /* Checks destination hierarchy. */ 2518 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY)); 2519 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 2520 } 2521 2522 #define LOWER_BASE TMP_DIR "/lower" 2523 #define LOWER_DATA LOWER_BASE "/data" 2524 static const char lower_fl1[] = LOWER_DATA "/fl1"; 2525 static const char lower_dl1[] = LOWER_DATA "/dl1"; 2526 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; 2527 static const char lower_fo1[] = LOWER_DATA "/fo1"; 2528 static const char lower_do1[] = LOWER_DATA "/do1"; 2529 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; 2530 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; 2531 2532 static const char (*lower_base_files[])[] = { 2533 &lower_fl1, 2534 &lower_fo1, 2535 NULL, 2536 }; 2537 static const char (*lower_base_directories[])[] = { 2538 &lower_dl1, 2539 &lower_do1, 2540 NULL, 2541 }; 2542 static const char (*lower_sub_files[])[] = { 2543 &lower_dl1_fl2, 2544 &lower_do1_fo2, 2545 &lower_do1_fl3, 2546 NULL, 2547 }; 2548 2549 #define UPPER_BASE TMP_DIR "/upper" 2550 #define UPPER_DATA UPPER_BASE "/data" 2551 #define UPPER_WORK UPPER_BASE "/work" 2552 static const char upper_fu1[] = UPPER_DATA "/fu1"; 2553 static const char upper_du1[] = UPPER_DATA "/du1"; 2554 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; 2555 static const char upper_fo1[] = UPPER_DATA "/fo1"; 2556 static const char upper_do1[] = UPPER_DATA "/do1"; 2557 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; 2558 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; 2559 2560 static const char (*upper_base_files[])[] = { 2561 &upper_fu1, 2562 &upper_fo1, 2563 NULL, 2564 }; 2565 static const char (*upper_base_directories[])[] = { 2566 &upper_du1, 2567 &upper_do1, 2568 NULL, 2569 }; 2570 static const char (*upper_sub_files[])[] = { 2571 &upper_du1_fu2, 2572 &upper_do1_fo2, 2573 &upper_do1_fu3, 2574 NULL, 2575 }; 2576 2577 #define MERGE_BASE TMP_DIR "/merge" 2578 #define MERGE_DATA MERGE_BASE "/data" 2579 static const char merge_fl1[] = MERGE_DATA "/fl1"; 2580 static const char merge_dl1[] = MERGE_DATA "/dl1"; 2581 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; 2582 static const char merge_fu1[] = MERGE_DATA "/fu1"; 2583 static const char merge_du1[] = MERGE_DATA "/du1"; 2584 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; 2585 static const char merge_fo1[] = MERGE_DATA "/fo1"; 2586 static const char merge_do1[] = MERGE_DATA "/do1"; 2587 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; 2588 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; 2589 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; 2590 2591 static const char (*merge_base_files[])[] = { 2592 &merge_fl1, 2593 &merge_fu1, 2594 &merge_fo1, 2595 NULL, 2596 }; 2597 static const char (*merge_base_directories[])[] = { 2598 &merge_dl1, 2599 &merge_du1, 2600 &merge_do1, 2601 NULL, 2602 }; 2603 static const char (*merge_sub_files[])[] = { 2604 &merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2, 2605 &merge_do1_fl3, &merge_do1_fu3, NULL, 2606 }; 2607 2608 /* 2609 * layout2_overlay hierarchy: 2610 * 2611 * tmp 2612 * ├── lower 2613 * │ └── data 2614 * │ ├── dl1 2615 * │ │ └── fl2 2616 * │ ├── do1 2617 * │ │ ├── fl3 2618 * │ │ └── fo2 2619 * │ ├── fl1 2620 * │ └── fo1 2621 * ├── merge 2622 * │ └── data 2623 * │ ├── dl1 2624 * │ │ └── fl2 2625 * │ ├── do1 2626 * │ │ ├── fl3 2627 * │ │ ├── fo2 2628 * │ │ └── fu3 2629 * │ ├── du1 2630 * │ │ └── fu2 2631 * │ ├── fl1 2632 * │ ├── fo1 2633 * │ └── fu1 2634 * └── upper 2635 * ├── data 2636 * │ ├── do1 2637 * │ │ ├── fo2 2638 * │ │ └── fu3 2639 * │ ├── du1 2640 * │ │ └── fu2 2641 * │ ├── fo1 2642 * │ └── fu1 2643 * └── work 2644 * └── work 2645 */ 2646 2647 /* clang-format off */ 2648 FIXTURE(layout2_overlay) {}; 2649 /* clang-format on */ 2650 2651 FIXTURE_SETUP(layout2_overlay) 2652 { 2653 prepare_layout(_metadata); 2654 2655 create_directory(_metadata, LOWER_BASE); 2656 set_cap(_metadata, CAP_SYS_ADMIN); 2657 /* Creates tmpfs mount points to get deterministic overlayfs. */ 2658 ASSERT_EQ(0, mount("tmp", LOWER_BASE, "tmpfs", 0, "size=4m,mode=700")); 2659 clear_cap(_metadata, CAP_SYS_ADMIN); 2660 create_file(_metadata, lower_fl1); 2661 create_file(_metadata, lower_dl1_fl2); 2662 create_file(_metadata, lower_fo1); 2663 create_file(_metadata, lower_do1_fo2); 2664 create_file(_metadata, lower_do1_fl3); 2665 2666 create_directory(_metadata, UPPER_BASE); 2667 set_cap(_metadata, CAP_SYS_ADMIN); 2668 ASSERT_EQ(0, mount("tmp", UPPER_BASE, "tmpfs", 0, "size=4m,mode=700")); 2669 clear_cap(_metadata, CAP_SYS_ADMIN); 2670 create_file(_metadata, upper_fu1); 2671 create_file(_metadata, upper_du1_fu2); 2672 create_file(_metadata, upper_fo1); 2673 create_file(_metadata, upper_do1_fo2); 2674 create_file(_metadata, upper_do1_fu3); 2675 ASSERT_EQ(0, mkdir(UPPER_WORK, 0700)); 2676 2677 create_directory(_metadata, MERGE_DATA); 2678 set_cap(_metadata, CAP_SYS_ADMIN); 2679 set_cap(_metadata, CAP_DAC_OVERRIDE); 2680 ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0, 2681 "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA 2682 ",workdir=" UPPER_WORK)); 2683 clear_cap(_metadata, CAP_DAC_OVERRIDE); 2684 clear_cap(_metadata, CAP_SYS_ADMIN); 2685 } 2686 2687 FIXTURE_TEARDOWN(layout2_overlay) 2688 { 2689 EXPECT_EQ(0, remove_path(lower_do1_fl3)); 2690 EXPECT_EQ(0, remove_path(lower_dl1_fl2)); 2691 EXPECT_EQ(0, remove_path(lower_fl1)); 2692 EXPECT_EQ(0, remove_path(lower_do1_fo2)); 2693 EXPECT_EQ(0, remove_path(lower_fo1)); 2694 set_cap(_metadata, CAP_SYS_ADMIN); 2695 EXPECT_EQ(0, umount(LOWER_BASE)); 2696 clear_cap(_metadata, CAP_SYS_ADMIN); 2697 EXPECT_EQ(0, remove_path(LOWER_BASE)); 2698 2699 EXPECT_EQ(0, remove_path(upper_do1_fu3)); 2700 EXPECT_EQ(0, remove_path(upper_du1_fu2)); 2701 EXPECT_EQ(0, remove_path(upper_fu1)); 2702 EXPECT_EQ(0, remove_path(upper_do1_fo2)); 2703 EXPECT_EQ(0, remove_path(upper_fo1)); 2704 EXPECT_EQ(0, remove_path(UPPER_WORK "/work")); 2705 set_cap(_metadata, CAP_SYS_ADMIN); 2706 EXPECT_EQ(0, umount(UPPER_BASE)); 2707 clear_cap(_metadata, CAP_SYS_ADMIN); 2708 EXPECT_EQ(0, remove_path(UPPER_BASE)); 2709 2710 set_cap(_metadata, CAP_SYS_ADMIN); 2711 EXPECT_EQ(0, umount(MERGE_DATA)); 2712 clear_cap(_metadata, CAP_SYS_ADMIN); 2713 EXPECT_EQ(0, remove_path(MERGE_DATA)); 2714 2715 cleanup_layout(_metadata); 2716 } 2717 2718 TEST_F_FORK(layout2_overlay, no_restriction) 2719 { 2720 ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY)); 2721 ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY)); 2722 ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY)); 2723 ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY)); 2724 ASSERT_EQ(0, test_open(lower_do1, O_RDONLY)); 2725 ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY)); 2726 ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY)); 2727 2728 ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY)); 2729 ASSERT_EQ(0, test_open(upper_du1, O_RDONLY)); 2730 ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY)); 2731 ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY)); 2732 ASSERT_EQ(0, test_open(upper_do1, O_RDONLY)); 2733 ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY)); 2734 ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY)); 2735 2736 ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY)); 2737 ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY)); 2738 ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY)); 2739 ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY)); 2740 ASSERT_EQ(0, test_open(merge_du1, O_RDONLY)); 2741 ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY)); 2742 ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY)); 2743 ASSERT_EQ(0, test_open(merge_do1, O_RDONLY)); 2744 ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY)); 2745 ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY)); 2746 ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY)); 2747 } 2748 2749 #define for_each_path(path_list, path_entry, i) \ 2750 for (i = 0, path_entry = *path_list[i]; path_list[i]; \ 2751 path_entry = *path_list[++i]) 2752 2753 TEST_F_FORK(layout2_overlay, same_content_different_file) 2754 { 2755 /* Sets access right on parent directories of both layers. */ 2756 const struct rule layer1_base[] = { 2757 { 2758 .path = LOWER_BASE, 2759 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2760 }, 2761 { 2762 .path = UPPER_BASE, 2763 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2764 }, 2765 { 2766 .path = MERGE_BASE, 2767 .access = ACCESS_RW, 2768 }, 2769 {}, 2770 }; 2771 const struct rule layer2_data[] = { 2772 { 2773 .path = LOWER_DATA, 2774 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2775 }, 2776 { 2777 .path = UPPER_DATA, 2778 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2779 }, 2780 { 2781 .path = MERGE_DATA, 2782 .access = ACCESS_RW, 2783 }, 2784 {}, 2785 }; 2786 /* Sets access right on directories inside both layers. */ 2787 const struct rule layer3_subdirs[] = { 2788 { 2789 .path = lower_dl1, 2790 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2791 }, 2792 { 2793 .path = lower_do1, 2794 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2795 }, 2796 { 2797 .path = upper_du1, 2798 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2799 }, 2800 { 2801 .path = upper_do1, 2802 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2803 }, 2804 { 2805 .path = merge_dl1, 2806 .access = ACCESS_RW, 2807 }, 2808 { 2809 .path = merge_du1, 2810 .access = ACCESS_RW, 2811 }, 2812 { 2813 .path = merge_do1, 2814 .access = ACCESS_RW, 2815 }, 2816 {}, 2817 }; 2818 /* Tighten access rights to the files. */ 2819 const struct rule layer4_files[] = { 2820 { 2821 .path = lower_dl1_fl2, 2822 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2823 }, 2824 { 2825 .path = lower_do1_fo2, 2826 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2827 }, 2828 { 2829 .path = lower_do1_fl3, 2830 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2831 }, 2832 { 2833 .path = upper_du1_fu2, 2834 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2835 }, 2836 { 2837 .path = upper_do1_fo2, 2838 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2839 }, 2840 { 2841 .path = upper_do1_fu3, 2842 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2843 }, 2844 { 2845 .path = merge_dl1_fl2, 2846 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2847 LANDLOCK_ACCESS_FS_WRITE_FILE, 2848 }, 2849 { 2850 .path = merge_du1_fu2, 2851 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2852 LANDLOCK_ACCESS_FS_WRITE_FILE, 2853 }, 2854 { 2855 .path = merge_do1_fo2, 2856 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2857 LANDLOCK_ACCESS_FS_WRITE_FILE, 2858 }, 2859 { 2860 .path = merge_do1_fl3, 2861 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2862 LANDLOCK_ACCESS_FS_WRITE_FILE, 2863 }, 2864 { 2865 .path = merge_do1_fu3, 2866 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2867 LANDLOCK_ACCESS_FS_WRITE_FILE, 2868 }, 2869 {}, 2870 }; 2871 const struct rule layer5_merge_only[] = { 2872 { 2873 .path = MERGE_DATA, 2874 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2875 LANDLOCK_ACCESS_FS_WRITE_FILE, 2876 }, 2877 {}, 2878 }; 2879 int ruleset_fd; 2880 size_t i; 2881 const char *path_entry; 2882 2883 /* Sets rules on base directories (i.e. outside overlay scope). */ 2884 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 2885 ASSERT_LE(0, ruleset_fd); 2886 enforce_ruleset(_metadata, ruleset_fd); 2887 ASSERT_EQ(0, close(ruleset_fd)); 2888 2889 /* Checks lower layer. */ 2890 for_each_path(lower_base_files, path_entry, i) { 2891 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2892 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2893 } 2894 for_each_path(lower_base_directories, path_entry, i) { 2895 ASSERT_EQ(EACCES, 2896 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2897 } 2898 for_each_path(lower_sub_files, path_entry, i) { 2899 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2900 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2901 } 2902 /* Checks upper layer. */ 2903 for_each_path(upper_base_files, path_entry, i) { 2904 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2905 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2906 } 2907 for_each_path(upper_base_directories, path_entry, i) { 2908 ASSERT_EQ(EACCES, 2909 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2910 } 2911 for_each_path(upper_sub_files, path_entry, i) { 2912 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2913 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2914 } 2915 /* 2916 * Checks that access rights are independent from the lower and upper 2917 * layers: write access to upper files viewed through the merge point 2918 * is still allowed, and write access to lower file viewed (and copied) 2919 * through the merge point is still allowed. 2920 */ 2921 for_each_path(merge_base_files, path_entry, i) { 2922 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2923 } 2924 for_each_path(merge_base_directories, path_entry, i) { 2925 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2926 } 2927 for_each_path(merge_sub_files, path_entry, i) { 2928 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2929 } 2930 2931 /* Sets rules on data directories (i.e. inside overlay scope). */ 2932 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data); 2933 ASSERT_LE(0, ruleset_fd); 2934 enforce_ruleset(_metadata, ruleset_fd); 2935 ASSERT_EQ(0, close(ruleset_fd)); 2936 2937 /* Checks merge. */ 2938 for_each_path(merge_base_files, path_entry, i) { 2939 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2940 } 2941 for_each_path(merge_base_directories, path_entry, i) { 2942 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2943 } 2944 for_each_path(merge_sub_files, path_entry, i) { 2945 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2946 } 2947 2948 /* Same checks with tighter rules. */ 2949 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs); 2950 ASSERT_LE(0, ruleset_fd); 2951 enforce_ruleset(_metadata, ruleset_fd); 2952 ASSERT_EQ(0, close(ruleset_fd)); 2953 2954 /* Checks changes for lower layer. */ 2955 for_each_path(lower_base_files, path_entry, i) { 2956 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2957 } 2958 /* Checks changes for upper layer. */ 2959 for_each_path(upper_base_files, path_entry, i) { 2960 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2961 } 2962 /* Checks all merge accesses. */ 2963 for_each_path(merge_base_files, path_entry, i) { 2964 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 2965 } 2966 for_each_path(merge_base_directories, path_entry, i) { 2967 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2968 } 2969 for_each_path(merge_sub_files, path_entry, i) { 2970 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2971 } 2972 2973 /* Sets rules directly on overlayed files. */ 2974 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files); 2975 ASSERT_LE(0, ruleset_fd); 2976 enforce_ruleset(_metadata, ruleset_fd); 2977 ASSERT_EQ(0, close(ruleset_fd)); 2978 2979 /* Checks unchanged accesses on lower layer. */ 2980 for_each_path(lower_sub_files, path_entry, i) { 2981 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2982 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2983 } 2984 /* Checks unchanged accesses on upper layer. */ 2985 for_each_path(upper_sub_files, path_entry, i) { 2986 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2987 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2988 } 2989 /* Checks all merge accesses. */ 2990 for_each_path(merge_base_files, path_entry, i) { 2991 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 2992 } 2993 for_each_path(merge_base_directories, path_entry, i) { 2994 ASSERT_EQ(EACCES, 2995 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2996 } 2997 for_each_path(merge_sub_files, path_entry, i) { 2998 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2999 } 3000 3001 /* Only allowes access to the merge hierarchy. */ 3002 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only); 3003 ASSERT_LE(0, ruleset_fd); 3004 enforce_ruleset(_metadata, ruleset_fd); 3005 ASSERT_EQ(0, close(ruleset_fd)); 3006 3007 /* Checks new accesses on lower layer. */ 3008 for_each_path(lower_sub_files, path_entry, i) { 3009 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 3010 } 3011 /* Checks new accesses on upper layer. */ 3012 for_each_path(upper_sub_files, path_entry, i) { 3013 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 3014 } 3015 /* Checks all merge accesses. */ 3016 for_each_path(merge_base_files, path_entry, i) { 3017 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 3018 } 3019 for_each_path(merge_base_directories, path_entry, i) { 3020 ASSERT_EQ(EACCES, 3021 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 3022 } 3023 for_each_path(merge_sub_files, path_entry, i) { 3024 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 3025 } 3026 } 3027 3028 TEST_HARNESS_MAIN 3029