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