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