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 enum relative_access { 1836 REL_OPEN, 1837 REL_CHDIR, 1838 REL_CHROOT_ONLY, 1839 REL_CHROOT_CHDIR, 1840 }; 1841 1842 static void test_relative_path(struct __test_metadata *const _metadata, 1843 const enum relative_access rel) 1844 { 1845 /* 1846 * Common layer to check that chroot doesn't ignore it (i.e. a chroot 1847 * is not a disconnected root directory). 1848 */ 1849 const struct rule layer1_base[] = { 1850 { 1851 .path = TMP_DIR, 1852 .access = ACCESS_RO, 1853 }, 1854 {}, 1855 }; 1856 const struct rule layer2_subs[] = { 1857 { 1858 .path = dir_s1d2, 1859 .access = ACCESS_RO, 1860 }, 1861 { 1862 .path = dir_s2d2, 1863 .access = ACCESS_RO, 1864 }, 1865 {}, 1866 }; 1867 int dirfd, ruleset_fd; 1868 1869 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 1870 ASSERT_LE(0, ruleset_fd); 1871 enforce_ruleset(_metadata, ruleset_fd); 1872 ASSERT_EQ(0, close(ruleset_fd)); 1873 1874 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs); 1875 1876 ASSERT_LE(0, ruleset_fd); 1877 switch (rel) { 1878 case REL_OPEN: 1879 case REL_CHDIR: 1880 break; 1881 case REL_CHROOT_ONLY: 1882 ASSERT_EQ(0, chdir(dir_s2d2)); 1883 break; 1884 case REL_CHROOT_CHDIR: 1885 ASSERT_EQ(0, chdir(dir_s1d2)); 1886 break; 1887 default: 1888 ASSERT_TRUE(false); 1889 return; 1890 } 1891 1892 set_cap(_metadata, CAP_SYS_CHROOT); 1893 enforce_ruleset(_metadata, ruleset_fd); 1894 1895 switch (rel) { 1896 case REL_OPEN: 1897 dirfd = open(dir_s1d2, O_DIRECTORY); 1898 ASSERT_LE(0, dirfd); 1899 break; 1900 case REL_CHDIR: 1901 ASSERT_EQ(0, chdir(dir_s1d2)); 1902 dirfd = AT_FDCWD; 1903 break; 1904 case REL_CHROOT_ONLY: 1905 /* Do chroot into dir_s1d2 (relative to dir_s2d2). */ 1906 ASSERT_EQ(0, chroot("../../s1d1/s1d2")) 1907 { 1908 TH_LOG("Failed to chroot: %s", strerror(errno)); 1909 } 1910 dirfd = AT_FDCWD; 1911 break; 1912 case REL_CHROOT_CHDIR: 1913 /* Do chroot into dir_s1d2. */ 1914 ASSERT_EQ(0, chroot(".")) 1915 { 1916 TH_LOG("Failed to chroot: %s", strerror(errno)); 1917 } 1918 dirfd = AT_FDCWD; 1919 break; 1920 } 1921 1922 ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES, 1923 test_open_rel(dirfd, "..", O_RDONLY)); 1924 ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY)); 1925 1926 if (rel == REL_CHROOT_ONLY) { 1927 /* The current directory is dir_s2d2. */ 1928 ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY)); 1929 } else { 1930 /* The current directory is dir_s1d2. */ 1931 ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY)); 1932 } 1933 1934 if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) { 1935 /* Checks the root dir_s1d2. */ 1936 ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY)); 1937 ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY)); 1938 ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY)); 1939 ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY)); 1940 } 1941 1942 if (rel != REL_CHROOT_CHDIR) { 1943 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY)); 1944 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY)); 1945 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3", 1946 O_RDONLY)); 1947 1948 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY)); 1949 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY)); 1950 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3", 1951 O_RDONLY)); 1952 } 1953 1954 if (rel == REL_OPEN) 1955 ASSERT_EQ(0, close(dirfd)); 1956 ASSERT_EQ(0, close(ruleset_fd)); 1957 } 1958 1959 TEST_F_FORK(layout1, relative_open) 1960 { 1961 test_relative_path(_metadata, REL_OPEN); 1962 } 1963 1964 TEST_F_FORK(layout1, relative_chdir) 1965 { 1966 test_relative_path(_metadata, REL_CHDIR); 1967 } 1968 1969 TEST_F_FORK(layout1, relative_chroot_only) 1970 { 1971 test_relative_path(_metadata, REL_CHROOT_ONLY); 1972 } 1973 1974 TEST_F_FORK(layout1, relative_chroot_chdir) 1975 { 1976 test_relative_path(_metadata, REL_CHROOT_CHDIR); 1977 } 1978 1979 static void copy_file(struct __test_metadata *const _metadata, 1980 const char *const src_path, const char *const dst_path) 1981 { 1982 int dst_fd, src_fd; 1983 struct stat statbuf; 1984 1985 dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC); 1986 ASSERT_LE(0, dst_fd) 1987 { 1988 TH_LOG("Failed to open \"%s\": %s", dst_path, strerror(errno)); 1989 } 1990 src_fd = open(src_path, O_RDONLY | O_CLOEXEC); 1991 ASSERT_LE(0, src_fd) 1992 { 1993 TH_LOG("Failed to open \"%s\": %s", src_path, strerror(errno)); 1994 } 1995 ASSERT_EQ(0, fstat(src_fd, &statbuf)); 1996 ASSERT_EQ(statbuf.st_size, 1997 sendfile(dst_fd, src_fd, 0, statbuf.st_size)); 1998 ASSERT_EQ(0, close(src_fd)); 1999 ASSERT_EQ(0, close(dst_fd)); 2000 } 2001 2002 static void test_execute(struct __test_metadata *const _metadata, const int err, 2003 const char *const path) 2004 { 2005 int status; 2006 char *const argv[] = { (char *)path, NULL }; 2007 const pid_t child = fork(); 2008 2009 ASSERT_LE(0, child); 2010 if (child == 0) { 2011 ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL)) 2012 { 2013 TH_LOG("Failed to execute \"%s\": %s", path, 2014 strerror(errno)); 2015 }; 2016 ASSERT_EQ(err, errno); 2017 _exit(__test_passed(_metadata) ? 2 : 1); 2018 return; 2019 } 2020 ASSERT_EQ(child, waitpid(child, &status, 0)); 2021 ASSERT_EQ(1, WIFEXITED(status)); 2022 ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status)) 2023 { 2024 TH_LOG("Unexpected return code for \"%s\"", path); 2025 }; 2026 } 2027 2028 static void test_check_exec(struct __test_metadata *const _metadata, 2029 const int err, const char *const path) 2030 { 2031 int ret; 2032 char *const argv[] = { (char *)path, NULL }; 2033 2034 ret = sys_execveat(AT_FDCWD, path, argv, NULL, 2035 AT_EMPTY_PATH | AT_EXECVE_CHECK); 2036 if (err) { 2037 EXPECT_EQ(-1, ret); 2038 EXPECT_EQ(errno, err); 2039 } else { 2040 EXPECT_EQ(0, ret); 2041 } 2042 } 2043 2044 TEST_F_FORK(layout1, execute) 2045 { 2046 const struct rule rules[] = { 2047 { 2048 .path = dir_s1d2, 2049 .access = LANDLOCK_ACCESS_FS_EXECUTE, 2050 }, 2051 {}, 2052 }; 2053 const int ruleset_fd = 2054 create_ruleset(_metadata, rules[0].access, rules); 2055 2056 ASSERT_LE(0, ruleset_fd); 2057 copy_file(_metadata, bin_true, file1_s1d1); 2058 copy_file(_metadata, bin_true, file1_s1d2); 2059 copy_file(_metadata, bin_true, file1_s1d3); 2060 2061 /* Checks before file1_s1d1 being denied. */ 2062 test_execute(_metadata, 0, file1_s1d1); 2063 test_check_exec(_metadata, 0, file1_s1d1); 2064 2065 enforce_ruleset(_metadata, ruleset_fd); 2066 ASSERT_EQ(0, close(ruleset_fd)); 2067 2068 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 2069 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 2070 test_execute(_metadata, EACCES, file1_s1d1); 2071 test_check_exec(_metadata, EACCES, file1_s1d1); 2072 2073 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 2074 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2075 test_execute(_metadata, 0, file1_s1d2); 2076 test_check_exec(_metadata, 0, file1_s1d2); 2077 2078 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 2079 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 2080 test_execute(_metadata, 0, file1_s1d3); 2081 test_check_exec(_metadata, 0, file1_s1d3); 2082 } 2083 2084 TEST_F_FORK(layout1, umount_sandboxer) 2085 { 2086 int pipe_child[2], pipe_parent[2]; 2087 char buf_parent; 2088 pid_t child; 2089 int status; 2090 2091 copy_file(_metadata, bin_sandbox_and_launch, file1_s3d3); 2092 ASSERT_EQ(0, pipe2(pipe_child, 0)); 2093 ASSERT_EQ(0, pipe2(pipe_parent, 0)); 2094 2095 child = fork(); 2096 ASSERT_LE(0, child); 2097 if (child == 0) { 2098 char pipe_child_str[12], pipe_parent_str[12]; 2099 char *const argv[] = { (char *)file1_s3d3, 2100 (char *)bin_wait_pipe, pipe_child_str, 2101 pipe_parent_str, NULL }; 2102 2103 /* Passes the pipe FDs to the executed binary and its child. */ 2104 EXPECT_EQ(0, close(pipe_child[0])); 2105 EXPECT_EQ(0, close(pipe_parent[1])); 2106 snprintf(pipe_child_str, sizeof(pipe_child_str), "%d", 2107 pipe_child[1]); 2108 snprintf(pipe_parent_str, sizeof(pipe_parent_str), "%d", 2109 pipe_parent[0]); 2110 2111 /* 2112 * We need bin_sandbox_and_launch (copied inside the mount as 2113 * file1_s3d3) to execute bin_wait_pipe (outside the mount) to 2114 * make sure the mount point will not be EBUSY because of 2115 * file1_s3d3 being in use. This avoids a potential race 2116 * condition between the following read() and umount() calls. 2117 */ 2118 ASSERT_EQ(0, execve(argv[0], argv, NULL)) 2119 { 2120 TH_LOG("Failed to execute \"%s\": %s", argv[0], 2121 strerror(errno)); 2122 }; 2123 _exit(1); 2124 return; 2125 } 2126 2127 EXPECT_EQ(0, close(pipe_child[1])); 2128 EXPECT_EQ(0, close(pipe_parent[0])); 2129 2130 /* Waits for the child to sandbox itself. */ 2131 EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1)); 2132 2133 /* Tests that the sandboxer is tied to its mount point. */ 2134 set_cap(_metadata, CAP_SYS_ADMIN); 2135 EXPECT_EQ(-1, umount(dir_s3d2)); 2136 EXPECT_EQ(EBUSY, errno); 2137 clear_cap(_metadata, CAP_SYS_ADMIN); 2138 2139 /* Signals the child to launch a grandchild. */ 2140 EXPECT_EQ(1, write(pipe_parent[1], ".", 1)); 2141 2142 /* Waits for the grandchild. */ 2143 EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1)); 2144 2145 /* Tests that the domain's sandboxer is not tied to its mount point. */ 2146 set_cap(_metadata, CAP_SYS_ADMIN); 2147 EXPECT_EQ(0, umount(dir_s3d2)) 2148 { 2149 TH_LOG("Failed to umount \"%s\": %s", dir_s3d2, 2150 strerror(errno)); 2151 }; 2152 clear_cap(_metadata, CAP_SYS_ADMIN); 2153 2154 /* Signals the grandchild to terminate. */ 2155 EXPECT_EQ(1, write(pipe_parent[1], ".", 1)); 2156 ASSERT_EQ(child, waitpid(child, &status, 0)); 2157 ASSERT_EQ(1, WIFEXITED(status)); 2158 ASSERT_EQ(0, WEXITSTATUS(status)); 2159 } 2160 2161 TEST_F_FORK(layout1, link) 2162 { 2163 const struct rule layer1[] = { 2164 { 2165 .path = dir_s1d2, 2166 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2167 }, 2168 {}, 2169 }; 2170 const struct rule layer2[] = { 2171 { 2172 .path = dir_s1d3, 2173 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 2174 }, 2175 {}, 2176 }; 2177 int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1); 2178 2179 ASSERT_LE(0, ruleset_fd); 2180 2181 ASSERT_EQ(0, unlink(file1_s1d1)); 2182 ASSERT_EQ(0, unlink(file1_s1d2)); 2183 ASSERT_EQ(0, unlink(file1_s1d3)); 2184 2185 enforce_ruleset(_metadata, ruleset_fd); 2186 ASSERT_EQ(0, close(ruleset_fd)); 2187 2188 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 2189 ASSERT_EQ(EACCES, errno); 2190 2191 /* Denies linking because of reparenting. */ 2192 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2)); 2193 ASSERT_EQ(EXDEV, errno); 2194 ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3)); 2195 ASSERT_EQ(EXDEV, errno); 2196 ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2)); 2197 ASSERT_EQ(EXDEV, errno); 2198 2199 ASSERT_EQ(0, link(file2_s1d2, file1_s1d2)); 2200 ASSERT_EQ(0, link(file2_s1d3, file1_s1d3)); 2201 2202 /* Prepares for next unlinks. */ 2203 ASSERT_EQ(0, unlink(file2_s1d2)); 2204 ASSERT_EQ(0, unlink(file2_s1d3)); 2205 2206 ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2); 2207 ASSERT_LE(0, ruleset_fd); 2208 enforce_ruleset(_metadata, ruleset_fd); 2209 ASSERT_EQ(0, close(ruleset_fd)); 2210 2211 /* Checks that linkind doesn't require the ability to delete a file. */ 2212 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 2213 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 2214 } 2215 2216 static int test_rename(const char *const oldpath, const char *const newpath) 2217 { 2218 if (rename(oldpath, newpath)) 2219 return errno; 2220 return 0; 2221 } 2222 2223 static int test_exchange(const char *const oldpath, const char *const newpath) 2224 { 2225 if (renameat2(AT_FDCWD, oldpath, AT_FDCWD, newpath, RENAME_EXCHANGE)) 2226 return errno; 2227 return 0; 2228 } 2229 2230 TEST_F_FORK(layout1, rename_file) 2231 { 2232 const struct rule rules[] = { 2233 { 2234 .path = dir_s1d3, 2235 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 2236 }, 2237 { 2238 .path = dir_s2d2, 2239 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 2240 }, 2241 {}, 2242 }; 2243 const int ruleset_fd = 2244 create_ruleset(_metadata, rules[0].access, rules); 2245 2246 ASSERT_LE(0, ruleset_fd); 2247 2248 ASSERT_EQ(0, unlink(file1_s1d2)); 2249 2250 enforce_ruleset(_metadata, ruleset_fd); 2251 ASSERT_EQ(0, close(ruleset_fd)); 2252 2253 /* 2254 * Tries to replace a file, from a directory that allows file removal, 2255 * but to a different directory (which also allows file removal). 2256 */ 2257 ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3)); 2258 ASSERT_EQ(EXDEV, errno); 2259 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3, 2260 RENAME_EXCHANGE)); 2261 ASSERT_EQ(EXDEV, errno); 2262 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3, 2263 RENAME_EXCHANGE)); 2264 ASSERT_EQ(EXDEV, errno); 2265 2266 /* 2267 * Tries to replace a file, from a directory that denies file removal, 2268 * to a different directory (which allows file removal). 2269 */ 2270 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 2271 ASSERT_EQ(EACCES, errno); 2272 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3, 2273 RENAME_EXCHANGE)); 2274 ASSERT_EQ(EACCES, errno); 2275 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3, 2276 RENAME_EXCHANGE)); 2277 ASSERT_EQ(EXDEV, errno); 2278 2279 /* Exchanges files and directories that partially allow removal. */ 2280 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1, 2281 RENAME_EXCHANGE)); 2282 ASSERT_EQ(EACCES, errno); 2283 /* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */ 2284 ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1)); 2285 ASSERT_EQ(EACCES, errno); 2286 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2, 2287 RENAME_EXCHANGE)); 2288 ASSERT_EQ(EACCES, errno); 2289 /* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */ 2290 ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2)); 2291 ASSERT_EQ(EACCES, errno); 2292 2293 /* Renames files with different parents. */ 2294 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2)); 2295 ASSERT_EQ(EXDEV, errno); 2296 ASSERT_EQ(0, unlink(file1_s1d3)); 2297 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 2298 ASSERT_EQ(EACCES, errno); 2299 2300 /* Exchanges and renames files with same parent. */ 2301 ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3, 2302 RENAME_EXCHANGE)); 2303 ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3)); 2304 2305 /* Exchanges files and directories with same parent, twice. */ 2306 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 2307 RENAME_EXCHANGE)); 2308 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 2309 RENAME_EXCHANGE)); 2310 } 2311 2312 TEST_F_FORK(layout1, rename_dir) 2313 { 2314 const struct rule rules[] = { 2315 { 2316 .path = dir_s1d2, 2317 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 2318 }, 2319 { 2320 .path = dir_s2d1, 2321 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 2322 }, 2323 {}, 2324 }; 2325 const int ruleset_fd = 2326 create_ruleset(_metadata, rules[0].access, rules); 2327 2328 ASSERT_LE(0, ruleset_fd); 2329 2330 /* Empties dir_s1d3 to allow renaming. */ 2331 ASSERT_EQ(0, unlink(file1_s1d3)); 2332 ASSERT_EQ(0, unlink(file2_s1d3)); 2333 2334 enforce_ruleset(_metadata, ruleset_fd); 2335 ASSERT_EQ(0, close(ruleset_fd)); 2336 2337 /* Exchanges and renames directory to a different parent. */ 2338 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, 2339 RENAME_EXCHANGE)); 2340 ASSERT_EQ(EXDEV, errno); 2341 ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3)); 2342 ASSERT_EQ(EXDEV, errno); 2343 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3, 2344 RENAME_EXCHANGE)); 2345 ASSERT_EQ(EXDEV, errno); 2346 2347 /* 2348 * Exchanges directory to the same parent, which doesn't allow 2349 * directory removal. 2350 */ 2351 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1, 2352 RENAME_EXCHANGE)); 2353 ASSERT_EQ(EACCES, errno); 2354 /* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */ 2355 ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1)); 2356 ASSERT_EQ(EACCES, errno); 2357 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2, 2358 RENAME_EXCHANGE)); 2359 ASSERT_EQ(EACCES, errno); 2360 /* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */ 2361 ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2)); 2362 ASSERT_EQ(EACCES, errno); 2363 2364 /* 2365 * Exchanges and renames directory to the same parent, which allows 2366 * directory removal. 2367 */ 2368 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2, 2369 RENAME_EXCHANGE)); 2370 ASSERT_EQ(0, unlink(dir_s1d3)); 2371 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 2372 ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3)); 2373 ASSERT_EQ(0, rmdir(dir_s1d3)); 2374 } 2375 2376 TEST_F_FORK(layout1, reparent_refer) 2377 { 2378 const struct rule layer1[] = { 2379 { 2380 .path = dir_s1d2, 2381 .access = LANDLOCK_ACCESS_FS_REFER, 2382 }, 2383 { 2384 .path = dir_s2d2, 2385 .access = LANDLOCK_ACCESS_FS_REFER, 2386 }, 2387 {}, 2388 }; 2389 int ruleset_fd = 2390 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 2391 2392 ASSERT_LE(0, ruleset_fd); 2393 enforce_ruleset(_metadata, ruleset_fd); 2394 ASSERT_EQ(0, close(ruleset_fd)); 2395 2396 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d1)); 2397 ASSERT_EQ(EXDEV, errno); 2398 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d2)); 2399 ASSERT_EQ(EXDEV, errno); 2400 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3)); 2401 ASSERT_EQ(EXDEV, errno); 2402 2403 ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d1)); 2404 ASSERT_EQ(EXDEV, errno); 2405 ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d2)); 2406 ASSERT_EQ(EXDEV, errno); 2407 /* 2408 * Moving should only be allowed when the source and the destination 2409 * parent directory have REFER. 2410 */ 2411 ASSERT_EQ(-1, rename(dir_s1d3, dir_s2d3)); 2412 ASSERT_EQ(ENOTEMPTY, errno); 2413 ASSERT_EQ(0, unlink(file1_s2d3)); 2414 ASSERT_EQ(0, unlink(file2_s2d3)); 2415 ASSERT_EQ(0, rename(dir_s1d3, dir_s2d3)); 2416 } 2417 2418 /* Checks renames beneath dir_s1d1. */ 2419 static void refer_denied_by_default(struct __test_metadata *const _metadata, 2420 const struct rule layer1[], 2421 const int layer1_err, 2422 const struct rule layer2[]) 2423 { 2424 int ruleset_fd; 2425 2426 ASSERT_EQ(0, unlink(file1_s1d2)); 2427 2428 ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1); 2429 ASSERT_LE(0, ruleset_fd); 2430 enforce_ruleset(_metadata, ruleset_fd); 2431 ASSERT_EQ(0, close(ruleset_fd)); 2432 2433 /* 2434 * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to 2435 * layer1_err), then it allows some different-parent renames and links. 2436 */ 2437 ASSERT_EQ(layer1_err, test_rename(file1_s1d1, file1_s1d2)); 2438 if (layer1_err == 0) 2439 ASSERT_EQ(layer1_err, test_rename(file1_s1d2, file1_s1d1)); 2440 ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2)); 2441 ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1)); 2442 2443 ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2); 2444 ASSERT_LE(0, ruleset_fd); 2445 enforce_ruleset(_metadata, ruleset_fd); 2446 ASSERT_EQ(0, close(ruleset_fd)); 2447 2448 /* 2449 * Now, either the first or the second layer does not handle 2450 * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent 2451 * renames and links are denied, thus making the layer handling 2452 * LANDLOCK_ACCESS_FS_REFER null and void. 2453 */ 2454 ASSERT_EQ(EXDEV, test_rename(file1_s1d1, file1_s1d2)); 2455 ASSERT_EQ(EXDEV, test_exchange(file2_s1d1, file2_s1d2)); 2456 ASSERT_EQ(EXDEV, test_exchange(file2_s1d2, file2_s1d1)); 2457 } 2458 2459 const struct rule layer_dir_s1d1_refer[] = { 2460 { 2461 .path = dir_s1d1, 2462 .access = LANDLOCK_ACCESS_FS_REFER, 2463 }, 2464 {}, 2465 }; 2466 2467 const struct rule layer_dir_s1d1_execute[] = { 2468 { 2469 /* Matches a parent directory. */ 2470 .path = dir_s1d1, 2471 .access = LANDLOCK_ACCESS_FS_EXECUTE, 2472 }, 2473 {}, 2474 }; 2475 2476 const struct rule layer_dir_s2d1_execute[] = { 2477 { 2478 /* Does not match a parent directory. */ 2479 .path = dir_s2d1, 2480 .access = LANDLOCK_ACCESS_FS_EXECUTE, 2481 }, 2482 {}, 2483 }; 2484 2485 /* 2486 * Tests precedence over renames: denied by default for different parent 2487 * directories, *with* a rule matching a parent directory, but not directly 2488 * denying access (with MAKE_REG nor REMOVE). 2489 */ 2490 TEST_F_FORK(layout1, refer_denied_by_default1) 2491 { 2492 refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0, 2493 layer_dir_s1d1_execute); 2494 } 2495 2496 /* 2497 * Same test but this time turning around the ABI version order: the first 2498 * layer does not handle LANDLOCK_ACCESS_FS_REFER. 2499 */ 2500 TEST_F_FORK(layout1, refer_denied_by_default2) 2501 { 2502 refer_denied_by_default(_metadata, layer_dir_s1d1_execute, EXDEV, 2503 layer_dir_s1d1_refer); 2504 } 2505 2506 /* 2507 * Tests precedence over renames: denied by default for different parent 2508 * directories, *without* a rule matching a parent directory, but not directly 2509 * denying access (with MAKE_REG nor REMOVE). 2510 */ 2511 TEST_F_FORK(layout1, refer_denied_by_default3) 2512 { 2513 refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0, 2514 layer_dir_s2d1_execute); 2515 } 2516 2517 /* 2518 * Same test but this time turning around the ABI version order: the first 2519 * layer does not handle LANDLOCK_ACCESS_FS_REFER. 2520 */ 2521 TEST_F_FORK(layout1, refer_denied_by_default4) 2522 { 2523 refer_denied_by_default(_metadata, layer_dir_s2d1_execute, EXDEV, 2524 layer_dir_s1d1_refer); 2525 } 2526 2527 /* 2528 * Tests walking through a denied root mount. 2529 */ 2530 TEST_F_FORK(layout1, refer_mount_root_deny) 2531 { 2532 const struct landlock_ruleset_attr ruleset_attr = { 2533 .handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_DIR, 2534 }; 2535 int root_fd, ruleset_fd; 2536 2537 /* Creates a mount object from a non-mount point. */ 2538 set_cap(_metadata, CAP_SYS_ADMIN); 2539 root_fd = 2540 open_tree(AT_FDCWD, dir_s1d1, 2541 AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC); 2542 clear_cap(_metadata, CAP_SYS_ADMIN); 2543 ASSERT_LE(0, root_fd); 2544 2545 ruleset_fd = 2546 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 2547 ASSERT_LE(0, ruleset_fd); 2548 2549 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 2550 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 2551 EXPECT_EQ(0, close(ruleset_fd)); 2552 2553 /* Link denied by Landlock: EACCES. */ 2554 EXPECT_EQ(-1, linkat(root_fd, ".", root_fd, "does_not_exist", 0)); 2555 EXPECT_EQ(EACCES, errno); 2556 2557 /* renameat2() always returns EBUSY. */ 2558 EXPECT_EQ(-1, renameat2(root_fd, ".", root_fd, "does_not_exist", 0)); 2559 EXPECT_EQ(EBUSY, errno); 2560 2561 EXPECT_EQ(0, close(root_fd)); 2562 } 2563 2564 TEST_F_FORK(layout1, refer_part_mount_tree_is_allowed) 2565 { 2566 const struct rule layer1[] = { 2567 { 2568 /* Parent mount point. */ 2569 .path = dir_s3d1, 2570 .access = LANDLOCK_ACCESS_FS_REFER | 2571 LANDLOCK_ACCESS_FS_MAKE_REG, 2572 }, 2573 { 2574 /* 2575 * Removing the source file is allowed because its 2576 * access rights are already a superset of the 2577 * destination. 2578 */ 2579 .path = dir_s3d4, 2580 .access = LANDLOCK_ACCESS_FS_REFER | 2581 LANDLOCK_ACCESS_FS_MAKE_REG | 2582 LANDLOCK_ACCESS_FS_REMOVE_FILE, 2583 }, 2584 {}, 2585 }; 2586 int ruleset_fd; 2587 2588 ASSERT_EQ(0, unlink(file1_s3d3)); 2589 ruleset_fd = create_ruleset(_metadata, 2590 LANDLOCK_ACCESS_FS_REFER | 2591 LANDLOCK_ACCESS_FS_MAKE_REG | 2592 LANDLOCK_ACCESS_FS_REMOVE_FILE, 2593 layer1); 2594 2595 ASSERT_LE(0, ruleset_fd); 2596 enforce_ruleset(_metadata, ruleset_fd); 2597 ASSERT_EQ(0, close(ruleset_fd)); 2598 2599 ASSERT_EQ(0, rename(file1_s3d4, file1_s3d3)); 2600 } 2601 2602 TEST_F_FORK(layout1, reparent_link) 2603 { 2604 const struct rule layer1[] = { 2605 { 2606 .path = dir_s1d2, 2607 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2608 }, 2609 { 2610 .path = dir_s1d3, 2611 .access = LANDLOCK_ACCESS_FS_REFER, 2612 }, 2613 { 2614 .path = dir_s2d2, 2615 .access = LANDLOCK_ACCESS_FS_REFER, 2616 }, 2617 { 2618 .path = dir_s2d3, 2619 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2620 }, 2621 {}, 2622 }; 2623 const int ruleset_fd = create_ruleset( 2624 _metadata, 2625 LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2626 2627 ASSERT_LE(0, ruleset_fd); 2628 enforce_ruleset(_metadata, ruleset_fd); 2629 ASSERT_EQ(0, close(ruleset_fd)); 2630 2631 ASSERT_EQ(0, unlink(file1_s1d1)); 2632 ASSERT_EQ(0, unlink(file1_s1d2)); 2633 ASSERT_EQ(0, unlink(file1_s1d3)); 2634 2635 /* Denies linking because of missing MAKE_REG. */ 2636 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 2637 ASSERT_EQ(EACCES, errno); 2638 /* Denies linking because of missing source and destination REFER. */ 2639 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2)); 2640 ASSERT_EQ(EXDEV, errno); 2641 /* Denies linking because of missing source REFER. */ 2642 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d3)); 2643 ASSERT_EQ(EXDEV, errno); 2644 2645 /* Denies linking because of missing MAKE_REG. */ 2646 ASSERT_EQ(-1, link(file1_s2d2, file1_s1d1)); 2647 ASSERT_EQ(EACCES, errno); 2648 /* Denies linking because of missing destination REFER. */ 2649 ASSERT_EQ(-1, link(file1_s2d2, file1_s1d2)); 2650 ASSERT_EQ(EXDEV, errno); 2651 2652 /* Allows linking because of REFER and MAKE_REG. */ 2653 ASSERT_EQ(0, link(file1_s2d2, file1_s1d3)); 2654 ASSERT_EQ(0, unlink(file1_s2d2)); 2655 /* Reverse linking denied because of missing MAKE_REG. */ 2656 ASSERT_EQ(-1, link(file1_s1d3, file1_s2d2)); 2657 ASSERT_EQ(EACCES, errno); 2658 ASSERT_EQ(0, unlink(file1_s2d3)); 2659 /* Checks reverse linking. */ 2660 ASSERT_EQ(0, link(file1_s1d3, file1_s2d3)); 2661 ASSERT_EQ(0, unlink(file1_s1d3)); 2662 2663 /* 2664 * This is OK for a file link, but it should not be allowed for a 2665 * directory rename (because of the superset of access rights. 2666 */ 2667 ASSERT_EQ(0, link(file1_s2d3, file1_s1d3)); 2668 ASSERT_EQ(0, unlink(file1_s1d3)); 2669 2670 ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3)); 2671 ASSERT_EQ(EXDEV, errno); 2672 ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2)); 2673 ASSERT_EQ(EXDEV, errno); 2674 2675 ASSERT_EQ(0, link(file2_s1d2, file1_s1d2)); 2676 ASSERT_EQ(0, link(file2_s1d3, file1_s1d3)); 2677 } 2678 2679 TEST_F_FORK(layout1, reparent_rename) 2680 { 2681 /* Same rules as for reparent_link. */ 2682 const struct rule layer1[] = { 2683 { 2684 .path = dir_s1d2, 2685 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2686 }, 2687 { 2688 .path = dir_s1d3, 2689 .access = LANDLOCK_ACCESS_FS_REFER, 2690 }, 2691 { 2692 .path = dir_s2d2, 2693 .access = LANDLOCK_ACCESS_FS_REFER, 2694 }, 2695 { 2696 .path = dir_s2d3, 2697 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2698 }, 2699 {}, 2700 }; 2701 const int ruleset_fd = create_ruleset( 2702 _metadata, 2703 LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2704 2705 ASSERT_LE(0, ruleset_fd); 2706 enforce_ruleset(_metadata, ruleset_fd); 2707 ASSERT_EQ(0, close(ruleset_fd)); 2708 2709 ASSERT_EQ(0, unlink(file1_s1d2)); 2710 ASSERT_EQ(0, unlink(file1_s1d3)); 2711 2712 /* Denies renaming because of missing MAKE_REG. */ 2713 ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s1d1, 2714 RENAME_EXCHANGE)); 2715 ASSERT_EQ(EACCES, errno); 2716 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file2_s1d1, 2717 RENAME_EXCHANGE)); 2718 ASSERT_EQ(EACCES, errno); 2719 ASSERT_EQ(0, unlink(file1_s1d1)); 2720 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 2721 ASSERT_EQ(EACCES, errno); 2722 /* Even denies same file exchange. */ 2723 ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file2_s1d1, 2724 RENAME_EXCHANGE)); 2725 ASSERT_EQ(EACCES, errno); 2726 2727 /* Denies renaming because of missing source and destination REFER. */ 2728 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d2)); 2729 ASSERT_EQ(EXDEV, errno); 2730 /* 2731 * Denies renaming because of missing MAKE_REG, source and destination 2732 * REFER. 2733 */ 2734 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d1, 2735 RENAME_EXCHANGE)); 2736 ASSERT_EQ(EACCES, errno); 2737 ASSERT_EQ(-1, renameat2(AT_FDCWD, file2_s1d1, AT_FDCWD, file1_s2d1, 2738 RENAME_EXCHANGE)); 2739 ASSERT_EQ(EACCES, errno); 2740 2741 /* Denies renaming because of missing source REFER. */ 2742 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 2743 ASSERT_EQ(EXDEV, errno); 2744 /* Denies renaming because of missing MAKE_REG. */ 2745 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file2_s1d3, 2746 RENAME_EXCHANGE)); 2747 ASSERT_EQ(EACCES, errno); 2748 2749 /* Denies renaming because of missing MAKE_REG. */ 2750 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d1)); 2751 ASSERT_EQ(EACCES, errno); 2752 /* Denies renaming because of missing destination REFER*/ 2753 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2)); 2754 ASSERT_EQ(EXDEV, errno); 2755 2756 /* Denies exchange because of one missing MAKE_REG. */ 2757 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, file2_s1d3, 2758 RENAME_EXCHANGE)); 2759 ASSERT_EQ(EACCES, errno); 2760 /* Allows renaming because of REFER and MAKE_REG. */ 2761 ASSERT_EQ(0, rename(file1_s2d2, file1_s1d3)); 2762 2763 /* Reverse renaming denied because of missing MAKE_REG. */ 2764 ASSERT_EQ(-1, rename(file1_s1d3, file1_s2d2)); 2765 ASSERT_EQ(EACCES, errno); 2766 ASSERT_EQ(0, unlink(file1_s2d3)); 2767 ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3)); 2768 2769 /* Tests reverse renaming. */ 2770 ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3)); 2771 ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s1d3, 2772 RENAME_EXCHANGE)); 2773 ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3)); 2774 2775 /* 2776 * This is OK for a file rename, but it should not be allowed for a 2777 * directory rename (because of the superset of access rights). 2778 */ 2779 ASSERT_EQ(0, rename(file1_s2d3, file1_s1d3)); 2780 ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3)); 2781 2782 /* 2783 * Tests superset restrictions applied to directories. Not only the 2784 * dir_s2d3's parent (dir_s2d2) should be taken into account but also 2785 * access rights tied to dir_s2d3. dir_s2d2 is missing one access right 2786 * compared to dir_s1d3/file1_s1d3 (MAKE_REG) but it is provided 2787 * directly by the moved dir_s2d3. 2788 */ 2789 ASSERT_EQ(0, rename(dir_s2d3, file1_s1d3)); 2790 ASSERT_EQ(0, rename(file1_s1d3, dir_s2d3)); 2791 /* 2792 * The first rename is allowed but not the exchange because dir_s1d3's 2793 * parent (dir_s1d2) doesn't have REFER. 2794 */ 2795 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3, 2796 RENAME_EXCHANGE)); 2797 ASSERT_EQ(EXDEV, errno); 2798 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s2d3, 2799 RENAME_EXCHANGE)); 2800 ASSERT_EQ(EXDEV, errno); 2801 ASSERT_EQ(-1, rename(file1_s2d3, dir_s1d3)); 2802 ASSERT_EQ(EXDEV, errno); 2803 2804 ASSERT_EQ(-1, rename(file2_s1d2, file1_s1d3)); 2805 ASSERT_EQ(EXDEV, errno); 2806 ASSERT_EQ(-1, rename(file2_s1d3, file1_s1d2)); 2807 ASSERT_EQ(EXDEV, errno); 2808 2809 /* Renaming in the same directory is always allowed. */ 2810 ASSERT_EQ(0, rename(file2_s1d2, file1_s1d2)); 2811 ASSERT_EQ(0, rename(file2_s1d3, file1_s1d3)); 2812 2813 ASSERT_EQ(0, unlink(file1_s1d2)); 2814 /* Denies because of missing source MAKE_REG and destination REFER. */ 2815 ASSERT_EQ(-1, rename(dir_s2d3, file1_s1d2)); 2816 ASSERT_EQ(EXDEV, errno); 2817 2818 ASSERT_EQ(0, unlink(file1_s1d3)); 2819 /* Denies because of missing source MAKE_REG and REFER. */ 2820 ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d3)); 2821 ASSERT_EQ(EXDEV, errno); 2822 } 2823 2824 static void 2825 reparent_exdev_layers_enforce1(struct __test_metadata *const _metadata) 2826 { 2827 const struct rule layer1[] = { 2828 { 2829 .path = dir_s1d2, 2830 .access = LANDLOCK_ACCESS_FS_REFER, 2831 }, 2832 { 2833 /* Interesting for the layer2 tests. */ 2834 .path = dir_s1d3, 2835 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2836 }, 2837 { 2838 .path = dir_s2d2, 2839 .access = LANDLOCK_ACCESS_FS_REFER, 2840 }, 2841 { 2842 .path = dir_s2d3, 2843 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 2844 }, 2845 {}, 2846 }; 2847 const int ruleset_fd = create_ruleset( 2848 _metadata, 2849 LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2850 2851 ASSERT_LE(0, ruleset_fd); 2852 enforce_ruleset(_metadata, ruleset_fd); 2853 ASSERT_EQ(0, close(ruleset_fd)); 2854 } 2855 2856 static void 2857 reparent_exdev_layers_enforce2(struct __test_metadata *const _metadata) 2858 { 2859 const struct rule layer2[] = { 2860 { 2861 .path = dir_s2d3, 2862 .access = LANDLOCK_ACCESS_FS_MAKE_DIR, 2863 }, 2864 {}, 2865 }; 2866 /* 2867 * Same checks as before but with a second layer and a new MAKE_DIR 2868 * rule (and no explicit handling of REFER). 2869 */ 2870 const int ruleset_fd = 2871 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2); 2872 2873 ASSERT_LE(0, ruleset_fd); 2874 enforce_ruleset(_metadata, ruleset_fd); 2875 ASSERT_EQ(0, close(ruleset_fd)); 2876 } 2877 2878 TEST_F_FORK(layout1, reparent_exdev_layers_rename1) 2879 { 2880 ASSERT_EQ(0, unlink(file1_s2d2)); 2881 ASSERT_EQ(0, unlink(file1_s2d3)); 2882 2883 reparent_exdev_layers_enforce1(_metadata); 2884 2885 /* 2886 * Moving the dir_s1d3 directory below dir_s2d2 is allowed by Landlock 2887 * because it doesn't inherit new access rights. 2888 */ 2889 ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2)); 2890 ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3)); 2891 2892 /* 2893 * Moving the dir_s1d3 directory below dir_s2d3 is allowed, even if it 2894 * gets a new inherited access rights (MAKE_REG), because MAKE_REG is 2895 * already allowed for dir_s1d3. 2896 */ 2897 ASSERT_EQ(0, rename(dir_s1d3, file1_s2d3)); 2898 ASSERT_EQ(0, rename(file1_s2d3, dir_s1d3)); 2899 2900 /* 2901 * However, moving the file1_s1d3 file below dir_s2d3 is allowed 2902 * because it cannot inherit MAKE_REG right (which is dedicated to 2903 * directories). 2904 */ 2905 ASSERT_EQ(0, rename(file1_s1d3, file1_s2d3)); 2906 2907 reparent_exdev_layers_enforce2(_metadata); 2908 2909 /* 2910 * Moving the dir_s1d3 directory below dir_s2d2 is now denied because 2911 * MAKE_DIR is not tied to dir_s2d2. 2912 */ 2913 ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d2)); 2914 ASSERT_EQ(EACCES, errno); 2915 2916 /* 2917 * Moving the dir_s1d3 directory below dir_s2d3 is forbidden because it 2918 * would grants MAKE_REG and MAKE_DIR rights to it. 2919 */ 2920 ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3)); 2921 ASSERT_EQ(EXDEV, errno); 2922 2923 /* 2924 * Moving the file2_s1d3 file below dir_s2d3 is denied because the 2925 * second layer does not handle REFER, which is always denied by 2926 * default. 2927 */ 2928 ASSERT_EQ(-1, rename(file2_s1d3, file1_s2d3)); 2929 ASSERT_EQ(EXDEV, errno); 2930 } 2931 2932 TEST_F_FORK(layout1, reparent_exdev_layers_rename2) 2933 { 2934 reparent_exdev_layers_enforce1(_metadata); 2935 2936 /* Checks EACCES predominance over EXDEV. */ 2937 ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2)); 2938 ASSERT_EQ(EACCES, errno); 2939 ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d2)); 2940 ASSERT_EQ(EACCES, errno); 2941 ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3)); 2942 ASSERT_EQ(EXDEV, errno); 2943 /* Modify layout! */ 2944 ASSERT_EQ(0, rename(file1_s1d2, file1_s2d3)); 2945 2946 /* Without REFER source. */ 2947 ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2)); 2948 ASSERT_EQ(EXDEV, errno); 2949 ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2)); 2950 ASSERT_EQ(EXDEV, errno); 2951 2952 reparent_exdev_layers_enforce2(_metadata); 2953 2954 /* Checks EACCES predominance over EXDEV. */ 2955 ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d2)); 2956 ASSERT_EQ(EACCES, errno); 2957 /* Checks with actual file2_s1d2. */ 2958 ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d2)); 2959 ASSERT_EQ(EACCES, errno); 2960 ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3)); 2961 ASSERT_EQ(EXDEV, errno); 2962 /* 2963 * Modifying the layout is now denied because the second layer does not 2964 * handle REFER, which is always denied by default. 2965 */ 2966 ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3)); 2967 ASSERT_EQ(EXDEV, errno); 2968 2969 /* Without REFER source, EACCES wins over EXDEV. */ 2970 ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2)); 2971 ASSERT_EQ(EACCES, errno); 2972 ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d2)); 2973 ASSERT_EQ(EACCES, errno); 2974 } 2975 2976 TEST_F_FORK(layout1, reparent_exdev_layers_exchange1) 2977 { 2978 const char *const dir_file1_s1d2 = file1_s1d2, *const dir_file2_s2d3 = 2979 file2_s2d3; 2980 2981 ASSERT_EQ(0, unlink(file1_s1d2)); 2982 ASSERT_EQ(0, mkdir(file1_s1d2, 0700)); 2983 ASSERT_EQ(0, unlink(file2_s2d3)); 2984 ASSERT_EQ(0, mkdir(file2_s2d3, 0700)); 2985 2986 reparent_exdev_layers_enforce1(_metadata); 2987 2988 /* Error predominance with file exchange: returns EXDEV and EACCES. */ 2989 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3, 2990 RENAME_EXCHANGE)); 2991 ASSERT_EQ(EACCES, errno); 2992 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1, 2993 RENAME_EXCHANGE)); 2994 ASSERT_EQ(EACCES, errno); 2995 2996 /* 2997 * Checks with directories which creation could be allowed, but denied 2998 * because of access rights that would be inherited. 2999 */ 3000 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, 3001 dir_file2_s2d3, RENAME_EXCHANGE)); 3002 ASSERT_EQ(EXDEV, errno); 3003 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, 3004 dir_file1_s1d2, RENAME_EXCHANGE)); 3005 ASSERT_EQ(EXDEV, errno); 3006 3007 /* Checks with same access rights. */ 3008 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3, 3009 RENAME_EXCHANGE)); 3010 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, 3011 RENAME_EXCHANGE)); 3012 3013 /* Checks with different (child-only) access rights. */ 3014 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2, 3015 RENAME_EXCHANGE)); 3016 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3, 3017 RENAME_EXCHANGE)); 3018 3019 /* 3020 * Checks that exchange between file and directory are consistent. 3021 * 3022 * Moving a file (file1_s2d2) to a directory which only grants more 3023 * directory-related access rights is allowed, and at the same time 3024 * moving a directory (dir_file2_s2d3) to another directory which 3025 * grants less access rights is allowed too. 3026 * 3027 * See layout1.reparent_exdev_layers_exchange3 for inverted arguments. 3028 */ 3029 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3, 3030 RENAME_EXCHANGE)); 3031 /* 3032 * However, moving back the directory is denied because it would get 3033 * more access rights than the current state and because file creation 3034 * is forbidden (in dir_s2d2). 3035 */ 3036 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2, 3037 RENAME_EXCHANGE)); 3038 ASSERT_EQ(EACCES, errno); 3039 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3, 3040 RENAME_EXCHANGE)); 3041 ASSERT_EQ(EACCES, errno); 3042 3043 reparent_exdev_layers_enforce2(_metadata); 3044 3045 /* Error predominance with file exchange: returns EXDEV and EACCES. */ 3046 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, file1_s2d3, 3047 RENAME_EXCHANGE)); 3048 ASSERT_EQ(EACCES, errno); 3049 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d1, 3050 RENAME_EXCHANGE)); 3051 ASSERT_EQ(EACCES, errno); 3052 3053 /* Checks with directories which creation is now denied. */ 3054 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, 3055 dir_file2_s2d3, RENAME_EXCHANGE)); 3056 ASSERT_EQ(EACCES, errno); 3057 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, 3058 dir_file1_s1d2, RENAME_EXCHANGE)); 3059 ASSERT_EQ(EACCES, errno); 3060 3061 /* Checks with different (child-only) access rights. */ 3062 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, dir_s2d3, 3063 RENAME_EXCHANGE)); 3064 /* Denied because of MAKE_DIR. */ 3065 ASSERT_EQ(EACCES, errno); 3066 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, 3067 RENAME_EXCHANGE)); 3068 ASSERT_EQ(EACCES, errno); 3069 3070 /* Checks with different (child-only) access rights. */ 3071 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_file1_s1d2, 3072 RENAME_EXCHANGE)); 3073 /* Denied because of MAKE_DIR. */ 3074 ASSERT_EQ(EACCES, errno); 3075 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file1_s1d2, AT_FDCWD, dir_s2d3, 3076 RENAME_EXCHANGE)); 3077 ASSERT_EQ(EACCES, errno); 3078 3079 /* See layout1.reparent_exdev_layers_exchange2 for complement. */ 3080 } 3081 3082 TEST_F_FORK(layout1, reparent_exdev_layers_exchange2) 3083 { 3084 const char *const dir_file2_s2d3 = file2_s2d3; 3085 3086 ASSERT_EQ(0, unlink(file2_s2d3)); 3087 ASSERT_EQ(0, mkdir(file2_s2d3, 0700)); 3088 3089 reparent_exdev_layers_enforce1(_metadata); 3090 reparent_exdev_layers_enforce2(_metadata); 3091 3092 /* Checks that exchange between file and directory are consistent. */ 3093 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3, 3094 RENAME_EXCHANGE)); 3095 ASSERT_EQ(EACCES, errno); 3096 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2, 3097 RENAME_EXCHANGE)); 3098 ASSERT_EQ(EACCES, errno); 3099 } 3100 3101 TEST_F_FORK(layout1, reparent_exdev_layers_exchange3) 3102 { 3103 const char *const dir_file2_s2d3 = file2_s2d3; 3104 3105 ASSERT_EQ(0, unlink(file2_s2d3)); 3106 ASSERT_EQ(0, mkdir(file2_s2d3, 0700)); 3107 3108 reparent_exdev_layers_enforce1(_metadata); 3109 3110 /* 3111 * Checks that exchange between file and directory are consistent, 3112 * including with inverted arguments (see 3113 * layout1.reparent_exdev_layers_exchange1). 3114 */ 3115 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2, 3116 RENAME_EXCHANGE)); 3117 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_file2_s2d3, 3118 RENAME_EXCHANGE)); 3119 ASSERT_EQ(EACCES, errno); 3120 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_file2_s2d3, AT_FDCWD, file1_s2d2, 3121 RENAME_EXCHANGE)); 3122 ASSERT_EQ(EACCES, errno); 3123 } 3124 3125 TEST_F_FORK(layout1, reparent_remove) 3126 { 3127 const struct rule layer1[] = { 3128 { 3129 .path = dir_s1d1, 3130 .access = LANDLOCK_ACCESS_FS_REFER | 3131 LANDLOCK_ACCESS_FS_REMOVE_DIR, 3132 }, 3133 { 3134 .path = dir_s1d2, 3135 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 3136 }, 3137 { 3138 .path = dir_s2d1, 3139 .access = LANDLOCK_ACCESS_FS_REFER | 3140 LANDLOCK_ACCESS_FS_REMOVE_FILE, 3141 }, 3142 {}, 3143 }; 3144 const int ruleset_fd = create_ruleset( 3145 _metadata, 3146 LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR | 3147 LANDLOCK_ACCESS_FS_REMOVE_FILE, 3148 layer1); 3149 3150 ASSERT_LE(0, ruleset_fd); 3151 enforce_ruleset(_metadata, ruleset_fd); 3152 ASSERT_EQ(0, close(ruleset_fd)); 3153 3154 /* Access denied because of wrong/swapped remove file/dir. */ 3155 ASSERT_EQ(-1, rename(file1_s1d1, dir_s2d2)); 3156 ASSERT_EQ(EACCES, errno); 3157 ASSERT_EQ(-1, rename(dir_s2d2, file1_s1d1)); 3158 ASSERT_EQ(EACCES, errno); 3159 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d2, 3160 RENAME_EXCHANGE)); 3161 ASSERT_EQ(EACCES, errno); 3162 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s2d3, 3163 RENAME_EXCHANGE)); 3164 ASSERT_EQ(EACCES, errno); 3165 3166 /* Access allowed thanks to the matching rights. */ 3167 ASSERT_EQ(-1, rename(file1_s2d1, dir_s1d2)); 3168 ASSERT_EQ(EISDIR, errno); 3169 ASSERT_EQ(-1, rename(dir_s1d2, file1_s2d1)); 3170 ASSERT_EQ(ENOTDIR, errno); 3171 ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1)); 3172 ASSERT_EQ(ENOTDIR, errno); 3173 ASSERT_EQ(0, unlink(file1_s2d1)); 3174 ASSERT_EQ(0, unlink(file1_s1d3)); 3175 ASSERT_EQ(0, unlink(file2_s1d3)); 3176 ASSERT_EQ(0, rename(dir_s1d3, file1_s2d1)); 3177 3178 /* Effectively removes a file and a directory by exchanging them. */ 3179 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 3180 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3, 3181 RENAME_EXCHANGE)); 3182 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3, 3183 RENAME_EXCHANGE)); 3184 ASSERT_EQ(EACCES, errno); 3185 } 3186 3187 TEST_F_FORK(layout1, reparent_dom_superset) 3188 { 3189 const struct rule layer1[] = { 3190 { 3191 .path = dir_s1d2, 3192 .access = LANDLOCK_ACCESS_FS_REFER, 3193 }, 3194 { 3195 .path = file1_s1d2, 3196 .access = LANDLOCK_ACCESS_FS_EXECUTE, 3197 }, 3198 { 3199 .path = dir_s1d3, 3200 .access = LANDLOCK_ACCESS_FS_MAKE_SOCK | 3201 LANDLOCK_ACCESS_FS_EXECUTE, 3202 }, 3203 { 3204 .path = dir_s2d2, 3205 .access = LANDLOCK_ACCESS_FS_REFER | 3206 LANDLOCK_ACCESS_FS_EXECUTE | 3207 LANDLOCK_ACCESS_FS_MAKE_SOCK, 3208 }, 3209 { 3210 .path = dir_s2d3, 3211 .access = LANDLOCK_ACCESS_FS_READ_FILE | 3212 LANDLOCK_ACCESS_FS_MAKE_FIFO, 3213 }, 3214 {}, 3215 }; 3216 int ruleset_fd = create_ruleset(_metadata, 3217 LANDLOCK_ACCESS_FS_REFER | 3218 LANDLOCK_ACCESS_FS_EXECUTE | 3219 LANDLOCK_ACCESS_FS_MAKE_SOCK | 3220 LANDLOCK_ACCESS_FS_READ_FILE | 3221 LANDLOCK_ACCESS_FS_MAKE_FIFO, 3222 layer1); 3223 3224 ASSERT_LE(0, ruleset_fd); 3225 enforce_ruleset(_metadata, ruleset_fd); 3226 ASSERT_EQ(0, close(ruleset_fd)); 3227 3228 ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d1)); 3229 ASSERT_EQ(EXDEV, errno); 3230 /* 3231 * Moving file1_s1d2 beneath dir_s2d3 would grant it the READ_FILE 3232 * access right. 3233 */ 3234 ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d3)); 3235 ASSERT_EQ(EXDEV, errno); 3236 /* 3237 * Moving file1_s1d2 should be allowed even if dir_s2d2 grants a 3238 * superset of access rights compared to dir_s1d2, because file1_s1d2 3239 * already has these access rights anyway. 3240 */ 3241 ASSERT_EQ(0, rename(file1_s1d2, file1_s2d2)); 3242 ASSERT_EQ(0, rename(file1_s2d2, file1_s1d2)); 3243 3244 ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d1)); 3245 ASSERT_EQ(EXDEV, errno); 3246 /* 3247 * Moving dir_s1d3 beneath dir_s2d3 would grant it the MAKE_FIFO access 3248 * right. 3249 */ 3250 ASSERT_EQ(-1, rename(dir_s1d3, file1_s2d3)); 3251 ASSERT_EQ(EXDEV, errno); 3252 /* 3253 * Moving dir_s1d3 should be allowed even if dir_s2d2 grants a superset 3254 * of access rights compared to dir_s1d2, because dir_s1d3 already has 3255 * these access rights anyway. 3256 */ 3257 ASSERT_EQ(0, rename(dir_s1d3, file1_s2d2)); 3258 ASSERT_EQ(0, rename(file1_s2d2, dir_s1d3)); 3259 3260 /* 3261 * Moving file1_s2d3 beneath dir_s1d2 is allowed, but moving it back 3262 * will be denied because the new inherited access rights from dir_s1d2 3263 * will be less than the destination (original) dir_s2d3. This is a 3264 * sinkhole scenario where we cannot move back files or directories. 3265 */ 3266 ASSERT_EQ(0, rename(file1_s2d3, file2_s1d2)); 3267 ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3)); 3268 ASSERT_EQ(EXDEV, errno); 3269 ASSERT_EQ(0, unlink(file2_s1d2)); 3270 ASSERT_EQ(0, unlink(file2_s2d3)); 3271 /* 3272 * Checks similar directory one-way move: dir_s2d3 loses EXECUTE and 3273 * MAKE_SOCK which were inherited from dir_s1d3. 3274 */ 3275 ASSERT_EQ(0, rename(dir_s2d3, file2_s1d2)); 3276 ASSERT_EQ(-1, rename(file2_s1d2, dir_s2d3)); 3277 ASSERT_EQ(EXDEV, errno); 3278 } 3279 3280 TEST_F_FORK(layout1, remove_dir) 3281 { 3282 const struct rule rules[] = { 3283 { 3284 .path = dir_s1d2, 3285 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 3286 }, 3287 {}, 3288 }; 3289 const int ruleset_fd = 3290 create_ruleset(_metadata, rules[0].access, rules); 3291 3292 ASSERT_LE(0, ruleset_fd); 3293 3294 ASSERT_EQ(0, unlink(file1_s1d1)); 3295 ASSERT_EQ(0, unlink(file1_s1d2)); 3296 ASSERT_EQ(0, unlink(file1_s1d3)); 3297 ASSERT_EQ(0, unlink(file2_s1d3)); 3298 3299 enforce_ruleset(_metadata, ruleset_fd); 3300 ASSERT_EQ(0, close(ruleset_fd)); 3301 3302 ASSERT_EQ(0, rmdir(dir_s1d3)); 3303 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 3304 ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR)); 3305 3306 /* dir_s1d2 itself cannot be removed. */ 3307 ASSERT_EQ(-1, rmdir(dir_s1d2)); 3308 ASSERT_EQ(EACCES, errno); 3309 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR)); 3310 ASSERT_EQ(EACCES, errno); 3311 ASSERT_EQ(-1, rmdir(dir_s1d1)); 3312 ASSERT_EQ(EACCES, errno); 3313 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR)); 3314 ASSERT_EQ(EACCES, errno); 3315 } 3316 3317 TEST_F_FORK(layout1, remove_file) 3318 { 3319 const struct rule rules[] = { 3320 { 3321 .path = dir_s1d2, 3322 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 3323 }, 3324 {}, 3325 }; 3326 const int ruleset_fd = 3327 create_ruleset(_metadata, rules[0].access, rules); 3328 3329 ASSERT_LE(0, ruleset_fd); 3330 enforce_ruleset(_metadata, ruleset_fd); 3331 ASSERT_EQ(0, close(ruleset_fd)); 3332 3333 ASSERT_EQ(-1, unlink(file1_s1d1)); 3334 ASSERT_EQ(EACCES, errno); 3335 ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0)); 3336 ASSERT_EQ(EACCES, errno); 3337 ASSERT_EQ(0, unlink(file1_s1d2)); 3338 ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0)); 3339 } 3340 3341 static void test_make_file(struct __test_metadata *const _metadata, 3342 const __u64 access, const mode_t mode, 3343 const dev_t dev) 3344 { 3345 const struct rule rules[] = { 3346 { 3347 .path = dir_s1d2, 3348 .access = access, 3349 }, 3350 {}, 3351 }; 3352 const int ruleset_fd = create_ruleset(_metadata, access, rules); 3353 3354 ASSERT_LE(0, ruleset_fd); 3355 3356 ASSERT_EQ(0, unlink(file1_s1d1)); 3357 ASSERT_EQ(0, unlink(file2_s1d1)); 3358 ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev)) 3359 { 3360 TH_LOG("Failed to make file \"%s\": %s", file2_s1d1, 3361 strerror(errno)); 3362 }; 3363 3364 ASSERT_EQ(0, unlink(file1_s1d2)); 3365 ASSERT_EQ(0, unlink(file2_s1d2)); 3366 3367 ASSERT_EQ(0, unlink(file1_s1d3)); 3368 ASSERT_EQ(0, unlink(file2_s1d3)); 3369 3370 enforce_ruleset(_metadata, ruleset_fd); 3371 ASSERT_EQ(0, close(ruleset_fd)); 3372 3373 ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev)); 3374 ASSERT_EQ(EACCES, errno); 3375 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 3376 ASSERT_EQ(EACCES, errno); 3377 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 3378 ASSERT_EQ(EACCES, errno); 3379 3380 ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev)) 3381 { 3382 TH_LOG("Failed to make file \"%s\": %s", file1_s1d2, 3383 strerror(errno)); 3384 }; 3385 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 3386 ASSERT_EQ(0, unlink(file2_s1d2)); 3387 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 3388 3389 ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev)); 3390 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 3391 ASSERT_EQ(0, unlink(file2_s1d3)); 3392 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 3393 } 3394 3395 TEST_F_FORK(layout1, make_char) 3396 { 3397 /* Creates a /dev/null device. */ 3398 set_cap(_metadata, CAP_MKNOD); 3399 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR, 3400 makedev(1, 3)); 3401 } 3402 3403 TEST_F_FORK(layout1, make_block) 3404 { 3405 /* Creates a /dev/loop0 device. */ 3406 set_cap(_metadata, CAP_MKNOD); 3407 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK, 3408 makedev(7, 0)); 3409 } 3410 3411 TEST_F_FORK(layout1, make_reg_1) 3412 { 3413 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0); 3414 } 3415 3416 TEST_F_FORK(layout1, make_reg_2) 3417 { 3418 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0); 3419 } 3420 3421 TEST_F_FORK(layout1, make_sock) 3422 { 3423 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0); 3424 } 3425 3426 TEST_F_FORK(layout1, make_fifo) 3427 { 3428 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0); 3429 } 3430 3431 TEST_F_FORK(layout1, make_sym) 3432 { 3433 const struct rule rules[] = { 3434 { 3435 .path = dir_s1d2, 3436 .access = LANDLOCK_ACCESS_FS_MAKE_SYM, 3437 }, 3438 {}, 3439 }; 3440 const int ruleset_fd = 3441 create_ruleset(_metadata, rules[0].access, rules); 3442 3443 ASSERT_LE(0, ruleset_fd); 3444 3445 ASSERT_EQ(0, unlink(file1_s1d1)); 3446 ASSERT_EQ(0, unlink(file2_s1d1)); 3447 ASSERT_EQ(0, symlink("none", file2_s1d1)); 3448 3449 ASSERT_EQ(0, unlink(file1_s1d2)); 3450 ASSERT_EQ(0, unlink(file2_s1d2)); 3451 3452 ASSERT_EQ(0, unlink(file1_s1d3)); 3453 ASSERT_EQ(0, unlink(file2_s1d3)); 3454 3455 enforce_ruleset(_metadata, ruleset_fd); 3456 ASSERT_EQ(0, close(ruleset_fd)); 3457 3458 ASSERT_EQ(-1, symlink("none", file1_s1d1)); 3459 ASSERT_EQ(EACCES, errno); 3460 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 3461 ASSERT_EQ(EACCES, errno); 3462 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 3463 ASSERT_EQ(EACCES, errno); 3464 3465 ASSERT_EQ(0, symlink("none", file1_s1d2)); 3466 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 3467 ASSERT_EQ(0, unlink(file2_s1d2)); 3468 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 3469 3470 ASSERT_EQ(0, symlink("none", file1_s1d3)); 3471 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 3472 ASSERT_EQ(0, unlink(file2_s1d3)); 3473 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 3474 } 3475 3476 TEST_F_FORK(layout1, make_dir) 3477 { 3478 const struct rule rules[] = { 3479 { 3480 .path = dir_s1d2, 3481 .access = LANDLOCK_ACCESS_FS_MAKE_DIR, 3482 }, 3483 {}, 3484 }; 3485 const int ruleset_fd = 3486 create_ruleset(_metadata, rules[0].access, rules); 3487 3488 ASSERT_LE(0, ruleset_fd); 3489 3490 ASSERT_EQ(0, unlink(file1_s1d1)); 3491 ASSERT_EQ(0, unlink(file1_s1d2)); 3492 ASSERT_EQ(0, unlink(file1_s1d3)); 3493 3494 enforce_ruleset(_metadata, ruleset_fd); 3495 ASSERT_EQ(0, close(ruleset_fd)); 3496 3497 /* Uses file_* as directory names. */ 3498 ASSERT_EQ(-1, mkdir(file1_s1d1, 0700)); 3499 ASSERT_EQ(EACCES, errno); 3500 ASSERT_EQ(0, mkdir(file1_s1d2, 0700)); 3501 ASSERT_EQ(0, mkdir(file1_s1d3, 0700)); 3502 } 3503 3504 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd, 3505 const int open_flags) 3506 { 3507 static const char path_template[] = "/proc/self/fd/%d"; 3508 char procfd_path[sizeof(path_template) + 10]; 3509 const int procfd_path_size = 3510 snprintf(procfd_path, sizeof(procfd_path), path_template, fd); 3511 3512 ASSERT_LT(procfd_path_size, sizeof(procfd_path)); 3513 return open(procfd_path, open_flags); 3514 } 3515 3516 TEST_F_FORK(layout1, proc_unlinked_file) 3517 { 3518 const struct rule rules[] = { 3519 { 3520 .path = file1_s1d2, 3521 .access = LANDLOCK_ACCESS_FS_READ_FILE, 3522 }, 3523 {}, 3524 }; 3525 int reg_fd, proc_fd; 3526 const int ruleset_fd = create_ruleset( 3527 _metadata, 3528 LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 3529 rules); 3530 3531 ASSERT_LE(0, ruleset_fd); 3532 enforce_ruleset(_metadata, ruleset_fd); 3533 ASSERT_EQ(0, close(ruleset_fd)); 3534 3535 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 3536 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 3537 reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC); 3538 ASSERT_LE(0, reg_fd); 3539 ASSERT_EQ(0, unlink(file1_s1d2)); 3540 3541 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC); 3542 ASSERT_LE(0, proc_fd); 3543 ASSERT_EQ(0, close(proc_fd)); 3544 3545 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC); 3546 ASSERT_EQ(-1, proc_fd) 3547 { 3548 TH_LOG("Successfully opened /proc/self/fd/%d: %s", reg_fd, 3549 strerror(errno)); 3550 } 3551 ASSERT_EQ(EACCES, errno); 3552 3553 ASSERT_EQ(0, close(reg_fd)); 3554 } 3555 3556 TEST_F_FORK(layout1, proc_pipe) 3557 { 3558 int proc_fd; 3559 int pipe_fds[2]; 3560 char buf = '\0'; 3561 const struct rule rules[] = { 3562 { 3563 .path = dir_s1d2, 3564 .access = LANDLOCK_ACCESS_FS_READ_FILE | 3565 LANDLOCK_ACCESS_FS_WRITE_FILE, 3566 }, 3567 {}, 3568 }; 3569 /* Limits read and write access to files tied to the filesystem. */ 3570 const int ruleset_fd = 3571 create_ruleset(_metadata, rules[0].access, rules); 3572 3573 ASSERT_LE(0, ruleset_fd); 3574 enforce_ruleset(_metadata, ruleset_fd); 3575 ASSERT_EQ(0, close(ruleset_fd)); 3576 3577 /* Checks enforcement for normal files. */ 3578 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 3579 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 3580 3581 /* Checks access to pipes through FD. */ 3582 ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC)); 3583 ASSERT_EQ(1, write(pipe_fds[1], ".", 1)) 3584 { 3585 TH_LOG("Failed to write in pipe: %s", strerror(errno)); 3586 } 3587 ASSERT_EQ(1, read(pipe_fds[0], &buf, 1)); 3588 ASSERT_EQ('.', buf); 3589 3590 /* Checks write access to pipe through /proc/self/fd . */ 3591 proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC); 3592 ASSERT_LE(0, proc_fd); 3593 ASSERT_EQ(1, write(proc_fd, ".", 1)) 3594 { 3595 TH_LOG("Failed to write through /proc/self/fd/%d: %s", 3596 pipe_fds[1], strerror(errno)); 3597 } 3598 ASSERT_EQ(0, close(proc_fd)); 3599 3600 /* Checks read access to pipe through /proc/self/fd . */ 3601 proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC); 3602 ASSERT_LE(0, proc_fd); 3603 buf = '\0'; 3604 ASSERT_EQ(1, read(proc_fd, &buf, 1)) 3605 { 3606 TH_LOG("Failed to read through /proc/self/fd/%d: %s", 3607 pipe_fds[1], strerror(errno)); 3608 } 3609 ASSERT_EQ(0, close(proc_fd)); 3610 3611 ASSERT_EQ(0, close(pipe_fds[0])); 3612 ASSERT_EQ(0, close(pipe_fds[1])); 3613 } 3614 3615 /* Invokes truncate(2) and returns its errno or 0. */ 3616 static int test_truncate(const char *const path) 3617 { 3618 if (truncate(path, 10) < 0) 3619 return errno; 3620 return 0; 3621 } 3622 3623 /* 3624 * Invokes creat(2) and returns its errno or 0. 3625 * Closes the opened file descriptor on success. 3626 */ 3627 static int test_creat(const char *const path) 3628 { 3629 int fd = creat(path, 0600); 3630 3631 if (fd < 0) 3632 return errno; 3633 3634 /* 3635 * Mixing error codes from close(2) and creat(2) should not lead to any 3636 * (access type) confusion for this test. 3637 */ 3638 if (close(fd) < 0) 3639 return errno; 3640 return 0; 3641 } 3642 3643 /* 3644 * Exercises file truncation when it's not restricted, 3645 * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed. 3646 */ 3647 TEST_F_FORK(layout1, truncate_unhandled) 3648 { 3649 const char *const file_r = file1_s1d1; 3650 const char *const file_w = file2_s1d1; 3651 const char *const file_none = file1_s1d2; 3652 const struct rule rules[] = { 3653 { 3654 .path = file_r, 3655 .access = LANDLOCK_ACCESS_FS_READ_FILE, 3656 }, 3657 { 3658 .path = file_w, 3659 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 3660 }, 3661 /* Implicitly: No rights for file_none. */ 3662 {}, 3663 }; 3664 3665 const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | 3666 LANDLOCK_ACCESS_FS_WRITE_FILE; 3667 int ruleset_fd; 3668 3669 /* Enables Landlock. */ 3670 ruleset_fd = create_ruleset(_metadata, handled, rules); 3671 3672 ASSERT_LE(0, ruleset_fd); 3673 enforce_ruleset(_metadata, ruleset_fd); 3674 ASSERT_EQ(0, close(ruleset_fd)); 3675 3676 /* 3677 * Checks read right: truncate and open with O_TRUNC work, unless the 3678 * file is attempted to be opened for writing. 3679 */ 3680 EXPECT_EQ(0, test_truncate(file_r)); 3681 EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC)); 3682 EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC)); 3683 EXPECT_EQ(EACCES, test_creat(file_r)); 3684 3685 /* 3686 * Checks write right: truncate and open with O_TRUNC work, unless the 3687 * file is attempted to be opened for reading. 3688 */ 3689 EXPECT_EQ(0, test_truncate(file_w)); 3690 EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC)); 3691 EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC)); 3692 EXPECT_EQ(0, test_creat(file_w)); 3693 3694 /* 3695 * Checks "no rights" case: truncate works but all open attempts fail, 3696 * including creat. 3697 */ 3698 EXPECT_EQ(0, test_truncate(file_none)); 3699 EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC)); 3700 EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC)); 3701 EXPECT_EQ(EACCES, test_creat(file_none)); 3702 } 3703 3704 TEST_F_FORK(layout1, truncate) 3705 { 3706 const char *const file_rwt = file1_s1d1; 3707 const char *const file_rw = file2_s1d1; 3708 const char *const file_rt = file1_s1d2; 3709 const char *const file_t = file2_s1d2; 3710 const char *const file_none = file1_s1d3; 3711 const char *const dir_t = dir_s2d1; 3712 const char *const file_in_dir_t = file1_s2d1; 3713 const char *const dir_w = dir_s3d1; 3714 const char *const file_in_dir_w = file1_s3d1; 3715 const struct rule rules[] = { 3716 { 3717 .path = file_rwt, 3718 .access = LANDLOCK_ACCESS_FS_READ_FILE | 3719 LANDLOCK_ACCESS_FS_WRITE_FILE | 3720 LANDLOCK_ACCESS_FS_TRUNCATE, 3721 }, 3722 { 3723 .path = file_rw, 3724 .access = LANDLOCK_ACCESS_FS_READ_FILE | 3725 LANDLOCK_ACCESS_FS_WRITE_FILE, 3726 }, 3727 { 3728 .path = file_rt, 3729 .access = LANDLOCK_ACCESS_FS_READ_FILE | 3730 LANDLOCK_ACCESS_FS_TRUNCATE, 3731 }, 3732 { 3733 .path = file_t, 3734 .access = LANDLOCK_ACCESS_FS_TRUNCATE, 3735 }, 3736 /* Implicitly: No access rights for file_none. */ 3737 { 3738 .path = dir_t, 3739 .access = LANDLOCK_ACCESS_FS_TRUNCATE, 3740 }, 3741 { 3742 .path = dir_w, 3743 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 3744 }, 3745 {}, 3746 }; 3747 const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | 3748 LANDLOCK_ACCESS_FS_WRITE_FILE | 3749 LANDLOCK_ACCESS_FS_TRUNCATE; 3750 int ruleset_fd; 3751 3752 /* Enables Landlock. */ 3753 ruleset_fd = create_ruleset(_metadata, handled, rules); 3754 3755 ASSERT_LE(0, ruleset_fd); 3756 enforce_ruleset(_metadata, ruleset_fd); 3757 ASSERT_EQ(0, close(ruleset_fd)); 3758 3759 /* Checks read, write and truncate rights: truncation works. */ 3760 EXPECT_EQ(0, test_truncate(file_rwt)); 3761 EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC)); 3762 EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC)); 3763 3764 /* Checks read and write rights: no truncate variant works. */ 3765 EXPECT_EQ(EACCES, test_truncate(file_rw)); 3766 EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC)); 3767 EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC)); 3768 3769 /* 3770 * Checks read and truncate rights: truncation works. 3771 * 3772 * Note: Files can get truncated using open() even with O_RDONLY. 3773 */ 3774 EXPECT_EQ(0, test_truncate(file_rt)); 3775 EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC)); 3776 EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC)); 3777 3778 /* Checks truncate right: truncate works, but can't open file. */ 3779 EXPECT_EQ(0, test_truncate(file_t)); 3780 EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC)); 3781 EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC)); 3782 3783 /* Checks "no rights" case: No form of truncation works. */ 3784 EXPECT_EQ(EACCES, test_truncate(file_none)); 3785 EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC)); 3786 EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC)); 3787 3788 /* 3789 * Checks truncate right on directory: truncate works on contained 3790 * files. 3791 */ 3792 EXPECT_EQ(0, test_truncate(file_in_dir_t)); 3793 EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC)); 3794 EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC)); 3795 3796 /* 3797 * Checks creat in dir_w: This requires the truncate right when 3798 * overwriting an existing file, but does not require it when the file 3799 * is new. 3800 */ 3801 EXPECT_EQ(EACCES, test_creat(file_in_dir_w)); 3802 3803 ASSERT_EQ(0, unlink(file_in_dir_w)); 3804 EXPECT_EQ(0, test_creat(file_in_dir_w)); 3805 } 3806 3807 /* Invokes ftruncate(2) and returns its errno or 0. */ 3808 static int test_ftruncate(int fd) 3809 { 3810 if (ftruncate(fd, 10) < 0) 3811 return errno; 3812 return 0; 3813 } 3814 3815 TEST_F_FORK(layout1, ftruncate) 3816 { 3817 /* 3818 * This test opens a new file descriptor at different stages of 3819 * Landlock restriction: 3820 * 3821 * without restriction: ftruncate works 3822 * something else but truncate restricted: ftruncate works 3823 * truncate restricted and permitted: ftruncate works 3824 * truncate restricted and not permitted: ftruncate fails 3825 * 3826 * Whether this works or not is expected to depend on the time when the 3827 * FD was opened, not to depend on the time when ftruncate() was 3828 * called. 3829 */ 3830 const char *const path = file1_s1d1; 3831 const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE | 3832 LANDLOCK_ACCESS_FS_WRITE_FILE; 3833 const struct rule layer1[] = { 3834 { 3835 .path = path, 3836 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 3837 }, 3838 {}, 3839 }; 3840 const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE; 3841 const struct rule layer2[] = { 3842 { 3843 .path = path, 3844 .access = LANDLOCK_ACCESS_FS_TRUNCATE, 3845 }, 3846 {}, 3847 }; 3848 const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE | 3849 LANDLOCK_ACCESS_FS_WRITE_FILE; 3850 const struct rule layer3[] = { 3851 { 3852 .path = path, 3853 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 3854 }, 3855 {}, 3856 }; 3857 int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd; 3858 3859 fd_layer0 = open(path, O_WRONLY); 3860 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3861 3862 ruleset_fd = create_ruleset(_metadata, handled1, layer1); 3863 ASSERT_LE(0, ruleset_fd); 3864 enforce_ruleset(_metadata, ruleset_fd); 3865 ASSERT_EQ(0, close(ruleset_fd)); 3866 3867 fd_layer1 = open(path, O_WRONLY); 3868 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3869 EXPECT_EQ(0, test_ftruncate(fd_layer1)); 3870 3871 ruleset_fd = create_ruleset(_metadata, handled2, layer2); 3872 ASSERT_LE(0, ruleset_fd); 3873 enforce_ruleset(_metadata, ruleset_fd); 3874 ASSERT_EQ(0, close(ruleset_fd)); 3875 3876 fd_layer2 = open(path, O_WRONLY); 3877 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3878 EXPECT_EQ(0, test_ftruncate(fd_layer1)); 3879 EXPECT_EQ(0, test_ftruncate(fd_layer2)); 3880 3881 ruleset_fd = create_ruleset(_metadata, handled3, layer3); 3882 ASSERT_LE(0, ruleset_fd); 3883 enforce_ruleset(_metadata, ruleset_fd); 3884 ASSERT_EQ(0, close(ruleset_fd)); 3885 3886 fd_layer3 = open(path, O_WRONLY); 3887 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3888 EXPECT_EQ(0, test_ftruncate(fd_layer1)); 3889 EXPECT_EQ(0, test_ftruncate(fd_layer2)); 3890 EXPECT_EQ(EACCES, test_ftruncate(fd_layer3)); 3891 3892 ASSERT_EQ(0, close(fd_layer0)); 3893 ASSERT_EQ(0, close(fd_layer1)); 3894 ASSERT_EQ(0, close(fd_layer2)); 3895 ASSERT_EQ(0, close(fd_layer3)); 3896 } 3897 3898 /* clang-format off */ 3899 FIXTURE(ftruncate) {}; 3900 /* clang-format on */ 3901 3902 FIXTURE_SETUP(ftruncate) 3903 { 3904 prepare_layout(_metadata); 3905 create_file(_metadata, file1_s1d1); 3906 } 3907 3908 FIXTURE_TEARDOWN_PARENT(ftruncate) 3909 { 3910 EXPECT_EQ(0, remove_path(file1_s1d1)); 3911 cleanup_layout(_metadata); 3912 } 3913 3914 FIXTURE_VARIANT(ftruncate) 3915 { 3916 const __u64 handled; 3917 const __u64 allowed; 3918 const int expected_open_result; 3919 const int expected_ftruncate_result; 3920 }; 3921 3922 /* clang-format off */ 3923 FIXTURE_VARIANT_ADD(ftruncate, w_w) { 3924 /* clang-format on */ 3925 .handled = LANDLOCK_ACCESS_FS_WRITE_FILE, 3926 .allowed = LANDLOCK_ACCESS_FS_WRITE_FILE, 3927 .expected_open_result = 0, 3928 .expected_ftruncate_result = 0, 3929 }; 3930 3931 /* clang-format off */ 3932 FIXTURE_VARIANT_ADD(ftruncate, t_t) { 3933 /* clang-format on */ 3934 .handled = LANDLOCK_ACCESS_FS_TRUNCATE, 3935 .allowed = LANDLOCK_ACCESS_FS_TRUNCATE, 3936 .expected_open_result = 0, 3937 .expected_ftruncate_result = 0, 3938 }; 3939 3940 /* clang-format off */ 3941 FIXTURE_VARIANT_ADD(ftruncate, wt_w) { 3942 /* clang-format on */ 3943 .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, 3944 .allowed = LANDLOCK_ACCESS_FS_WRITE_FILE, 3945 .expected_open_result = 0, 3946 .expected_ftruncate_result = EACCES, 3947 }; 3948 3949 /* clang-format off */ 3950 FIXTURE_VARIANT_ADD(ftruncate, wt_wt) { 3951 /* clang-format on */ 3952 .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, 3953 .allowed = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, 3954 .expected_open_result = 0, 3955 .expected_ftruncate_result = 0, 3956 }; 3957 3958 /* clang-format off */ 3959 FIXTURE_VARIANT_ADD(ftruncate, wt_t) { 3960 /* clang-format on */ 3961 .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, 3962 .allowed = LANDLOCK_ACCESS_FS_TRUNCATE, 3963 .expected_open_result = EACCES, 3964 }; 3965 3966 TEST_F_FORK(ftruncate, open_and_ftruncate) 3967 { 3968 const char *const path = file1_s1d1; 3969 const struct rule rules[] = { 3970 { 3971 .path = path, 3972 .access = variant->allowed, 3973 }, 3974 {}, 3975 }; 3976 int fd, ruleset_fd; 3977 3978 /* Enables Landlock. */ 3979 ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 3980 ASSERT_LE(0, ruleset_fd); 3981 enforce_ruleset(_metadata, ruleset_fd); 3982 ASSERT_EQ(0, close(ruleset_fd)); 3983 3984 fd = open(path, O_WRONLY); 3985 EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); 3986 if (fd >= 0) { 3987 EXPECT_EQ(variant->expected_ftruncate_result, 3988 test_ftruncate(fd)); 3989 ASSERT_EQ(0, close(fd)); 3990 } 3991 } 3992 3993 TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) 3994 { 3995 int child, fd, status; 3996 int socket_fds[2]; 3997 3998 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, 3999 socket_fds)); 4000 4001 child = fork(); 4002 ASSERT_LE(0, child); 4003 if (child == 0) { 4004 /* 4005 * Enables Landlock in the child process, open a file descriptor 4006 * where truncation is forbidden and send it to the 4007 * non-landlocked parent process. 4008 */ 4009 const char *const path = file1_s1d1; 4010 const struct rule rules[] = { 4011 { 4012 .path = path, 4013 .access = variant->allowed, 4014 }, 4015 {}, 4016 }; 4017 int fd, ruleset_fd; 4018 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 ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); 4026 4027 if (fd >= 0) { 4028 ASSERT_EQ(0, send_fd(socket_fds[0], fd)); 4029 ASSERT_EQ(0, close(fd)); 4030 } 4031 4032 ASSERT_EQ(0, close(socket_fds[0])); 4033 4034 _exit(_metadata->exit_code); 4035 return; 4036 } 4037 4038 if (variant->expected_open_result == 0) { 4039 fd = recv_fd(socket_fds[1]); 4040 ASSERT_LE(0, fd); 4041 4042 EXPECT_EQ(variant->expected_ftruncate_result, 4043 test_ftruncate(fd)); 4044 ASSERT_EQ(0, close(fd)); 4045 } 4046 4047 ASSERT_EQ(child, waitpid(child, &status, 0)); 4048 ASSERT_EQ(1, WIFEXITED(status)); 4049 ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 4050 4051 ASSERT_EQ(0, close(socket_fds[0])); 4052 ASSERT_EQ(0, close(socket_fds[1])); 4053 } 4054 4055 /* Invokes the FS_IOC_GETFLAGS IOCTL and returns its errno or 0. */ 4056 static int test_fs_ioc_getflags_ioctl(int fd) 4057 { 4058 uint32_t flags; 4059 4060 if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0) 4061 return errno; 4062 return 0; 4063 } 4064 4065 TEST(memfd_ftruncate_and_ioctl) 4066 { 4067 const struct landlock_ruleset_attr attr = { 4068 .handled_access_fs = ACCESS_ALL, 4069 }; 4070 int ruleset_fd, fd, i; 4071 4072 /* 4073 * We exercise the same test both with and without Landlock enabled, to 4074 * ensure that it behaves the same in both cases. 4075 */ 4076 for (i = 0; i < 2; i++) { 4077 /* Creates a new memfd. */ 4078 fd = memfd_create("name", MFD_CLOEXEC); 4079 ASSERT_LE(0, fd); 4080 4081 /* 4082 * Checks that operations associated with the opened file 4083 * (ftruncate, ioctl) are permitted on file descriptors that are 4084 * created in ways other than open(2). 4085 */ 4086 EXPECT_EQ(0, test_ftruncate(fd)); 4087 EXPECT_EQ(0, test_fs_ioc_getflags_ioctl(fd)); 4088 4089 ASSERT_EQ(0, close(fd)); 4090 4091 /* Enables Landlock. */ 4092 ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4093 ASSERT_LE(0, ruleset_fd); 4094 enforce_ruleset(_metadata, ruleset_fd); 4095 ASSERT_EQ(0, close(ruleset_fd)); 4096 } 4097 } 4098 4099 static int test_fionread_ioctl(int fd) 4100 { 4101 size_t sz = 0; 4102 4103 if (ioctl(fd, FIONREAD, &sz) < 0 && errno == EACCES) 4104 return errno; 4105 return 0; 4106 } 4107 4108 TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl) 4109 { 4110 const struct landlock_ruleset_attr attr = { 4111 .handled_access_fs = ACCESS_ALL, 4112 }; 4113 int ruleset_fd, fd; 4114 4115 /* 4116 * Checks that for files opened with O_PATH, both ioctl(2) and 4117 * ftruncate(2) yield EBADF, as it is documented in open(2) for the 4118 * O_PATH flag. 4119 */ 4120 fd = open(dir_s1d1, O_PATH | O_CLOEXEC); 4121 ASSERT_LE(0, fd); 4122 4123 EXPECT_EQ(EBADF, test_ftruncate(fd)); 4124 EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd)); 4125 4126 ASSERT_EQ(0, close(fd)); 4127 4128 /* Enables Landlock. */ 4129 ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4130 ASSERT_LE(0, ruleset_fd); 4131 enforce_ruleset(_metadata, ruleset_fd); 4132 ASSERT_EQ(0, close(ruleset_fd)); 4133 4134 /* 4135 * Checks that after enabling Landlock, 4136 * - the file can still be opened with O_PATH 4137 * - both ioctl and truncate still yield EBADF (not EACCES). 4138 */ 4139 fd = open(dir_s1d1, O_PATH | O_CLOEXEC); 4140 ASSERT_LE(0, fd); 4141 4142 EXPECT_EQ(EBADF, test_ftruncate(fd)); 4143 EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd)); 4144 4145 ASSERT_EQ(0, close(fd)); 4146 } 4147 4148 /* 4149 * ioctl_error - generically call the given ioctl with a pointer to a 4150 * sufficiently large zeroed-out memory region. 4151 * 4152 * Returns the IOCTLs error, or 0. 4153 */ 4154 static int ioctl_error(struct __test_metadata *const _metadata, int fd, 4155 unsigned int cmd) 4156 { 4157 char buf[128]; /* sufficiently large */ 4158 int res, stdinbak_fd; 4159 4160 /* 4161 * Depending on the IOCTL command, parts of the zeroed-out buffer might 4162 * be interpreted as file descriptor numbers. We do not want to 4163 * accidentally operate on file descriptor 0 (stdin), so we temporarily 4164 * move stdin to a different FD and close FD 0 for the IOCTL call. 4165 */ 4166 stdinbak_fd = dup(0); 4167 ASSERT_LT(0, stdinbak_fd); 4168 ASSERT_EQ(0, close(0)); 4169 4170 /* Invokes the IOCTL with a zeroed-out buffer. */ 4171 bzero(&buf, sizeof(buf)); 4172 res = ioctl(fd, cmd, &buf); 4173 4174 /* Restores the old FD 0 and closes the backup FD. */ 4175 ASSERT_EQ(0, dup2(stdinbak_fd, 0)); 4176 ASSERT_EQ(0, close(stdinbak_fd)); 4177 4178 if (res < 0) 4179 return errno; 4180 4181 return 0; 4182 } 4183 4184 /* Define some linux/falloc.h IOCTL commands which are not available in uapi headers. */ 4185 struct space_resv { 4186 __s16 l_type; 4187 __s16 l_whence; 4188 __s64 l_start; 4189 __s64 l_len; /* len == 0 means until end of file */ 4190 __s32 l_sysid; 4191 __u32 l_pid; 4192 __s32 l_pad[4]; /* reserved area */ 4193 }; 4194 4195 #define FS_IOC_RESVSP _IOW('X', 40, struct space_resv) 4196 #define FS_IOC_UNRESVSP _IOW('X', 41, struct space_resv) 4197 #define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv) 4198 #define FS_IOC_UNRESVSP64 _IOW('X', 43, struct space_resv) 4199 #define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv) 4200 4201 /* 4202 * Tests a series of blanket-permitted and denied IOCTLs. 4203 */ 4204 TEST_F_FORK(layout1, blanket_permitted_ioctls) 4205 { 4206 const struct landlock_ruleset_attr attr = { 4207 .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4208 }; 4209 int ruleset_fd, fd; 4210 4211 /* Enables Landlock. */ 4212 ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4213 ASSERT_LE(0, ruleset_fd); 4214 enforce_ruleset(_metadata, ruleset_fd); 4215 ASSERT_EQ(0, close(ruleset_fd)); 4216 4217 fd = open("/dev/null", O_RDWR | O_CLOEXEC); 4218 ASSERT_LE(0, fd); 4219 4220 /* 4221 * Checks permitted commands. 4222 * These ones may return errors, but should not be blocked by Landlock. 4223 */ 4224 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOCLEX)); 4225 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONCLEX)); 4226 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIONBIO)); 4227 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOASYNC)); 4228 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIOQSIZE)); 4229 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIFREEZE)); 4230 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FITHAW)); 4231 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_FIEMAP)); 4232 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIGETBSZ)); 4233 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONE)); 4234 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FICLONERANGE)); 4235 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FIDEDUPERANGE)); 4236 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSUUID)); 4237 EXPECT_NE(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFSSYSFSPATH)); 4238 4239 /* 4240 * Checks blocked commands. 4241 * A call to a blocked IOCTL command always returns EACCES. 4242 */ 4243 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD)); 4244 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_GETFLAGS)); 4245 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_SETFLAGS)); 4246 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSGETXATTR)); 4247 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_FSSETXATTR)); 4248 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIBMAP)); 4249 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP)); 4250 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_RESVSP64)); 4251 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP)); 4252 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_UNRESVSP64)); 4253 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_ZERO_RANGE)); 4254 4255 /* Default case is also blocked. */ 4256 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, 0xc00ffeee)); 4257 4258 ASSERT_EQ(0, close(fd)); 4259 } 4260 4261 /* 4262 * Named pipes are not governed by the LANDLOCK_ACCESS_FS_IOCTL_DEV right, 4263 * because they are not character or block devices. 4264 */ 4265 TEST_F_FORK(layout1, named_pipe_ioctl) 4266 { 4267 pid_t child_pid; 4268 int fd, ruleset_fd; 4269 const char *const path = file1_s1d1; 4270 const struct landlock_ruleset_attr attr = { 4271 .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4272 }; 4273 4274 ASSERT_EQ(0, unlink(path)); 4275 ASSERT_EQ(0, mkfifo(path, 0600)); 4276 4277 /* Enables Landlock. */ 4278 ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4279 ASSERT_LE(0, ruleset_fd); 4280 enforce_ruleset(_metadata, ruleset_fd); 4281 ASSERT_EQ(0, close(ruleset_fd)); 4282 4283 /* The child process opens the pipe for writing. */ 4284 child_pid = fork(); 4285 ASSERT_NE(-1, child_pid); 4286 if (child_pid == 0) { 4287 fd = open(path, O_WRONLY); 4288 close(fd); 4289 exit(0); 4290 } 4291 4292 fd = open(path, O_RDONLY); 4293 ASSERT_LE(0, fd); 4294 4295 /* FIONREAD is implemented by pipefifo_fops. */ 4296 EXPECT_EQ(0, test_fionread_ioctl(fd)); 4297 4298 ASSERT_EQ(0, close(fd)); 4299 ASSERT_EQ(0, unlink(path)); 4300 4301 ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0)); 4302 } 4303 4304 /* For named UNIX domain sockets, no IOCTL restrictions apply. */ 4305 TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) 4306 { 4307 const char *const path = file1_s1d1; 4308 int srv_fd, cli_fd, ruleset_fd; 4309 socklen_t size; 4310 struct sockaddr_un srv_un, cli_un; 4311 const struct landlock_ruleset_attr attr = { 4312 .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4313 }; 4314 4315 /* Sets up a server */ 4316 srv_un.sun_family = AF_UNIX; 4317 strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path)); 4318 4319 ASSERT_EQ(0, unlink(path)); 4320 srv_fd = socket(AF_UNIX, SOCK_STREAM, 0); 4321 ASSERT_LE(0, srv_fd); 4322 4323 size = offsetof(struct sockaddr_un, sun_path) + strlen(srv_un.sun_path); 4324 ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, size)); 4325 ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */)); 4326 4327 /* Enables Landlock. */ 4328 ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4329 ASSERT_LE(0, ruleset_fd); 4330 enforce_ruleset(_metadata, ruleset_fd); 4331 ASSERT_EQ(0, close(ruleset_fd)); 4332 4333 /* Sets up a client connection to it */ 4334 cli_un.sun_family = AF_UNIX; 4335 cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); 4336 ASSERT_LE(0, cli_fd); 4337 4338 size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path); 4339 ASSERT_EQ(0, bind(cli_fd, (struct sockaddr *)&cli_un, size)); 4340 4341 bzero(&cli_un, sizeof(cli_un)); 4342 cli_un.sun_family = AF_UNIX; 4343 strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path)); 4344 size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path); 4345 4346 ASSERT_EQ(0, connect(cli_fd, (struct sockaddr *)&cli_un, size)); 4347 4348 /* FIONREAD and other IOCTLs should not be forbidden. */ 4349 EXPECT_EQ(0, test_fionread_ioctl(cli_fd)); 4350 4351 ASSERT_EQ(0, close(cli_fd)); 4352 } 4353 4354 /* clang-format off */ 4355 FIXTURE(ioctl) {}; 4356 4357 FIXTURE_SETUP(ioctl) {}; 4358 4359 FIXTURE_TEARDOWN(ioctl) {}; 4360 /* clang-format on */ 4361 4362 FIXTURE_VARIANT(ioctl) 4363 { 4364 const __u64 handled; 4365 const __u64 allowed; 4366 const mode_t open_mode; 4367 /* 4368 * FIONREAD is used as a characteristic device-specific IOCTL command. 4369 * It is implemented in fs/ioctl.c for regular files, 4370 * but we do not blanket-permit it for devices. 4371 */ 4372 const int expected_fionread_result; 4373 }; 4374 4375 /* clang-format off */ 4376 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_none) { 4377 /* clang-format on */ 4378 .handled = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4379 .allowed = 0, 4380 .open_mode = O_RDWR, 4381 .expected_fionread_result = EACCES, 4382 }; 4383 4384 /* clang-format off */ 4385 FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_i) { 4386 /* clang-format on */ 4387 .handled = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4388 .allowed = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4389 .open_mode = O_RDWR, 4390 .expected_fionread_result = 0, 4391 }; 4392 4393 /* clang-format off */ 4394 FIXTURE_VARIANT_ADD(ioctl, unhandled) { 4395 /* clang-format on */ 4396 .handled = LANDLOCK_ACCESS_FS_EXECUTE, 4397 .allowed = LANDLOCK_ACCESS_FS_EXECUTE, 4398 .open_mode = O_RDWR, 4399 .expected_fionread_result = 0, 4400 }; 4401 4402 TEST_F_FORK(ioctl, handle_dir_access_file) 4403 { 4404 const int flag = 0; 4405 const struct rule rules[] = { 4406 { 4407 .path = "/dev", 4408 .access = variant->allowed, 4409 }, 4410 {}, 4411 }; 4412 int file_fd, ruleset_fd; 4413 4414 /* Enables Landlock. */ 4415 ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4416 ASSERT_LE(0, ruleset_fd); 4417 enforce_ruleset(_metadata, ruleset_fd); 4418 ASSERT_EQ(0, close(ruleset_fd)); 4419 4420 file_fd = open("/dev/zero", variant->open_mode); 4421 ASSERT_LE(0, file_fd); 4422 4423 /* Checks that IOCTL commands return the expected errors. */ 4424 EXPECT_EQ(variant->expected_fionread_result, 4425 test_fionread_ioctl(file_fd)); 4426 4427 /* Checks that unrestrictable commands are unrestricted. */ 4428 EXPECT_EQ(0, ioctl(file_fd, FIOCLEX)); 4429 EXPECT_EQ(0, ioctl(file_fd, FIONCLEX)); 4430 EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag)); 4431 EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag)); 4432 EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag)); 4433 4434 ASSERT_EQ(0, close(file_fd)); 4435 } 4436 4437 TEST_F_FORK(ioctl, handle_dir_access_dir) 4438 { 4439 const int flag = 0; 4440 const struct rule rules[] = { 4441 { 4442 .path = "/dev", 4443 .access = variant->allowed, 4444 }, 4445 {}, 4446 }; 4447 int dir_fd, ruleset_fd; 4448 4449 /* Enables Landlock. */ 4450 ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4451 ASSERT_LE(0, ruleset_fd); 4452 enforce_ruleset(_metadata, ruleset_fd); 4453 ASSERT_EQ(0, close(ruleset_fd)); 4454 4455 /* 4456 * Ignore variant->open_mode for this test, as we intend to open a 4457 * directory. If the directory can not be opened, the variant is 4458 * infeasible to test with an opened directory. 4459 */ 4460 dir_fd = open("/dev", O_RDONLY); 4461 if (dir_fd < 0) 4462 return; 4463 4464 /* 4465 * Checks that IOCTL commands return the expected errors. 4466 * We do not use the expected values from the fixture here. 4467 * 4468 * When using IOCTL on a directory, no Landlock restrictions apply. 4469 */ 4470 EXPECT_EQ(0, test_fionread_ioctl(dir_fd)); 4471 4472 /* Checks that unrestrictable commands are unrestricted. */ 4473 EXPECT_EQ(0, ioctl(dir_fd, FIOCLEX)); 4474 EXPECT_EQ(0, ioctl(dir_fd, FIONCLEX)); 4475 EXPECT_EQ(0, ioctl(dir_fd, FIONBIO, &flag)); 4476 EXPECT_EQ(0, ioctl(dir_fd, FIOASYNC, &flag)); 4477 EXPECT_EQ(0, ioctl(dir_fd, FIGETBSZ, &flag)); 4478 4479 ASSERT_EQ(0, close(dir_fd)); 4480 } 4481 4482 TEST_F_FORK(ioctl, handle_file_access_file) 4483 { 4484 const int flag = 0; 4485 const struct rule rules[] = { 4486 { 4487 .path = "/dev/zero", 4488 .access = variant->allowed, 4489 }, 4490 {}, 4491 }; 4492 int file_fd, ruleset_fd; 4493 4494 /* Enables Landlock. */ 4495 ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4496 ASSERT_LE(0, ruleset_fd); 4497 enforce_ruleset(_metadata, ruleset_fd); 4498 ASSERT_EQ(0, close(ruleset_fd)); 4499 4500 file_fd = open("/dev/zero", variant->open_mode); 4501 ASSERT_LE(0, file_fd) 4502 { 4503 TH_LOG("Failed to open /dev/zero: %s", strerror(errno)); 4504 } 4505 4506 /* Checks that IOCTL commands return the expected errors. */ 4507 EXPECT_EQ(variant->expected_fionread_result, 4508 test_fionread_ioctl(file_fd)); 4509 4510 /* Checks that unrestrictable commands are unrestricted. */ 4511 EXPECT_EQ(0, ioctl(file_fd, FIOCLEX)); 4512 EXPECT_EQ(0, ioctl(file_fd, FIONCLEX)); 4513 EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag)); 4514 EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag)); 4515 EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag)); 4516 4517 ASSERT_EQ(0, close(file_fd)); 4518 } 4519 4520 /* clang-format off */ 4521 FIXTURE(layout1_bind) {}; 4522 /* clang-format on */ 4523 4524 FIXTURE_SETUP(layout1_bind) 4525 { 4526 prepare_layout(_metadata); 4527 4528 create_layout1(_metadata); 4529 4530 set_cap(_metadata, CAP_SYS_ADMIN); 4531 ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL)); 4532 clear_cap(_metadata, CAP_SYS_ADMIN); 4533 } 4534 4535 FIXTURE_TEARDOWN_PARENT(layout1_bind) 4536 { 4537 /* umount(dir_s2d2)) is handled by namespace lifetime. */ 4538 4539 remove_layout1(_metadata); 4540 4541 cleanup_layout(_metadata); 4542 } 4543 4544 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; 4545 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; 4546 4547 /* 4548 * layout1_bind hierarchy: 4549 * 4550 * tmp 4551 * ├── s1d1 4552 * │ ├── f1 4553 * │ ├── f2 4554 * │ └── s1d2 4555 * │ ├── f1 4556 * │ ├── f2 4557 * │ └── s1d3 4558 * │ ├── f1 4559 * │ └── f2 4560 * ├── s2d1 4561 * │ ├── f1 4562 * │ └── s2d2 4563 * │ ├── f1 4564 * │ ├── f2 4565 * │ └── s1d3 4566 * │ ├── f1 4567 * │ └── f2 4568 * └── s3d1 4569 * └── s3d2 4570 * └── s3d3 4571 */ 4572 4573 TEST_F_FORK(layout1_bind, no_restriction) 4574 { 4575 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 4576 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 4577 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 4578 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 4579 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 4580 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 4581 4582 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY)); 4583 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY)); 4584 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY)); 4585 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 4586 ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY)); 4587 ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY)); 4588 4589 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY)); 4590 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 4591 4592 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 4593 } 4594 4595 TEST_F_FORK(layout1_bind, same_content_same_file) 4596 { 4597 /* 4598 * Sets access right on parent directories of both source and 4599 * destination mount points. 4600 */ 4601 const struct rule layer1_parent[] = { 4602 { 4603 .path = dir_s1d1, 4604 .access = ACCESS_RO, 4605 }, 4606 { 4607 .path = dir_s2d1, 4608 .access = ACCESS_RW, 4609 }, 4610 {}, 4611 }; 4612 /* 4613 * Sets access rights on the same bind-mounted directories. The result 4614 * should be ACCESS_RW for both directories, but not both hierarchies 4615 * because of the first layer. 4616 */ 4617 const struct rule layer2_mount_point[] = { 4618 { 4619 .path = dir_s1d2, 4620 .access = LANDLOCK_ACCESS_FS_READ_FILE, 4621 }, 4622 { 4623 .path = dir_s2d2, 4624 .access = ACCESS_RW, 4625 }, 4626 {}, 4627 }; 4628 /* Only allow read-access to the s1d3 hierarchies. */ 4629 const struct rule layer3_source[] = { 4630 { 4631 .path = dir_s1d3, 4632 .access = LANDLOCK_ACCESS_FS_READ_FILE, 4633 }, 4634 {}, 4635 }; 4636 /* Removes all access rights. */ 4637 const struct rule layer4_destination[] = { 4638 { 4639 .path = bind_file1_s1d3, 4640 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 4641 }, 4642 {}, 4643 }; 4644 int ruleset_fd; 4645 4646 /* Sets rules for the parent directories. */ 4647 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent); 4648 ASSERT_LE(0, ruleset_fd); 4649 enforce_ruleset(_metadata, ruleset_fd); 4650 ASSERT_EQ(0, close(ruleset_fd)); 4651 4652 /* Checks source hierarchy. */ 4653 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 4654 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 4655 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 4656 4657 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 4658 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 4659 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 4660 4661 /* Checks destination hierarchy. */ 4662 ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR)); 4663 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 4664 4665 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 4666 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 4667 4668 /* Sets rules for the mount points. */ 4669 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point); 4670 ASSERT_LE(0, ruleset_fd); 4671 enforce_ruleset(_metadata, ruleset_fd); 4672 ASSERT_EQ(0, close(ruleset_fd)); 4673 4674 /* Checks source hierarchy. */ 4675 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 4676 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 4677 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 4678 4679 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 4680 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 4681 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 4682 4683 /* Checks destination hierarchy. */ 4684 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY)); 4685 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY)); 4686 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 4687 4688 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 4689 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 4690 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 4691 4692 /* Sets a (shared) rule only on the source. */ 4693 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source); 4694 ASSERT_LE(0, ruleset_fd); 4695 enforce_ruleset(_metadata, ruleset_fd); 4696 ASSERT_EQ(0, close(ruleset_fd)); 4697 4698 /* Checks source hierarchy. */ 4699 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY)); 4700 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 4701 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 4702 4703 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 4704 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 4705 ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 4706 4707 /* Checks destination hierarchy. */ 4708 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY)); 4709 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY)); 4710 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 4711 4712 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 4713 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 4714 ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 4715 4716 /* Sets a (shared) rule only on the destination. */ 4717 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination); 4718 ASSERT_LE(0, ruleset_fd); 4719 enforce_ruleset(_metadata, ruleset_fd); 4720 ASSERT_EQ(0, close(ruleset_fd)); 4721 4722 /* Checks source hierarchy. */ 4723 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 4724 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 4725 4726 /* Checks destination hierarchy. */ 4727 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY)); 4728 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 4729 } 4730 4731 TEST_F_FORK(layout1_bind, reparent_cross_mount) 4732 { 4733 const struct rule layer1[] = { 4734 { 4735 /* dir_s2d1 is beneath the dir_s2d2 mount point. */ 4736 .path = dir_s2d1, 4737 .access = LANDLOCK_ACCESS_FS_REFER, 4738 }, 4739 { 4740 .path = bind_dir_s1d3, 4741 .access = LANDLOCK_ACCESS_FS_EXECUTE, 4742 }, 4743 {}, 4744 }; 4745 int ruleset_fd = create_ruleset( 4746 _metadata, 4747 LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1); 4748 4749 ASSERT_LE(0, ruleset_fd); 4750 enforce_ruleset(_metadata, ruleset_fd); 4751 ASSERT_EQ(0, close(ruleset_fd)); 4752 4753 /* Checks basic denied move. */ 4754 ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2)); 4755 ASSERT_EQ(EXDEV, errno); 4756 4757 /* Checks real cross-mount move (Landlock is not involved). */ 4758 ASSERT_EQ(-1, rename(file1_s2d1, file1_s2d2)); 4759 ASSERT_EQ(EXDEV, errno); 4760 4761 /* Checks move that will give more accesses. */ 4762 ASSERT_EQ(-1, rename(file1_s2d2, bind_file1_s1d3)); 4763 ASSERT_EQ(EXDEV, errno); 4764 4765 /* Checks legitimate downgrade move. */ 4766 ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2)); 4767 } 4768 4769 #define LOWER_BASE TMP_DIR "/lower" 4770 #define LOWER_DATA LOWER_BASE "/data" 4771 static const char lower_fl1[] = LOWER_DATA "/fl1"; 4772 static const char lower_dl1[] = LOWER_DATA "/dl1"; 4773 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; 4774 static const char lower_fo1[] = LOWER_DATA "/fo1"; 4775 static const char lower_do1[] = LOWER_DATA "/do1"; 4776 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; 4777 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; 4778 4779 static const char (*lower_base_files[])[] = { 4780 &lower_fl1, 4781 &lower_fo1, 4782 NULL, 4783 }; 4784 static const char (*lower_base_directories[])[] = { 4785 &lower_dl1, 4786 &lower_do1, 4787 NULL, 4788 }; 4789 static const char (*lower_sub_files[])[] = { 4790 &lower_dl1_fl2, 4791 &lower_do1_fo2, 4792 &lower_do1_fl3, 4793 NULL, 4794 }; 4795 4796 #define UPPER_BASE TMP_DIR "/upper" 4797 #define UPPER_DATA UPPER_BASE "/data" 4798 #define UPPER_WORK UPPER_BASE "/work" 4799 static const char upper_fu1[] = UPPER_DATA "/fu1"; 4800 static const char upper_du1[] = UPPER_DATA "/du1"; 4801 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; 4802 static const char upper_fo1[] = UPPER_DATA "/fo1"; 4803 static const char upper_do1[] = UPPER_DATA "/do1"; 4804 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; 4805 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; 4806 4807 static const char (*upper_base_files[])[] = { 4808 &upper_fu1, 4809 &upper_fo1, 4810 NULL, 4811 }; 4812 static const char (*upper_base_directories[])[] = { 4813 &upper_du1, 4814 &upper_do1, 4815 NULL, 4816 }; 4817 static const char (*upper_sub_files[])[] = { 4818 &upper_du1_fu2, 4819 &upper_do1_fo2, 4820 &upper_do1_fu3, 4821 NULL, 4822 }; 4823 4824 #define MERGE_BASE TMP_DIR "/merge" 4825 #define MERGE_DATA MERGE_BASE "/data" 4826 static const char merge_fl1[] = MERGE_DATA "/fl1"; 4827 static const char merge_dl1[] = MERGE_DATA "/dl1"; 4828 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; 4829 static const char merge_fu1[] = MERGE_DATA "/fu1"; 4830 static const char merge_du1[] = MERGE_DATA "/du1"; 4831 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; 4832 static const char merge_fo1[] = MERGE_DATA "/fo1"; 4833 static const char merge_do1[] = MERGE_DATA "/do1"; 4834 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; 4835 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; 4836 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; 4837 4838 static const char (*merge_base_files[])[] = { 4839 &merge_fl1, 4840 &merge_fu1, 4841 &merge_fo1, 4842 NULL, 4843 }; 4844 static const char (*merge_base_directories[])[] = { 4845 &merge_dl1, 4846 &merge_du1, 4847 &merge_do1, 4848 NULL, 4849 }; 4850 static const char (*merge_sub_files[])[] = { 4851 &merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2, 4852 &merge_do1_fl3, &merge_do1_fu3, NULL, 4853 }; 4854 4855 /* 4856 * layout2_overlay hierarchy: 4857 * 4858 * tmp 4859 * ├── lower 4860 * │ └── data 4861 * │ ├── dl1 4862 * │ │ └── fl2 4863 * │ ├── do1 4864 * │ │ ├── fl3 4865 * │ │ └── fo2 4866 * │ ├── fl1 4867 * │ └── fo1 4868 * ├── merge 4869 * │ └── data 4870 * │ ├── dl1 4871 * │ │ └── fl2 4872 * │ ├── do1 4873 * │ │ ├── fl3 4874 * │ │ ├── fo2 4875 * │ │ └── fu3 4876 * │ ├── du1 4877 * │ │ └── fu2 4878 * │ ├── fl1 4879 * │ ├── fo1 4880 * │ └── fu1 4881 * └── upper 4882 * ├── data 4883 * │ ├── do1 4884 * │ │ ├── fo2 4885 * │ │ └── fu3 4886 * │ ├── du1 4887 * │ │ └── fu2 4888 * │ ├── fo1 4889 * │ └── fu1 4890 * └── work 4891 * └── work 4892 */ 4893 4894 FIXTURE(layout2_overlay) 4895 { 4896 bool skip_test; 4897 }; 4898 4899 FIXTURE_SETUP(layout2_overlay) 4900 { 4901 if (!supports_filesystem("overlay")) { 4902 self->skip_test = true; 4903 SKIP(return, "overlayfs is not supported (setup)"); 4904 } 4905 4906 prepare_layout(_metadata); 4907 4908 create_directory(_metadata, LOWER_BASE); 4909 set_cap(_metadata, CAP_SYS_ADMIN); 4910 /* Creates tmpfs mount points to get deterministic overlayfs. */ 4911 ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE)); 4912 clear_cap(_metadata, CAP_SYS_ADMIN); 4913 create_file(_metadata, lower_fl1); 4914 create_file(_metadata, lower_dl1_fl2); 4915 create_file(_metadata, lower_fo1); 4916 create_file(_metadata, lower_do1_fo2); 4917 create_file(_metadata, lower_do1_fl3); 4918 4919 create_directory(_metadata, UPPER_BASE); 4920 set_cap(_metadata, CAP_SYS_ADMIN); 4921 ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE)); 4922 clear_cap(_metadata, CAP_SYS_ADMIN); 4923 create_file(_metadata, upper_fu1); 4924 create_file(_metadata, upper_du1_fu2); 4925 create_file(_metadata, upper_fo1); 4926 create_file(_metadata, upper_do1_fo2); 4927 create_file(_metadata, upper_do1_fu3); 4928 ASSERT_EQ(0, mkdir(UPPER_WORK, 0700)); 4929 4930 create_directory(_metadata, MERGE_DATA); 4931 set_cap(_metadata, CAP_SYS_ADMIN); 4932 set_cap(_metadata, CAP_DAC_OVERRIDE); 4933 ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0, 4934 "lowerdir=" LOWER_DATA ",upperdir=" UPPER_DATA 4935 ",workdir=" UPPER_WORK)); 4936 clear_cap(_metadata, CAP_DAC_OVERRIDE); 4937 clear_cap(_metadata, CAP_SYS_ADMIN); 4938 } 4939 4940 FIXTURE_TEARDOWN_PARENT(layout2_overlay) 4941 { 4942 if (self->skip_test) 4943 SKIP(return, "overlayfs is not supported (teardown)"); 4944 4945 EXPECT_EQ(0, remove_path(lower_do1_fl3)); 4946 EXPECT_EQ(0, remove_path(lower_dl1_fl2)); 4947 EXPECT_EQ(0, remove_path(lower_fl1)); 4948 EXPECT_EQ(0, remove_path(lower_do1_fo2)); 4949 EXPECT_EQ(0, remove_path(lower_fo1)); 4950 4951 /* umount(LOWER_BASE)) is handled by namespace lifetime. */ 4952 EXPECT_EQ(0, remove_path(LOWER_BASE)); 4953 4954 EXPECT_EQ(0, remove_path(upper_do1_fu3)); 4955 EXPECT_EQ(0, remove_path(upper_du1_fu2)); 4956 EXPECT_EQ(0, remove_path(upper_fu1)); 4957 EXPECT_EQ(0, remove_path(upper_do1_fo2)); 4958 EXPECT_EQ(0, remove_path(upper_fo1)); 4959 EXPECT_EQ(0, remove_path(UPPER_WORK "/work")); 4960 4961 /* umount(UPPER_BASE)) is handled by namespace lifetime. */ 4962 EXPECT_EQ(0, remove_path(UPPER_BASE)); 4963 4964 /* umount(MERGE_DATA)) is handled by namespace lifetime. */ 4965 EXPECT_EQ(0, remove_path(MERGE_DATA)); 4966 4967 cleanup_layout(_metadata); 4968 } 4969 4970 TEST_F_FORK(layout2_overlay, no_restriction) 4971 { 4972 if (self->skip_test) 4973 SKIP(return, "overlayfs is not supported (test)"); 4974 4975 ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY)); 4976 ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY)); 4977 ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY)); 4978 ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY)); 4979 ASSERT_EQ(0, test_open(lower_do1, O_RDONLY)); 4980 ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY)); 4981 ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY)); 4982 4983 ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY)); 4984 ASSERT_EQ(0, test_open(upper_du1, O_RDONLY)); 4985 ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY)); 4986 ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY)); 4987 ASSERT_EQ(0, test_open(upper_do1, O_RDONLY)); 4988 ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY)); 4989 ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY)); 4990 4991 ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY)); 4992 ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY)); 4993 ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY)); 4994 ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY)); 4995 ASSERT_EQ(0, test_open(merge_du1, O_RDONLY)); 4996 ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY)); 4997 ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY)); 4998 ASSERT_EQ(0, test_open(merge_do1, O_RDONLY)); 4999 ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY)); 5000 ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY)); 5001 ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY)); 5002 } 5003 5004 #define for_each_path(path_list, path_entry, i) \ 5005 for (i = 0, path_entry = *path_list[i]; path_list[i]; \ 5006 path_entry = *path_list[++i]) 5007 5008 TEST_F_FORK(layout2_overlay, same_content_different_file) 5009 { 5010 /* Sets access right on parent directories of both layers. */ 5011 const struct rule layer1_base[] = { 5012 { 5013 .path = LOWER_BASE, 5014 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5015 }, 5016 { 5017 .path = UPPER_BASE, 5018 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5019 }, 5020 { 5021 .path = MERGE_BASE, 5022 .access = ACCESS_RW, 5023 }, 5024 {}, 5025 }; 5026 const struct rule layer2_data[] = { 5027 { 5028 .path = LOWER_DATA, 5029 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5030 }, 5031 { 5032 .path = UPPER_DATA, 5033 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5034 }, 5035 { 5036 .path = MERGE_DATA, 5037 .access = ACCESS_RW, 5038 }, 5039 {}, 5040 }; 5041 /* Sets access right on directories inside both layers. */ 5042 const struct rule layer3_subdirs[] = { 5043 { 5044 .path = lower_dl1, 5045 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5046 }, 5047 { 5048 .path = lower_do1, 5049 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5050 }, 5051 { 5052 .path = upper_du1, 5053 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5054 }, 5055 { 5056 .path = upper_do1, 5057 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5058 }, 5059 { 5060 .path = merge_dl1, 5061 .access = ACCESS_RW, 5062 }, 5063 { 5064 .path = merge_du1, 5065 .access = ACCESS_RW, 5066 }, 5067 { 5068 .path = merge_do1, 5069 .access = ACCESS_RW, 5070 }, 5071 {}, 5072 }; 5073 /* Tighten access rights to the files. */ 5074 const struct rule layer4_files[] = { 5075 { 5076 .path = lower_dl1_fl2, 5077 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5078 }, 5079 { 5080 .path = lower_do1_fo2, 5081 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5082 }, 5083 { 5084 .path = lower_do1_fl3, 5085 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5086 }, 5087 { 5088 .path = upper_du1_fu2, 5089 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5090 }, 5091 { 5092 .path = upper_do1_fo2, 5093 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5094 }, 5095 { 5096 .path = upper_do1_fu3, 5097 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5098 }, 5099 { 5100 .path = merge_dl1_fl2, 5101 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5102 LANDLOCK_ACCESS_FS_WRITE_FILE, 5103 }, 5104 { 5105 .path = merge_du1_fu2, 5106 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5107 LANDLOCK_ACCESS_FS_WRITE_FILE, 5108 }, 5109 { 5110 .path = merge_do1_fo2, 5111 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5112 LANDLOCK_ACCESS_FS_WRITE_FILE, 5113 }, 5114 { 5115 .path = merge_do1_fl3, 5116 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5117 LANDLOCK_ACCESS_FS_WRITE_FILE, 5118 }, 5119 { 5120 .path = merge_do1_fu3, 5121 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5122 LANDLOCK_ACCESS_FS_WRITE_FILE, 5123 }, 5124 {}, 5125 }; 5126 const struct rule layer5_merge_only[] = { 5127 { 5128 .path = MERGE_DATA, 5129 .access = LANDLOCK_ACCESS_FS_READ_FILE | 5130 LANDLOCK_ACCESS_FS_WRITE_FILE, 5131 }, 5132 {}, 5133 }; 5134 int ruleset_fd; 5135 size_t i; 5136 const char *path_entry; 5137 5138 if (self->skip_test) 5139 SKIP(return, "overlayfs is not supported (test)"); 5140 5141 /* Sets rules on base directories (i.e. outside overlay scope). */ 5142 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 5143 ASSERT_LE(0, ruleset_fd); 5144 enforce_ruleset(_metadata, ruleset_fd); 5145 ASSERT_EQ(0, close(ruleset_fd)); 5146 5147 /* Checks lower layer. */ 5148 for_each_path(lower_base_files, path_entry, i) { 5149 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5150 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5151 } 5152 for_each_path(lower_base_directories, path_entry, i) { 5153 ASSERT_EQ(EACCES, 5154 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5155 } 5156 for_each_path(lower_sub_files, path_entry, i) { 5157 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5158 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5159 } 5160 /* Checks upper layer. */ 5161 for_each_path(upper_base_files, path_entry, i) { 5162 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5163 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5164 } 5165 for_each_path(upper_base_directories, path_entry, i) { 5166 ASSERT_EQ(EACCES, 5167 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5168 } 5169 for_each_path(upper_sub_files, path_entry, i) { 5170 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5171 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5172 } 5173 /* 5174 * Checks that access rights are independent from the lower and upper 5175 * layers: write access to upper files viewed through the merge point 5176 * is still allowed, and write access to lower file viewed (and copied) 5177 * through the merge point is still allowed. 5178 */ 5179 for_each_path(merge_base_files, path_entry, i) { 5180 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5181 } 5182 for_each_path(merge_base_directories, path_entry, i) { 5183 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5184 } 5185 for_each_path(merge_sub_files, path_entry, i) { 5186 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5187 } 5188 5189 /* Sets rules on data directories (i.e. inside overlay scope). */ 5190 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data); 5191 ASSERT_LE(0, ruleset_fd); 5192 enforce_ruleset(_metadata, ruleset_fd); 5193 ASSERT_EQ(0, close(ruleset_fd)); 5194 5195 /* Checks merge. */ 5196 for_each_path(merge_base_files, path_entry, i) { 5197 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5198 } 5199 for_each_path(merge_base_directories, path_entry, i) { 5200 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5201 } 5202 for_each_path(merge_sub_files, path_entry, i) { 5203 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5204 } 5205 5206 /* Same checks with tighter rules. */ 5207 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs); 5208 ASSERT_LE(0, ruleset_fd); 5209 enforce_ruleset(_metadata, ruleset_fd); 5210 ASSERT_EQ(0, close(ruleset_fd)); 5211 5212 /* Checks changes for lower layer. */ 5213 for_each_path(lower_base_files, path_entry, i) { 5214 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 5215 } 5216 /* Checks changes for upper layer. */ 5217 for_each_path(upper_base_files, path_entry, i) { 5218 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 5219 } 5220 /* Checks all merge accesses. */ 5221 for_each_path(merge_base_files, path_entry, i) { 5222 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 5223 } 5224 for_each_path(merge_base_directories, path_entry, i) { 5225 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5226 } 5227 for_each_path(merge_sub_files, path_entry, i) { 5228 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5229 } 5230 5231 /* Sets rules directly on overlayed files. */ 5232 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files); 5233 ASSERT_LE(0, ruleset_fd); 5234 enforce_ruleset(_metadata, ruleset_fd); 5235 ASSERT_EQ(0, close(ruleset_fd)); 5236 5237 /* Checks unchanged accesses on lower layer. */ 5238 for_each_path(lower_sub_files, path_entry, i) { 5239 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5240 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5241 } 5242 /* Checks unchanged accesses on upper layer. */ 5243 for_each_path(upper_sub_files, path_entry, i) { 5244 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 5245 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 5246 } 5247 /* Checks all merge accesses. */ 5248 for_each_path(merge_base_files, path_entry, i) { 5249 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 5250 } 5251 for_each_path(merge_base_directories, path_entry, i) { 5252 ASSERT_EQ(EACCES, 5253 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5254 } 5255 for_each_path(merge_sub_files, path_entry, i) { 5256 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5257 } 5258 5259 /* Only allowes access to the merge hierarchy. */ 5260 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only); 5261 ASSERT_LE(0, ruleset_fd); 5262 enforce_ruleset(_metadata, ruleset_fd); 5263 ASSERT_EQ(0, close(ruleset_fd)); 5264 5265 /* Checks new accesses on lower layer. */ 5266 for_each_path(lower_sub_files, path_entry, i) { 5267 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 5268 } 5269 /* Checks new accesses on upper layer. */ 5270 for_each_path(upper_sub_files, path_entry, i) { 5271 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 5272 } 5273 /* Checks all merge accesses. */ 5274 for_each_path(merge_base_files, path_entry, i) { 5275 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 5276 } 5277 for_each_path(merge_base_directories, path_entry, i) { 5278 ASSERT_EQ(EACCES, 5279 test_open(path_entry, O_RDONLY | O_DIRECTORY)); 5280 } 5281 for_each_path(merge_sub_files, path_entry, i) { 5282 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 5283 } 5284 } 5285 5286 FIXTURE(layout3_fs) 5287 { 5288 bool has_created_dir; 5289 bool has_created_file; 5290 bool skip_test; 5291 }; 5292 5293 FIXTURE_VARIANT(layout3_fs) 5294 { 5295 const struct mnt_opt mnt; 5296 const char *const file_path; 5297 unsigned int cwd_fs_magic; 5298 }; 5299 5300 /* clang-format off */ 5301 FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) { 5302 /* clang-format on */ 5303 .mnt = { 5304 .type = "tmpfs", 5305 .data = MNT_TMP_DATA, 5306 }, 5307 .file_path = file1_s1d1, 5308 }; 5309 5310 FIXTURE_VARIANT_ADD(layout3_fs, ramfs) { 5311 .mnt = { 5312 .type = "ramfs", 5313 .data = "mode=700", 5314 }, 5315 .file_path = TMP_DIR "/dir/file", 5316 }; 5317 5318 FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) { 5319 .mnt = { 5320 .type = "cgroup2", 5321 }, 5322 .file_path = TMP_DIR "/test/cgroup.procs", 5323 }; 5324 5325 FIXTURE_VARIANT_ADD(layout3_fs, proc) { 5326 .mnt = { 5327 .type = "proc", 5328 }, 5329 .file_path = TMP_DIR "/self/status", 5330 }; 5331 5332 FIXTURE_VARIANT_ADD(layout3_fs, sysfs) { 5333 .mnt = { 5334 .type = "sysfs", 5335 }, 5336 .file_path = TMP_DIR "/kernel/notes", 5337 }; 5338 5339 FIXTURE_VARIANT_ADD(layout3_fs, hostfs) { 5340 .mnt = { 5341 .source = TMP_DIR, 5342 .flags = MS_BIND, 5343 }, 5344 .file_path = TMP_DIR "/dir/file", 5345 .cwd_fs_magic = HOSTFS_SUPER_MAGIC, 5346 }; 5347 5348 static char *dirname_alloc(const char *path) 5349 { 5350 char *dup; 5351 5352 if (!path) 5353 return NULL; 5354 5355 dup = strdup(path); 5356 if (!dup) 5357 return NULL; 5358 5359 return dirname(dup); 5360 } 5361 5362 FIXTURE_SETUP(layout3_fs) 5363 { 5364 struct stat statbuf; 5365 char *dir_path = dirname_alloc(variant->file_path); 5366 5367 if (!supports_filesystem(variant->mnt.type) || 5368 !cwd_matches_fs(variant->cwd_fs_magic)) { 5369 self->skip_test = true; 5370 SKIP(return, "this filesystem is not supported (setup)"); 5371 } 5372 5373 prepare_layout_opt(_metadata, &variant->mnt); 5374 5375 /* Creates directory when required. */ 5376 if (stat(dir_path, &statbuf)) { 5377 set_cap(_metadata, CAP_DAC_OVERRIDE); 5378 EXPECT_EQ(0, mkdir(dir_path, 0700)) 5379 { 5380 TH_LOG("Failed to create directory \"%s\": %s", 5381 dir_path, strerror(errno)); 5382 } 5383 self->has_created_dir = true; 5384 clear_cap(_metadata, CAP_DAC_OVERRIDE); 5385 } 5386 5387 /* Creates file when required. */ 5388 if (stat(variant->file_path, &statbuf)) { 5389 int fd; 5390 5391 set_cap(_metadata, CAP_DAC_OVERRIDE); 5392 fd = creat(variant->file_path, 0600); 5393 EXPECT_LE(0, fd) 5394 { 5395 TH_LOG("Failed to create file \"%s\": %s", 5396 variant->file_path, strerror(errno)); 5397 } 5398 EXPECT_EQ(0, close(fd)); 5399 self->has_created_file = true; 5400 clear_cap(_metadata, CAP_DAC_OVERRIDE); 5401 } 5402 5403 free(dir_path); 5404 } 5405 5406 FIXTURE_TEARDOWN_PARENT(layout3_fs) 5407 { 5408 if (self->skip_test) 5409 SKIP(return, "this filesystem is not supported (teardown)"); 5410 5411 if (self->has_created_file) { 5412 set_cap(_metadata, CAP_DAC_OVERRIDE); 5413 /* 5414 * Don't check for error because the file might already 5415 * have been removed (cf. release_inode test). 5416 */ 5417 unlink(variant->file_path); 5418 clear_cap(_metadata, CAP_DAC_OVERRIDE); 5419 } 5420 5421 if (self->has_created_dir) { 5422 char *dir_path = dirname_alloc(variant->file_path); 5423 5424 set_cap(_metadata, CAP_DAC_OVERRIDE); 5425 /* 5426 * Don't check for error because the directory might already 5427 * have been removed (cf. release_inode test). 5428 */ 5429 rmdir(dir_path); 5430 clear_cap(_metadata, CAP_DAC_OVERRIDE); 5431 free(dir_path); 5432 } 5433 5434 cleanup_layout(_metadata); 5435 } 5436 5437 static void layer3_fs_tag_inode(struct __test_metadata *const _metadata, 5438 FIXTURE_DATA(layout3_fs) * self, 5439 const FIXTURE_VARIANT(layout3_fs) * variant, 5440 const char *const rule_path) 5441 { 5442 const struct rule layer1_allow_read_file[] = { 5443 { 5444 .path = rule_path, 5445 .access = LANDLOCK_ACCESS_FS_READ_FILE, 5446 }, 5447 {}, 5448 }; 5449 const struct landlock_ruleset_attr layer2_deny_everything_attr = { 5450 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 5451 }; 5452 const char *const dev_null_path = "/dev/null"; 5453 int ruleset_fd; 5454 5455 if (self->skip_test) 5456 SKIP(return, "this filesystem is not supported (test)"); 5457 5458 /* Checks without Landlock. */ 5459 EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); 5460 EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); 5461 5462 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 5463 layer1_allow_read_file); 5464 EXPECT_LE(0, ruleset_fd); 5465 enforce_ruleset(_metadata, ruleset_fd); 5466 EXPECT_EQ(0, close(ruleset_fd)); 5467 5468 EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); 5469 EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); 5470 5471 /* Forbids directory reading. */ 5472 ruleset_fd = 5473 landlock_create_ruleset(&layer2_deny_everything_attr, 5474 sizeof(layer2_deny_everything_attr), 0); 5475 EXPECT_LE(0, ruleset_fd); 5476 enforce_ruleset(_metadata, ruleset_fd); 5477 EXPECT_EQ(0, close(ruleset_fd)); 5478 5479 /* Checks with Landlock and forbidden access. */ 5480 EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); 5481 EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); 5482 } 5483 5484 /* Matrix of tests to check file hierarchy evaluation. */ 5485 5486 TEST_F_FORK(layout3_fs, tag_inode_dir_parent) 5487 { 5488 /* The current directory must not be the root for this test. */ 5489 layer3_fs_tag_inode(_metadata, self, variant, "."); 5490 } 5491 5492 TEST_F_FORK(layout3_fs, tag_inode_dir_mnt) 5493 { 5494 layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR); 5495 } 5496 5497 TEST_F_FORK(layout3_fs, tag_inode_dir_child) 5498 { 5499 char *dir_path = dirname_alloc(variant->file_path); 5500 5501 layer3_fs_tag_inode(_metadata, self, variant, dir_path); 5502 free(dir_path); 5503 } 5504 5505 TEST_F_FORK(layout3_fs, tag_inode_file) 5506 { 5507 layer3_fs_tag_inode(_metadata, self, variant, variant->file_path); 5508 } 5509 5510 /* Light version of layout1.release_inodes */ 5511 TEST_F_FORK(layout3_fs, release_inodes) 5512 { 5513 const struct rule layer1[] = { 5514 { 5515 .path = TMP_DIR, 5516 .access = LANDLOCK_ACCESS_FS_READ_DIR, 5517 }, 5518 {}, 5519 }; 5520 int ruleset_fd; 5521 5522 if (self->skip_test) 5523 SKIP(return, "this filesystem is not supported (test)"); 5524 5525 /* Clean up for the teardown to not fail. */ 5526 if (self->has_created_file) 5527 EXPECT_EQ(0, remove_path(variant->file_path)); 5528 5529 if (self->has_created_dir) { 5530 char *dir_path = dirname_alloc(variant->file_path); 5531 5532 /* Don't check for error because of cgroup specificities. */ 5533 remove_path(dir_path); 5534 free(dir_path); 5535 } 5536 5537 ruleset_fd = 5538 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1); 5539 ASSERT_LE(0, ruleset_fd); 5540 5541 /* Unmount the filesystem while it is being used by a ruleset. */ 5542 set_cap(_metadata, CAP_SYS_ADMIN); 5543 ASSERT_EQ(0, umount(TMP_DIR)); 5544 clear_cap(_metadata, CAP_SYS_ADMIN); 5545 5546 /* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */ 5547 set_cap(_metadata, CAP_SYS_ADMIN); 5548 ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR)); 5549 clear_cap(_metadata, CAP_SYS_ADMIN); 5550 5551 enforce_ruleset(_metadata, ruleset_fd); 5552 ASSERT_EQ(0, close(ruleset_fd)); 5553 5554 /* Checks that access to the new mount point is denied. */ 5555 ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY)); 5556 } 5557 5558 static int matches_log_fs_extra(struct __test_metadata *const _metadata, 5559 int audit_fd, const char *const blockers, 5560 const char *const path, const char *const extra) 5561 { 5562 static const char log_template[] = REGEX_LANDLOCK_PREFIX 5563 " blockers=fs\\.%s path=\"%s\" dev=\"[^\"]\\+\" ino=[0-9]\\+$"; 5564 char *absolute_path = NULL; 5565 size_t log_match_remaining = sizeof(log_template) + strlen(blockers) + 5566 PATH_MAX * 2 + 5567 (extra ? strlen(extra) : 0) + 1; 5568 char log_match[log_match_remaining]; 5569 char *log_match_cursor = log_match; 5570 size_t chunk_len; 5571 5572 chunk_len = snprintf(log_match_cursor, log_match_remaining, 5573 REGEX_LANDLOCK_PREFIX " blockers=%s path=\"", 5574 blockers); 5575 if (chunk_len < 0 || chunk_len >= log_match_remaining) 5576 return -E2BIG; 5577 5578 /* 5579 * It is assume that absolute_path does not contain control characters nor 5580 * spaces, see audit_string_contains_control(). 5581 */ 5582 absolute_path = realpath(path, NULL); 5583 if (!absolute_path) 5584 return -errno; 5585 5586 log_match_remaining -= chunk_len; 5587 log_match_cursor += chunk_len; 5588 log_match_cursor = regex_escape(absolute_path, log_match_cursor, 5589 log_match_remaining); 5590 free(absolute_path); 5591 if (log_match_cursor < 0) 5592 return (long long)log_match_cursor; 5593 5594 log_match_remaining -= log_match_cursor - log_match; 5595 chunk_len = snprintf(log_match_cursor, log_match_remaining, 5596 "\" dev=\"[^\"]\\+\" ino=[0-9]\\+%s$", 5597 extra ?: ""); 5598 if (chunk_len < 0 || chunk_len >= log_match_remaining) 5599 return -E2BIG; 5600 5601 return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match, 5602 NULL); 5603 } 5604 5605 static int matches_log_fs(struct __test_metadata *const _metadata, int audit_fd, 5606 const char *const blockers, const char *const path) 5607 { 5608 return matches_log_fs_extra(_metadata, audit_fd, blockers, path, NULL); 5609 } 5610 5611 FIXTURE(audit_layout1) 5612 { 5613 struct audit_filter audit_filter; 5614 int audit_fd; 5615 }; 5616 5617 FIXTURE_SETUP(audit_layout1) 5618 { 5619 prepare_layout(_metadata); 5620 5621 create_layout1(_metadata); 5622 5623 set_cap(_metadata, CAP_AUDIT_CONTROL); 5624 self->audit_fd = audit_init_with_exe_filter(&self->audit_filter); 5625 EXPECT_LE(0, self->audit_fd); 5626 disable_caps(_metadata); 5627 } 5628 5629 FIXTURE_TEARDOWN_PARENT(audit_layout1) 5630 { 5631 remove_layout1(_metadata); 5632 5633 cleanup_layout(_metadata); 5634 5635 EXPECT_EQ(0, audit_cleanup(-1, NULL)); 5636 } 5637 5638 TEST_F(audit_layout1, execute_make) 5639 { 5640 struct audit_records records; 5641 5642 copy_file(_metadata, bin_true, file1_s1d1); 5643 test_execute(_metadata, 0, file1_s1d1); 5644 test_check_exec(_metadata, 0, file1_s1d1); 5645 5646 drop_access_rights(_metadata, 5647 &(struct landlock_ruleset_attr){ 5648 .handled_access_fs = 5649 LANDLOCK_ACCESS_FS_EXECUTE, 5650 }); 5651 5652 test_execute(_metadata, EACCES, file1_s1d1); 5653 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute", 5654 file1_s1d1)); 5655 test_check_exec(_metadata, EACCES, file1_s1d1); 5656 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute", 5657 file1_s1d1)); 5658 5659 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5660 EXPECT_EQ(0, records.access); 5661 EXPECT_EQ(0, records.domain); 5662 } 5663 5664 /* 5665 * Using a set of handled/denied access rights make it possible to check that 5666 * only the blocked ones are logged. 5667 */ 5668 5669 /* clang-format off */ 5670 static const __u64 access_fs_16 = 5671 LANDLOCK_ACCESS_FS_EXECUTE | 5672 LANDLOCK_ACCESS_FS_WRITE_FILE | 5673 LANDLOCK_ACCESS_FS_READ_FILE | 5674 LANDLOCK_ACCESS_FS_READ_DIR | 5675 LANDLOCK_ACCESS_FS_REMOVE_DIR | 5676 LANDLOCK_ACCESS_FS_REMOVE_FILE | 5677 LANDLOCK_ACCESS_FS_MAKE_CHAR | 5678 LANDLOCK_ACCESS_FS_MAKE_DIR | 5679 LANDLOCK_ACCESS_FS_MAKE_REG | 5680 LANDLOCK_ACCESS_FS_MAKE_SOCK | 5681 LANDLOCK_ACCESS_FS_MAKE_FIFO | 5682 LANDLOCK_ACCESS_FS_MAKE_BLOCK | 5683 LANDLOCK_ACCESS_FS_MAKE_SYM | 5684 LANDLOCK_ACCESS_FS_REFER | 5685 LANDLOCK_ACCESS_FS_TRUNCATE | 5686 LANDLOCK_ACCESS_FS_IOCTL_DEV; 5687 /* clang-format on */ 5688 5689 TEST_F(audit_layout1, execute_read) 5690 { 5691 struct audit_records records; 5692 5693 copy_file(_metadata, bin_true, file1_s1d1); 5694 test_execute(_metadata, 0, file1_s1d1); 5695 test_check_exec(_metadata, 0, file1_s1d1); 5696 5697 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5698 .handled_access_fs = access_fs_16, 5699 }); 5700 5701 /* 5702 * The only difference with the previous audit_layout1.execute_read test is 5703 * the extra ",fs\\.read_file" blocked by the executable file. 5704 */ 5705 test_execute(_metadata, EACCES, file1_s1d1); 5706 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5707 "fs\\.execute,fs\\.read_file", file1_s1d1)); 5708 test_check_exec(_metadata, EACCES, file1_s1d1); 5709 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5710 "fs\\.execute,fs\\.read_file", file1_s1d1)); 5711 5712 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5713 EXPECT_EQ(0, records.access); 5714 EXPECT_EQ(0, records.domain); 5715 } 5716 5717 TEST_F(audit_layout1, write_file) 5718 { 5719 struct audit_records records; 5720 5721 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5722 .handled_access_fs = access_fs_16, 5723 }); 5724 5725 EXPECT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 5726 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5727 "fs\\.write_file", file1_s1d1)); 5728 5729 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5730 EXPECT_EQ(0, records.access); 5731 EXPECT_EQ(1, records.domain); 5732 } 5733 5734 TEST_F(audit_layout1, read_file) 5735 { 5736 struct audit_records records; 5737 5738 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5739 .handled_access_fs = access_fs_16, 5740 }); 5741 5742 EXPECT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 5743 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_file", 5744 file1_s1d1)); 5745 5746 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5747 EXPECT_EQ(0, records.access); 5748 EXPECT_EQ(1, records.domain); 5749 } 5750 5751 TEST_F(audit_layout1, read_dir) 5752 { 5753 struct audit_records records; 5754 5755 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5756 .handled_access_fs = access_fs_16, 5757 }); 5758 5759 EXPECT_EQ(EACCES, test_open(dir_s1d1, O_DIRECTORY)); 5760 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_dir", 5761 dir_s1d1)); 5762 5763 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5764 EXPECT_EQ(0, records.access); 5765 EXPECT_EQ(1, records.domain); 5766 } 5767 5768 TEST_F(audit_layout1, remove_dir) 5769 { 5770 struct audit_records records; 5771 5772 EXPECT_EQ(0, unlink(file1_s1d3)); 5773 EXPECT_EQ(0, unlink(file2_s1d3)); 5774 5775 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5776 .handled_access_fs = access_fs_16, 5777 }); 5778 5779 EXPECT_EQ(-1, rmdir(dir_s1d3)); 5780 EXPECT_EQ(EACCES, errno); 5781 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5782 "fs\\.remove_dir", dir_s1d2)); 5783 5784 EXPECT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR)); 5785 EXPECT_EQ(EACCES, errno); 5786 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5787 "fs\\.remove_dir", dir_s1d2)); 5788 5789 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5790 EXPECT_EQ(0, records.access); 5791 EXPECT_EQ(0, records.domain); 5792 } 5793 5794 TEST_F(audit_layout1, remove_file) 5795 { 5796 struct audit_records records; 5797 5798 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5799 .handled_access_fs = access_fs_16, 5800 }); 5801 5802 EXPECT_EQ(-1, unlink(file1_s1d3)); 5803 EXPECT_EQ(EACCES, errno); 5804 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5805 "fs\\.remove_file", dir_s1d3)); 5806 5807 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5808 EXPECT_EQ(0, records.access); 5809 EXPECT_EQ(1, records.domain); 5810 } 5811 5812 TEST_F(audit_layout1, make_char) 5813 { 5814 struct audit_records records; 5815 5816 EXPECT_EQ(0, unlink(file1_s1d3)); 5817 5818 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5819 .handled_access_fs = access_fs_16, 5820 }); 5821 5822 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0)); 5823 EXPECT_EQ(EACCES, errno); 5824 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char", 5825 dir_s1d3)); 5826 5827 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5828 EXPECT_EQ(0, records.access); 5829 EXPECT_EQ(1, records.domain); 5830 } 5831 5832 TEST_F(audit_layout1, make_dir) 5833 { 5834 struct audit_records records; 5835 5836 EXPECT_EQ(0, unlink(file1_s1d3)); 5837 5838 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 5839 .handled_access_fs = access_fs_16, 5840 }); 5841 5842 EXPECT_EQ(-1, mkdir(file1_s1d3, 0755)); 5843 EXPECT_EQ(EACCES, errno); 5844 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_dir", 5845 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_reg) 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_IFREG | 0644, 0)); 5863 EXPECT_EQ(EACCES, errno); 5864 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_reg", 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_sock) 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, mknod(file1_s1d3, S_IFSOCK | 0644, 0)); 5883 EXPECT_EQ(EACCES, errno); 5884 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sock", 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_fifo) 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_IFIFO | 0644, 0)); 5903 EXPECT_EQ(EACCES, errno); 5904 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_fifo", 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_block) 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_IFBLK | 0644, 0)); 5923 EXPECT_EQ(EACCES, errno); 5924 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5925 "fs\\.make_block", 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_sym) 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, symlink("target", file1_s1d3)); 5943 EXPECT_EQ(EACCES, errno); 5944 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_sym", 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, refer_handled) 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 = 5960 LANDLOCK_ACCESS_FS_REFER, 5961 }); 5962 5963 EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3)); 5964 EXPECT_EQ(EXDEV, errno); 5965 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer", 5966 dir_s1d1)); 5967 EXPECT_EQ(0, matches_log_domain_allocated(self->audit_fd, NULL)); 5968 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer", 5969 dir_s1d3)); 5970 5971 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5972 EXPECT_EQ(0, records.access); 5973 EXPECT_EQ(0, records.domain); 5974 } 5975 5976 TEST_F(audit_layout1, refer_make) 5977 { 5978 struct audit_records records; 5979 5980 EXPECT_EQ(0, unlink(file1_s1d3)); 5981 5982 drop_access_rights(_metadata, 5983 &(struct landlock_ruleset_attr){ 5984 .handled_access_fs = 5985 LANDLOCK_ACCESS_FS_MAKE_REG | 5986 LANDLOCK_ACCESS_FS_REFER, 5987 }); 5988 5989 EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3)); 5990 EXPECT_EQ(EACCES, errno); 5991 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer", 5992 dir_s1d1)); 5993 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 5994 "fs\\.make_reg,fs\\.refer", dir_s1d3)); 5995 5996 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 5997 EXPECT_EQ(0, records.access); 5998 EXPECT_EQ(0, records.domain); 5999 } 6000 6001 TEST_F(audit_layout1, refer_rename) 6002 { 6003 struct audit_records records; 6004 6005 EXPECT_EQ(0, unlink(file1_s1d3)); 6006 6007 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 6008 .handled_access_fs = access_fs_16, 6009 }); 6010 6011 EXPECT_EQ(EACCES, test_rename(file1_s1d2, file1_s2d3)); 6012 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 6013 "fs\\.remove_file,fs\\.refer", dir_s1d2)); 6014 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 6015 "fs\\.remove_file,fs\\.make_reg,fs\\.refer", 6016 dir_s2d3)); 6017 6018 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6019 EXPECT_EQ(0, records.access); 6020 EXPECT_EQ(0, records.domain); 6021 } 6022 6023 TEST_F(audit_layout1, refer_exchange) 6024 { 6025 struct audit_records records; 6026 6027 EXPECT_EQ(0, unlink(file1_s1d3)); 6028 6029 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 6030 .handled_access_fs = access_fs_16, 6031 }); 6032 6033 /* 6034 * The only difference with the previous audit_layout1.refer_rename test is 6035 * the extra ",fs\\.make_reg" blocked by the source directory. 6036 */ 6037 EXPECT_EQ(EACCES, test_exchange(file1_s1d2, file1_s2d3)); 6038 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 6039 "fs\\.remove_file,fs\\.make_reg,fs\\.refer", 6040 dir_s1d2)); 6041 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 6042 "fs\\.remove_file,fs\\.make_reg,fs\\.refer", 6043 dir_s2d3)); 6044 6045 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6046 EXPECT_EQ(0, records.access); 6047 EXPECT_EQ(0, records.domain); 6048 } 6049 6050 /* 6051 * This test checks that the audit record is correctly generated when the 6052 * operation is only partially denied. This is the case for rename(2) when the 6053 * source file is allowed to be referenced but the destination directory is not. 6054 * 6055 * This is also a regression test for commit d617f0d72d80 ("landlock: Optimize 6056 * file path walks and prepare for audit support") and commit 058518c20920 6057 * ("landlock: Align partial refer access checks with final ones"). 6058 */ 6059 TEST_F(audit_layout1, refer_rename_half) 6060 { 6061 struct audit_records records; 6062 const struct rule layer1[] = { 6063 { 6064 .path = dir_s2d2, 6065 .access = LANDLOCK_ACCESS_FS_REFER, 6066 }, 6067 {}, 6068 }; 6069 int ruleset_fd = 6070 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 6071 6072 ASSERT_LE(0, ruleset_fd); 6073 enforce_ruleset(_metadata, ruleset_fd); 6074 ASSERT_EQ(0, close(ruleset_fd)); 6075 6076 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3)); 6077 ASSERT_EQ(EXDEV, errno); 6078 6079 /* Only half of the request is denied. */ 6080 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.refer", 6081 dir_s1d1)); 6082 6083 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6084 EXPECT_EQ(0, records.access); 6085 EXPECT_EQ(1, records.domain); 6086 } 6087 6088 TEST_F(audit_layout1, truncate) 6089 { 6090 struct audit_records records; 6091 6092 drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 6093 .handled_access_fs = access_fs_16, 6094 }); 6095 6096 EXPECT_EQ(-1, truncate(file1_s1d3, 0)); 6097 EXPECT_EQ(EACCES, errno); 6098 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.truncate", 6099 file1_s1d3)); 6100 6101 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6102 EXPECT_EQ(0, records.access); 6103 EXPECT_EQ(1, records.domain); 6104 } 6105 6106 TEST_F(audit_layout1, ioctl_dev) 6107 { 6108 struct audit_records records; 6109 int fd; 6110 6111 drop_access_rights(_metadata, 6112 &(struct landlock_ruleset_attr){ 6113 .handled_access_fs = 6114 access_fs_16 & 6115 ~LANDLOCK_ACCESS_FS_READ_FILE, 6116 }); 6117 6118 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 6119 ASSERT_LE(0, fd); 6120 EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD)); 6121 EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd, 6122 "fs\\.ioctl_dev", "/dev/null", 6123 " ioctlcmd=0x541b")); 6124 6125 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6126 EXPECT_EQ(0, records.access); 6127 EXPECT_EQ(1, records.domain); 6128 } 6129 6130 TEST_F(audit_layout1, mount) 6131 { 6132 struct audit_records records; 6133 6134 drop_access_rights(_metadata, 6135 &(struct landlock_ruleset_attr){ 6136 .handled_access_fs = 6137 LANDLOCK_ACCESS_FS_EXECUTE, 6138 }); 6139 6140 set_cap(_metadata, CAP_SYS_ADMIN); 6141 EXPECT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL)); 6142 EXPECT_EQ(EPERM, errno); 6143 clear_cap(_metadata, CAP_SYS_ADMIN); 6144 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, 6145 "fs\\.change_topology", dir_s3d2)); 6146 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 6147 EXPECT_EQ(0, records.access); 6148 EXPECT_EQ(1, records.domain); 6149 } 6150 6151 TEST_HARNESS_MAIN 6152