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