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