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