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