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