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