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