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