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-2021 Microsoft Corporation 8 */ 9 10 #define _GNU_SOURCE 11 #include <fcntl.h> 12 #include <linux/landlock.h> 13 #include <sched.h> 14 #include <string.h> 15 #include <sys/capability.h> 16 #include <sys/mount.h> 17 #include <sys/prctl.h> 18 #include <sys/sendfile.h> 19 #include <sys/stat.h> 20 #include <sys/sysmacros.h> 21 #include <unistd.h> 22 23 #include "common.h" 24 25 #define TMP_DIR "tmp" 26 #define BINARY_PATH "./true" 27 28 /* Paths (sibling number and depth) */ 29 static const char dir_s1d1[] = TMP_DIR "/s1d1"; 30 static const char file1_s1d1[] = TMP_DIR "/s1d1/f1"; 31 static const char file2_s1d1[] = TMP_DIR "/s1d1/f2"; 32 static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2"; 33 static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1"; 34 static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2"; 35 static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3"; 36 static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1"; 37 static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2"; 38 39 static const char dir_s2d1[] = TMP_DIR "/s2d1"; 40 static const char file1_s2d1[] = TMP_DIR "/s2d1/f1"; 41 static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2"; 42 static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1"; 43 static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3"; 44 static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1"; 45 static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2"; 46 47 static const char dir_s3d1[] = TMP_DIR "/s3d1"; 48 /* dir_s3d2 is a mount point. */ 49 static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2"; 50 static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3"; 51 52 /* 53 * layout1 hierarchy: 54 * 55 * tmp 56 * ├── s1d1 57 * │ ├── f1 58 * │ ├── f2 59 * │ └── s1d2 60 * │ ├── f1 61 * │ ├── f2 62 * │ └── s1d3 63 * │ ├── f1 64 * │ └── f2 65 * ├── s2d1 66 * │ ├── f1 67 * │ └── s2d2 68 * │ ├── f1 69 * │ └── s2d3 70 * │ ├── f1 71 * │ └── f2 72 * └── s3d1 73 * └── s3d2 74 * └── s3d3 75 */ 76 77 static void mkdir_parents(struct __test_metadata *const _metadata, 78 const char *const path) 79 { 80 char *walker; 81 const char *parent; 82 int i, err; 83 84 ASSERT_NE(path[0], '\0'); 85 walker = strdup(path); 86 ASSERT_NE(NULL, walker); 87 parent = walker; 88 for (i = 1; walker[i]; i++) { 89 if (walker[i] != '/') 90 continue; 91 walker[i] = '\0'; 92 err = mkdir(parent, 0700); 93 ASSERT_FALSE(err && errno != EEXIST) { 94 TH_LOG("Failed to create directory \"%s\": %s", 95 parent, strerror(errno)); 96 } 97 walker[i] = '/'; 98 } 99 free(walker); 100 } 101 102 static void create_directory(struct __test_metadata *const _metadata, 103 const char *const path) 104 { 105 mkdir_parents(_metadata, path); 106 ASSERT_EQ(0, mkdir(path, 0700)) { 107 TH_LOG("Failed to create directory \"%s\": %s", path, 108 strerror(errno)); 109 } 110 } 111 112 static void create_file(struct __test_metadata *const _metadata, 113 const char *const path) 114 { 115 mkdir_parents(_metadata, path); 116 ASSERT_EQ(0, mknod(path, S_IFREG | 0700, 0)) { 117 TH_LOG("Failed to create file \"%s\": %s", path, 118 strerror(errno)); 119 } 120 } 121 122 static int remove_path(const char *const path) 123 { 124 char *walker; 125 int i, ret, err = 0; 126 127 walker = strdup(path); 128 if (!walker) { 129 err = ENOMEM; 130 goto out; 131 } 132 if (unlink(path) && rmdir(path)) { 133 if (errno != ENOENT) 134 err = errno; 135 goto out; 136 } 137 for (i = strlen(walker); i > 0; i--) { 138 if (walker[i] != '/') 139 continue; 140 walker[i] = '\0'; 141 ret = rmdir(walker); 142 if (ret) { 143 if (errno != ENOTEMPTY && errno != EBUSY) 144 err = errno; 145 goto out; 146 } 147 if (strcmp(walker, TMP_DIR) == 0) 148 goto out; 149 } 150 151 out: 152 free(walker); 153 return err; 154 } 155 156 static void prepare_layout(struct __test_metadata *const _metadata) 157 { 158 disable_caps(_metadata); 159 umask(0077); 160 create_directory(_metadata, TMP_DIR); 161 162 /* 163 * Do not pollute the rest of the system: creates a private mount point 164 * for tests relying on pivot_root(2) and move_mount(2). 165 */ 166 set_cap(_metadata, CAP_SYS_ADMIN); 167 ASSERT_EQ(0, unshare(CLONE_NEWNS)); 168 ASSERT_EQ(0, mount("tmp", TMP_DIR, "tmpfs", 0, "size=4m,mode=700")); 169 ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL)); 170 clear_cap(_metadata, CAP_SYS_ADMIN); 171 } 172 173 static void cleanup_layout(struct __test_metadata *const _metadata) 174 { 175 set_cap(_metadata, CAP_SYS_ADMIN); 176 EXPECT_EQ(0, umount(TMP_DIR)); 177 clear_cap(_metadata, CAP_SYS_ADMIN); 178 EXPECT_EQ(0, remove_path(TMP_DIR)); 179 } 180 181 static void create_layout1(struct __test_metadata *const _metadata) 182 { 183 create_file(_metadata, file1_s1d1); 184 create_file(_metadata, file1_s1d2); 185 create_file(_metadata, file1_s1d3); 186 create_file(_metadata, file2_s1d1); 187 create_file(_metadata, file2_s1d2); 188 create_file(_metadata, file2_s1d3); 189 190 create_file(_metadata, file1_s2d1); 191 create_file(_metadata, file1_s2d2); 192 create_file(_metadata, file1_s2d3); 193 create_file(_metadata, file2_s2d3); 194 195 create_directory(_metadata, dir_s3d2); 196 set_cap(_metadata, CAP_SYS_ADMIN); 197 ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700")); 198 clear_cap(_metadata, CAP_SYS_ADMIN); 199 200 ASSERT_EQ(0, mkdir(dir_s3d3, 0700)); 201 } 202 203 static void remove_layout1(struct __test_metadata *const _metadata) 204 { 205 EXPECT_EQ(0, remove_path(file2_s1d3)); 206 EXPECT_EQ(0, remove_path(file2_s1d2)); 207 EXPECT_EQ(0, remove_path(file2_s1d1)); 208 EXPECT_EQ(0, remove_path(file1_s1d3)); 209 EXPECT_EQ(0, remove_path(file1_s1d2)); 210 EXPECT_EQ(0, remove_path(file1_s1d1)); 211 212 EXPECT_EQ(0, remove_path(file2_s2d3)); 213 EXPECT_EQ(0, remove_path(file1_s2d3)); 214 EXPECT_EQ(0, remove_path(file1_s2d2)); 215 EXPECT_EQ(0, remove_path(file1_s2d1)); 216 217 EXPECT_EQ(0, remove_path(dir_s3d3)); 218 set_cap(_metadata, CAP_SYS_ADMIN); 219 umount(dir_s3d2); 220 clear_cap(_metadata, CAP_SYS_ADMIN); 221 EXPECT_EQ(0, remove_path(dir_s3d2)); 222 } 223 224 FIXTURE(layout1) { 225 }; 226 227 FIXTURE_SETUP(layout1) 228 { 229 prepare_layout(_metadata); 230 231 create_layout1(_metadata); 232 } 233 234 FIXTURE_TEARDOWN(layout1) 235 { 236 remove_layout1(_metadata); 237 238 cleanup_layout(_metadata); 239 } 240 241 /* 242 * This helper enables to use the ASSERT_* macros and print the line number 243 * pointing to the test caller. 244 */ 245 static int test_open_rel(const int dirfd, const char *const path, const int flags) 246 { 247 int fd; 248 249 /* Works with file and directories. */ 250 fd = openat(dirfd, path, flags | O_CLOEXEC); 251 if (fd < 0) 252 return errno; 253 /* 254 * Mixing error codes from close(2) and open(2) should not lead to any 255 * (access type) confusion for this test. 256 */ 257 if (close(fd) != 0) 258 return errno; 259 return 0; 260 } 261 262 static int test_open(const char *const path, const int flags) 263 { 264 return test_open_rel(AT_FDCWD, path, flags); 265 } 266 267 TEST_F_FORK(layout1, no_restriction) 268 { 269 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 270 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 271 ASSERT_EQ(0, test_open(file2_s1d1, O_RDONLY)); 272 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 273 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 274 ASSERT_EQ(0, test_open(file2_s1d2, O_RDONLY)); 275 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 276 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 277 278 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY)); 279 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY)); 280 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY)); 281 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 282 ASSERT_EQ(0, test_open(dir_s2d3, O_RDONLY)); 283 ASSERT_EQ(0, test_open(file1_s2d3, O_RDONLY)); 284 285 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 286 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 287 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 288 } 289 290 TEST_F_FORK(layout1, inval) 291 { 292 struct landlock_path_beneath_attr path_beneath = { 293 .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | 294 LANDLOCK_ACCESS_FS_WRITE_FILE, 295 .parent_fd = -1, 296 }; 297 struct landlock_ruleset_attr ruleset_attr = { 298 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE | 299 LANDLOCK_ACCESS_FS_WRITE_FILE, 300 }; 301 int ruleset_fd; 302 303 path_beneath.parent_fd = open(dir_s1d2, O_PATH | O_DIRECTORY | 304 O_CLOEXEC); 305 ASSERT_LE(0, path_beneath.parent_fd); 306 307 ruleset_fd = open(dir_s1d1, O_PATH | O_DIRECTORY | O_CLOEXEC); 308 ASSERT_LE(0, ruleset_fd); 309 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 310 &path_beneath, 0)); 311 /* Returns EBADF because ruleset_fd is not a landlock-ruleset FD. */ 312 ASSERT_EQ(EBADF, errno); 313 ASSERT_EQ(0, close(ruleset_fd)); 314 315 ruleset_fd = open(dir_s1d1, O_DIRECTORY | O_CLOEXEC); 316 ASSERT_LE(0, ruleset_fd); 317 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 318 &path_beneath, 0)); 319 /* Returns EBADFD because ruleset_fd is not a valid ruleset. */ 320 ASSERT_EQ(EBADFD, errno); 321 ASSERT_EQ(0, close(ruleset_fd)); 322 323 /* Gets a real ruleset. */ 324 ruleset_fd = landlock_create_ruleset(&ruleset_attr, 325 sizeof(ruleset_attr), 0); 326 ASSERT_LE(0, ruleset_fd); 327 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 328 &path_beneath, 0)); 329 ASSERT_EQ(0, close(path_beneath.parent_fd)); 330 331 /* Tests without O_PATH. */ 332 path_beneath.parent_fd = open(dir_s1d2, O_DIRECTORY | O_CLOEXEC); 333 ASSERT_LE(0, path_beneath.parent_fd); 334 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 335 &path_beneath, 0)); 336 ASSERT_EQ(0, close(path_beneath.parent_fd)); 337 338 /* Tests with a ruleset FD. */ 339 path_beneath.parent_fd = ruleset_fd; 340 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 341 &path_beneath, 0)); 342 ASSERT_EQ(EBADFD, errno); 343 344 /* Checks unhandled allowed_access. */ 345 path_beneath.parent_fd = open(dir_s1d2, O_PATH | O_DIRECTORY | 346 O_CLOEXEC); 347 ASSERT_LE(0, path_beneath.parent_fd); 348 349 /* Test with legitimate values. */ 350 path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_EXECUTE; 351 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 352 &path_beneath, 0)); 353 ASSERT_EQ(EINVAL, errno); 354 path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE; 355 356 /* Test with unknown (64-bits) value. */ 357 path_beneath.allowed_access |= (1ULL << 60); 358 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 359 &path_beneath, 0)); 360 ASSERT_EQ(EINVAL, errno); 361 path_beneath.allowed_access &= ~(1ULL << 60); 362 363 /* Test with no access. */ 364 path_beneath.allowed_access = 0; 365 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 366 &path_beneath, 0)); 367 ASSERT_EQ(ENOMSG, errno); 368 path_beneath.allowed_access &= ~(1ULL << 60); 369 370 ASSERT_EQ(0, close(path_beneath.parent_fd)); 371 372 /* Enforces the ruleset. */ 373 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 374 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 375 376 ASSERT_EQ(0, close(ruleset_fd)); 377 } 378 379 #define ACCESS_FILE ( \ 380 LANDLOCK_ACCESS_FS_EXECUTE | \ 381 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 382 LANDLOCK_ACCESS_FS_READ_FILE) 383 384 #define ACCESS_LAST LANDLOCK_ACCESS_FS_MAKE_SYM 385 386 #define ACCESS_ALL ( \ 387 ACCESS_FILE | \ 388 LANDLOCK_ACCESS_FS_READ_DIR | \ 389 LANDLOCK_ACCESS_FS_REMOVE_DIR | \ 390 LANDLOCK_ACCESS_FS_REMOVE_FILE | \ 391 LANDLOCK_ACCESS_FS_MAKE_CHAR | \ 392 LANDLOCK_ACCESS_FS_MAKE_DIR | \ 393 LANDLOCK_ACCESS_FS_MAKE_REG | \ 394 LANDLOCK_ACCESS_FS_MAKE_SOCK | \ 395 LANDLOCK_ACCESS_FS_MAKE_FIFO | \ 396 LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ 397 ACCESS_LAST) 398 399 TEST_F_FORK(layout1, file_access_rights) 400 { 401 __u64 access; 402 int err; 403 struct landlock_path_beneath_attr path_beneath = {}; 404 struct landlock_ruleset_attr ruleset_attr = { 405 .handled_access_fs = ACCESS_ALL, 406 }; 407 const int ruleset_fd = landlock_create_ruleset(&ruleset_attr, 408 sizeof(ruleset_attr), 0); 409 410 ASSERT_LE(0, ruleset_fd); 411 412 /* Tests access rights for files. */ 413 path_beneath.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC); 414 ASSERT_LE(0, path_beneath.parent_fd); 415 for (access = 1; access <= ACCESS_LAST; access <<= 1) { 416 path_beneath.allowed_access = access; 417 err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 418 &path_beneath, 0); 419 if ((access | ACCESS_FILE) == ACCESS_FILE) { 420 ASSERT_EQ(0, err); 421 } else { 422 ASSERT_EQ(-1, err); 423 ASSERT_EQ(EINVAL, errno); 424 } 425 } 426 ASSERT_EQ(0, close(path_beneath.parent_fd)); 427 } 428 429 static void add_path_beneath(struct __test_metadata *const _metadata, 430 const int ruleset_fd, const __u64 allowed_access, 431 const char *const path) 432 { 433 struct landlock_path_beneath_attr path_beneath = { 434 .allowed_access = allowed_access, 435 }; 436 437 path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC); 438 ASSERT_LE(0, path_beneath.parent_fd) { 439 TH_LOG("Failed to open directory \"%s\": %s", path, 440 strerror(errno)); 441 } 442 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 443 &path_beneath, 0)) { 444 TH_LOG("Failed to update the ruleset with \"%s\": %s", path, 445 strerror(errno)); 446 } 447 ASSERT_EQ(0, close(path_beneath.parent_fd)); 448 } 449 450 struct rule { 451 const char *path; 452 __u64 access; 453 }; 454 455 #define ACCESS_RO ( \ 456 LANDLOCK_ACCESS_FS_READ_FILE | \ 457 LANDLOCK_ACCESS_FS_READ_DIR) 458 459 #define ACCESS_RW ( \ 460 ACCESS_RO | \ 461 LANDLOCK_ACCESS_FS_WRITE_FILE) 462 463 static int create_ruleset(struct __test_metadata *const _metadata, 464 const __u64 handled_access_fs, const struct rule rules[]) 465 { 466 int ruleset_fd, i; 467 struct landlock_ruleset_attr ruleset_attr = { 468 .handled_access_fs = handled_access_fs, 469 }; 470 471 ASSERT_NE(NULL, rules) { 472 TH_LOG("No rule list"); 473 } 474 ASSERT_NE(NULL, rules[0].path) { 475 TH_LOG("Empty rule list"); 476 } 477 478 ruleset_fd = landlock_create_ruleset(&ruleset_attr, 479 sizeof(ruleset_attr), 0); 480 ASSERT_LE(0, ruleset_fd) { 481 TH_LOG("Failed to create a ruleset: %s", strerror(errno)); 482 } 483 484 for (i = 0; rules[i].path; i++) { 485 add_path_beneath(_metadata, ruleset_fd, rules[i].access, 486 rules[i].path); 487 } 488 return ruleset_fd; 489 } 490 491 static void enforce_ruleset(struct __test_metadata *const _metadata, 492 const int ruleset_fd) 493 { 494 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 495 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) { 496 TH_LOG("Failed to enforce ruleset: %s", strerror(errno)); 497 } 498 } 499 500 TEST_F_FORK(layout1, proc_nsfs) 501 { 502 const struct rule rules[] = { 503 { 504 .path = "/dev/null", 505 .access = LANDLOCK_ACCESS_FS_READ_FILE | 506 LANDLOCK_ACCESS_FS_WRITE_FILE, 507 }, 508 {} 509 }; 510 struct landlock_path_beneath_attr path_beneath; 511 const int ruleset_fd = create_ruleset(_metadata, rules[0].access | 512 LANDLOCK_ACCESS_FS_READ_DIR, rules); 513 514 ASSERT_LE(0, ruleset_fd); 515 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY)); 516 517 enforce_ruleset(_metadata, ruleset_fd); 518 519 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 520 ASSERT_EQ(EACCES, test_open("/dev", O_RDONLY)); 521 ASSERT_EQ(0, test_open("/dev/null", O_RDONLY)); 522 ASSERT_EQ(EACCES, test_open("/dev/full", O_RDONLY)); 523 524 ASSERT_EQ(EACCES, test_open("/proc", O_RDONLY)); 525 ASSERT_EQ(EACCES, test_open("/proc/self", O_RDONLY)); 526 ASSERT_EQ(EACCES, test_open("/proc/self/ns", O_RDONLY)); 527 /* 528 * Because nsfs is an internal filesystem, /proc/self/ns/mnt is a 529 * disconnected path. Such path cannot be identified and must then be 530 * allowed. 531 */ 532 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY)); 533 534 /* 535 * Checks that it is not possible to add nsfs-like filesystem 536 * references to a ruleset. 537 */ 538 path_beneath.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | 539 LANDLOCK_ACCESS_FS_WRITE_FILE, 540 path_beneath.parent_fd = open("/proc/self/ns/mnt", O_PATH | O_CLOEXEC); 541 ASSERT_LE(0, path_beneath.parent_fd); 542 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 543 &path_beneath, 0)); 544 ASSERT_EQ(EBADFD, errno); 545 ASSERT_EQ(0, close(path_beneath.parent_fd)); 546 } 547 548 TEST_F_FORK(layout1, unpriv) { 549 const struct rule rules[] = { 550 { 551 .path = dir_s1d2, 552 .access = ACCESS_RO, 553 }, 554 {} 555 }; 556 int ruleset_fd; 557 558 drop_caps(_metadata); 559 560 ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules); 561 ASSERT_LE(0, ruleset_fd); 562 ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0)); 563 ASSERT_EQ(EPERM, errno); 564 565 /* enforce_ruleset() calls prctl(no_new_privs). */ 566 enforce_ruleset(_metadata, ruleset_fd); 567 ASSERT_EQ(0, close(ruleset_fd)); 568 } 569 570 TEST_F_FORK(layout1, effective_access) 571 { 572 const struct rule rules[] = { 573 { 574 .path = dir_s1d2, 575 .access = ACCESS_RO, 576 }, 577 { 578 .path = file1_s2d2, 579 .access = LANDLOCK_ACCESS_FS_READ_FILE | 580 LANDLOCK_ACCESS_FS_WRITE_FILE, 581 }, 582 {} 583 }; 584 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 585 char buf; 586 int reg_fd; 587 588 ASSERT_LE(0, ruleset_fd); 589 enforce_ruleset(_metadata, ruleset_fd); 590 ASSERT_EQ(0, close(ruleset_fd)); 591 592 /* Tests on a directory. */ 593 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 594 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 595 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 596 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 597 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 598 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 599 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 600 601 /* Tests on a file. */ 602 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY)); 603 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 604 605 /* Checks effective read and write actions. */ 606 reg_fd = open(file1_s2d2, O_RDWR | O_CLOEXEC); 607 ASSERT_LE(0, reg_fd); 608 ASSERT_EQ(1, write(reg_fd, ".", 1)); 609 ASSERT_LE(0, lseek(reg_fd, 0, SEEK_SET)); 610 ASSERT_EQ(1, read(reg_fd, &buf, 1)); 611 ASSERT_EQ('.', buf); 612 ASSERT_EQ(0, close(reg_fd)); 613 614 /* Just in case, double-checks effective actions. */ 615 reg_fd = open(file1_s2d2, O_RDONLY | O_CLOEXEC); 616 ASSERT_LE(0, reg_fd); 617 ASSERT_EQ(-1, write(reg_fd, &buf, 1)); 618 ASSERT_EQ(EBADF, errno); 619 ASSERT_EQ(0, close(reg_fd)); 620 } 621 622 TEST_F_FORK(layout1, unhandled_access) 623 { 624 const struct rule rules[] = { 625 { 626 .path = dir_s1d2, 627 .access = ACCESS_RO, 628 }, 629 {} 630 }; 631 /* Here, we only handle read accesses, not write accesses. */ 632 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules); 633 634 ASSERT_LE(0, ruleset_fd); 635 enforce_ruleset(_metadata, ruleset_fd); 636 ASSERT_EQ(0, close(ruleset_fd)); 637 638 /* 639 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE, 640 * opening for write-only should be allowed, but not read-write. 641 */ 642 ASSERT_EQ(0, test_open(file1_s1d1, O_WRONLY)); 643 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 644 645 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY)); 646 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 647 } 648 649 TEST_F_FORK(layout1, ruleset_overlap) 650 { 651 const struct rule rules[] = { 652 /* These rules should be ORed among them. */ 653 { 654 .path = dir_s1d2, 655 .access = LANDLOCK_ACCESS_FS_READ_FILE | 656 LANDLOCK_ACCESS_FS_WRITE_FILE, 657 }, 658 { 659 .path = dir_s1d2, 660 .access = LANDLOCK_ACCESS_FS_READ_FILE | 661 LANDLOCK_ACCESS_FS_READ_DIR, 662 }, 663 {} 664 }; 665 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 666 667 ASSERT_LE(0, ruleset_fd); 668 enforce_ruleset(_metadata, ruleset_fd); 669 ASSERT_EQ(0, close(ruleset_fd)); 670 671 /* Checks s1d1 hierarchy. */ 672 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 673 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 674 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 675 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 676 677 /* Checks s1d2 hierarchy. */ 678 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 679 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY)); 680 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 681 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 682 683 /* Checks s1d3 hierarchy. */ 684 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 685 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY)); 686 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 687 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 688 } 689 690 TEST_F_FORK(layout1, non_overlapping_accesses) 691 { 692 const struct rule layer1[] = { 693 { 694 .path = dir_s1d2, 695 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 696 }, 697 {} 698 }; 699 const struct rule layer2[] = { 700 { 701 .path = dir_s1d3, 702 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 703 }, 704 {} 705 }; 706 int ruleset_fd; 707 708 ASSERT_EQ(0, unlink(file1_s1d1)); 709 ASSERT_EQ(0, unlink(file1_s1d2)); 710 711 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 712 layer1); 713 ASSERT_LE(0, ruleset_fd); 714 enforce_ruleset(_metadata, ruleset_fd); 715 ASSERT_EQ(0, close(ruleset_fd)); 716 717 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); 718 ASSERT_EQ(EACCES, errno); 719 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0)); 720 ASSERT_EQ(0, unlink(file1_s1d2)); 721 722 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE, 723 layer2); 724 ASSERT_LE(0, ruleset_fd); 725 enforce_ruleset(_metadata, ruleset_fd); 726 ASSERT_EQ(0, close(ruleset_fd)); 727 728 /* Unchanged accesses for file creation. */ 729 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); 730 ASSERT_EQ(EACCES, errno); 731 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0)); 732 733 /* Checks file removing. */ 734 ASSERT_EQ(-1, unlink(file1_s1d2)); 735 ASSERT_EQ(EACCES, errno); 736 ASSERT_EQ(0, unlink(file1_s1d3)); 737 } 738 739 TEST_F_FORK(layout1, interleaved_masked_accesses) 740 { 741 /* 742 * Checks overly restrictive rules: 743 * layer 1: allows R s1d1/s1d2/s1d3/file1 744 * layer 2: allows RW s1d1/s1d2/s1d3 745 * allows W s1d1/s1d2 746 * denies R s1d1/s1d2 747 * layer 3: allows R s1d1 748 * layer 4: allows R s1d1/s1d2 749 * denies W s1d1/s1d2 750 * layer 5: allows R s1d1/s1d2 751 * layer 6: allows X ---- 752 * layer 7: allows W s1d1/s1d2 753 * denies R s1d1/s1d2 754 */ 755 const struct rule layer1_read[] = { 756 /* Allows read access to file1_s1d3 with the first layer. */ 757 { 758 .path = file1_s1d3, 759 .access = LANDLOCK_ACCESS_FS_READ_FILE, 760 }, 761 {} 762 }; 763 /* First rule with write restrictions. */ 764 const struct rule layer2_read_write[] = { 765 /* Start by granting read-write access via its parent directory... */ 766 { 767 .path = dir_s1d3, 768 .access = LANDLOCK_ACCESS_FS_READ_FILE | 769 LANDLOCK_ACCESS_FS_WRITE_FILE, 770 }, 771 /* ...but also denies read access via its grandparent directory. */ 772 { 773 .path = dir_s1d2, 774 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 775 }, 776 {} 777 }; 778 const struct rule layer3_read[] = { 779 /* Allows read access via its great-grandparent directory. */ 780 { 781 .path = dir_s1d1, 782 .access = LANDLOCK_ACCESS_FS_READ_FILE, 783 }, 784 {} 785 }; 786 const struct rule layer4_read_write[] = { 787 /* 788 * Try to confuse the deny access by denying write (but not 789 * read) access via its grandparent directory. 790 */ 791 { 792 .path = dir_s1d2, 793 .access = LANDLOCK_ACCESS_FS_READ_FILE, 794 }, 795 {} 796 }; 797 const struct rule layer5_read[] = { 798 /* 799 * Try to override layer2's deny read access by explicitly 800 * allowing read access via file1_s1d3's grandparent. 801 */ 802 { 803 .path = dir_s1d2, 804 .access = LANDLOCK_ACCESS_FS_READ_FILE, 805 }, 806 {} 807 }; 808 const struct rule layer6_execute[] = { 809 /* 810 * Restricts an unrelated file hierarchy with a new access 811 * (non-overlapping) type. 812 */ 813 { 814 .path = dir_s2d1, 815 .access = LANDLOCK_ACCESS_FS_EXECUTE, 816 }, 817 {} 818 }; 819 const struct rule layer7_read_write[] = { 820 /* 821 * Finally, denies read access to file1_s1d3 via its 822 * grandparent. 823 */ 824 { 825 .path = dir_s1d2, 826 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 827 }, 828 {} 829 }; 830 int ruleset_fd; 831 832 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 833 layer1_read); 834 ASSERT_LE(0, ruleset_fd); 835 enforce_ruleset(_metadata, ruleset_fd); 836 ASSERT_EQ(0, close(ruleset_fd)); 837 838 /* Checks that read access is granted for file1_s1d3 with layer 1. */ 839 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 840 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 841 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 842 843 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE | 844 LANDLOCK_ACCESS_FS_WRITE_FILE, layer2_read_write); 845 ASSERT_LE(0, ruleset_fd); 846 enforce_ruleset(_metadata, ruleset_fd); 847 ASSERT_EQ(0, close(ruleset_fd)); 848 849 /* Checks that previous access rights are unchanged with layer 2. */ 850 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 851 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 852 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 853 854 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 855 layer3_read); 856 ASSERT_LE(0, ruleset_fd); 857 enforce_ruleset(_metadata, ruleset_fd); 858 ASSERT_EQ(0, close(ruleset_fd)); 859 860 /* Checks that previous access rights are unchanged with layer 3. */ 861 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 862 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 863 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 864 865 /* This time, denies write access for the file hierarchy. */ 866 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE | 867 LANDLOCK_ACCESS_FS_WRITE_FILE, layer4_read_write); 868 ASSERT_LE(0, ruleset_fd); 869 enforce_ruleset(_metadata, ruleset_fd); 870 ASSERT_EQ(0, close(ruleset_fd)); 871 872 /* 873 * Checks that the only change with layer 4 is that write access is 874 * denied. 875 */ 876 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 877 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 878 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 879 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 880 881 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 882 layer5_read); 883 ASSERT_LE(0, ruleset_fd); 884 enforce_ruleset(_metadata, ruleset_fd); 885 ASSERT_EQ(0, close(ruleset_fd)); 886 887 /* Checks that previous access rights are unchanged with layer 5. */ 888 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 889 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 890 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 891 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 892 893 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, 894 layer6_execute); 895 ASSERT_LE(0, ruleset_fd); 896 enforce_ruleset(_metadata, ruleset_fd); 897 ASSERT_EQ(0, close(ruleset_fd)); 898 899 /* Checks that previous access rights are unchanged with layer 6. */ 900 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 901 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 902 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 903 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 904 905 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE | 906 LANDLOCK_ACCESS_FS_WRITE_FILE, layer7_read_write); 907 ASSERT_LE(0, ruleset_fd); 908 enforce_ruleset(_metadata, ruleset_fd); 909 ASSERT_EQ(0, close(ruleset_fd)); 910 911 /* Checks read access is now denied with layer 7. */ 912 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 913 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 914 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 915 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 916 } 917 918 TEST_F_FORK(layout1, inherit_subset) 919 { 920 const struct rule rules[] = { 921 { 922 .path = dir_s1d2, 923 .access = LANDLOCK_ACCESS_FS_READ_FILE | 924 LANDLOCK_ACCESS_FS_READ_DIR, 925 }, 926 {} 927 }; 928 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 929 930 ASSERT_LE(0, ruleset_fd); 931 enforce_ruleset(_metadata, ruleset_fd); 932 933 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 934 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 935 936 /* Write access is forbidden. */ 937 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 938 /* Readdir access is allowed. */ 939 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 940 941 /* Write access is forbidden. */ 942 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 943 /* Readdir access is allowed. */ 944 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 945 946 /* 947 * Tests shared rule extension: the following rules should not grant 948 * any new access, only remove some. Once enforced, these rules are 949 * ANDed with the previous ones. 950 */ 951 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE, 952 dir_s1d2); 953 /* 954 * According to ruleset_fd, dir_s1d2 should now have the 955 * LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE 956 * access rights (even if this directory is opened a second time). 957 * However, when enforcing this updated ruleset, the ruleset tied to 958 * the current process (i.e. its domain) will still only have the 959 * dir_s1d2 with LANDLOCK_ACCESS_FS_READ_FILE and 960 * LANDLOCK_ACCESS_FS_READ_DIR accesses, but 961 * LANDLOCK_ACCESS_FS_WRITE_FILE must not be allowed because it would 962 * be a privilege escalation. 963 */ 964 enforce_ruleset(_metadata, ruleset_fd); 965 966 /* Same tests and results as above. */ 967 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 968 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 969 970 /* It is still forbidden to write in file1_s1d2. */ 971 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 972 /* Readdir access is still allowed. */ 973 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 974 975 /* It is still forbidden to write in file1_s1d3. */ 976 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 977 /* Readdir access is still allowed. */ 978 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 979 980 /* 981 * Try to get more privileges by adding new access rights to the parent 982 * directory: dir_s1d1. 983 */ 984 add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1); 985 enforce_ruleset(_metadata, ruleset_fd); 986 987 /* Same tests and results as above. */ 988 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 989 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 990 991 /* It is still forbidden to write in file1_s1d2. */ 992 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 993 /* Readdir access is still allowed. */ 994 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 995 996 /* It is still forbidden to write in file1_s1d3. */ 997 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 998 /* Readdir access is still allowed. */ 999 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1000 1001 /* 1002 * Now, dir_s1d3 get a new rule tied to it, only allowing 1003 * LANDLOCK_ACCESS_FS_WRITE_FILE. The (kernel internal) difference is 1004 * that there was no rule tied to it before. 1005 */ 1006 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE, 1007 dir_s1d3); 1008 enforce_ruleset(_metadata, ruleset_fd); 1009 ASSERT_EQ(0, close(ruleset_fd)); 1010 1011 /* 1012 * Same tests and results as above, except for open(dir_s1d3) which is 1013 * now denied because the new rule mask the rule previously inherited 1014 * from dir_s1d2. 1015 */ 1016 1017 /* Same tests and results as above. */ 1018 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 1019 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1020 1021 /* It is still forbidden to write in file1_s1d2. */ 1022 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 1023 /* Readdir access is still allowed. */ 1024 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1025 1026 /* It is still forbidden to write in file1_s1d3. */ 1027 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 1028 /* 1029 * Readdir of dir_s1d3 is still allowed because of the OR policy inside 1030 * the same layer. 1031 */ 1032 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1033 } 1034 1035 TEST_F_FORK(layout1, inherit_superset) 1036 { 1037 const struct rule rules[] = { 1038 { 1039 .path = dir_s1d3, 1040 .access = ACCESS_RO, 1041 }, 1042 {} 1043 }; 1044 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1045 1046 ASSERT_LE(0, ruleset_fd); 1047 enforce_ruleset(_metadata, ruleset_fd); 1048 1049 /* Readdir access is denied for dir_s1d2. */ 1050 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1051 /* Readdir access is allowed for dir_s1d3. */ 1052 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1053 /* File access is allowed for file1_s1d3. */ 1054 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1055 1056 /* Now dir_s1d2, parent of dir_s1d3, gets a new rule tied to it. */ 1057 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_READ_FILE | 1058 LANDLOCK_ACCESS_FS_READ_DIR, dir_s1d2); 1059 enforce_ruleset(_metadata, ruleset_fd); 1060 ASSERT_EQ(0, close(ruleset_fd)); 1061 1062 /* Readdir access is still denied for dir_s1d2. */ 1063 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 1064 /* Readdir access is still allowed for dir_s1d3. */ 1065 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 1066 /* File access is still allowed for file1_s1d3. */ 1067 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1068 } 1069 1070 TEST_F_FORK(layout1, max_layers) 1071 { 1072 int i, err; 1073 const struct rule rules[] = { 1074 { 1075 .path = dir_s1d2, 1076 .access = ACCESS_RO, 1077 }, 1078 {} 1079 }; 1080 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1081 1082 ASSERT_LE(0, ruleset_fd); 1083 for (i = 0; i < 64; i++) 1084 enforce_ruleset(_metadata, ruleset_fd); 1085 1086 for (i = 0; i < 2; i++) { 1087 err = landlock_restrict_self(ruleset_fd, 0); 1088 ASSERT_EQ(-1, err); 1089 ASSERT_EQ(E2BIG, errno); 1090 } 1091 ASSERT_EQ(0, close(ruleset_fd)); 1092 } 1093 1094 TEST_F_FORK(layout1, empty_or_same_ruleset) 1095 { 1096 struct landlock_ruleset_attr ruleset_attr = {}; 1097 int ruleset_fd; 1098 1099 /* Tests empty handled_access_fs. */ 1100 ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1101 sizeof(ruleset_attr), 0); 1102 ASSERT_LE(-1, ruleset_fd); 1103 ASSERT_EQ(ENOMSG, errno); 1104 1105 /* Enforces policy which deny read access to all files. */ 1106 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE; 1107 ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1108 sizeof(ruleset_attr), 0); 1109 ASSERT_LE(0, ruleset_fd); 1110 enforce_ruleset(_metadata, ruleset_fd); 1111 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1112 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1113 1114 /* Nests a policy which deny read access to all directories. */ 1115 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR; 1116 ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1117 sizeof(ruleset_attr), 0); 1118 ASSERT_LE(0, ruleset_fd); 1119 enforce_ruleset(_metadata, ruleset_fd); 1120 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1121 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1122 1123 /* Enforces a second time with the same ruleset. */ 1124 enforce_ruleset(_metadata, ruleset_fd); 1125 ASSERT_EQ(0, close(ruleset_fd)); 1126 } 1127 1128 TEST_F_FORK(layout1, rule_on_mountpoint) 1129 { 1130 const struct rule rules[] = { 1131 { 1132 .path = dir_s1d1, 1133 .access = ACCESS_RO, 1134 }, 1135 { 1136 /* dir_s3d2 is a mount point. */ 1137 .path = dir_s3d2, 1138 .access = ACCESS_RO, 1139 }, 1140 {} 1141 }; 1142 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1143 1144 ASSERT_LE(0, ruleset_fd); 1145 enforce_ruleset(_metadata, ruleset_fd); 1146 ASSERT_EQ(0, close(ruleset_fd)); 1147 1148 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1149 1150 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY)); 1151 1152 ASSERT_EQ(EACCES, test_open(dir_s3d1, O_RDONLY)); 1153 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 1154 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 1155 } 1156 1157 TEST_F_FORK(layout1, rule_over_mountpoint) 1158 { 1159 const struct rule rules[] = { 1160 { 1161 .path = dir_s1d1, 1162 .access = ACCESS_RO, 1163 }, 1164 { 1165 /* dir_s3d2 is a mount point. */ 1166 .path = dir_s3d1, 1167 .access = ACCESS_RO, 1168 }, 1169 {} 1170 }; 1171 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1172 1173 ASSERT_LE(0, ruleset_fd); 1174 enforce_ruleset(_metadata, ruleset_fd); 1175 ASSERT_EQ(0, close(ruleset_fd)); 1176 1177 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1178 1179 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY)); 1180 1181 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 1182 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY)); 1183 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY)); 1184 } 1185 1186 /* 1187 * This test verifies that we can apply a landlock rule on the root directory 1188 * (which might require special handling). 1189 */ 1190 TEST_F_FORK(layout1, rule_over_root_allow_then_deny) 1191 { 1192 struct rule rules[] = { 1193 { 1194 .path = "/", 1195 .access = ACCESS_RO, 1196 }, 1197 {} 1198 }; 1199 int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1200 1201 ASSERT_LE(0, ruleset_fd); 1202 enforce_ruleset(_metadata, ruleset_fd); 1203 ASSERT_EQ(0, close(ruleset_fd)); 1204 1205 /* Checks allowed access. */ 1206 ASSERT_EQ(0, test_open("/", O_RDONLY)); 1207 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1208 1209 rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE; 1210 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1211 ASSERT_LE(0, ruleset_fd); 1212 enforce_ruleset(_metadata, ruleset_fd); 1213 ASSERT_EQ(0, close(ruleset_fd)); 1214 1215 /* Checks denied access (on a directory). */ 1216 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1217 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1218 } 1219 1220 TEST_F_FORK(layout1, rule_over_root_deny) 1221 { 1222 const struct rule rules[] = { 1223 { 1224 .path = "/", 1225 .access = LANDLOCK_ACCESS_FS_READ_FILE, 1226 }, 1227 {} 1228 }; 1229 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1230 1231 ASSERT_LE(0, ruleset_fd); 1232 enforce_ruleset(_metadata, ruleset_fd); 1233 ASSERT_EQ(0, close(ruleset_fd)); 1234 1235 /* Checks denied access (on a directory). */ 1236 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1237 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); 1238 } 1239 1240 TEST_F_FORK(layout1, rule_inside_mount_ns) 1241 { 1242 const struct rule rules[] = { 1243 { 1244 .path = "s3d3", 1245 .access = ACCESS_RO, 1246 }, 1247 {} 1248 }; 1249 int ruleset_fd; 1250 1251 set_cap(_metadata, CAP_SYS_ADMIN); 1252 ASSERT_EQ(0, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3)) { 1253 TH_LOG("Failed to pivot root: %s", strerror(errno)); 1254 }; 1255 ASSERT_EQ(0, chdir("/")); 1256 clear_cap(_metadata, CAP_SYS_ADMIN); 1257 1258 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1259 ASSERT_LE(0, ruleset_fd); 1260 enforce_ruleset(_metadata, ruleset_fd); 1261 ASSERT_EQ(0, close(ruleset_fd)); 1262 1263 ASSERT_EQ(0, test_open("s3d3", O_RDONLY)); 1264 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); 1265 } 1266 1267 TEST_F_FORK(layout1, mount_and_pivot) 1268 { 1269 const struct rule rules[] = { 1270 { 1271 .path = dir_s3d2, 1272 .access = ACCESS_RO, 1273 }, 1274 {} 1275 }; 1276 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1277 1278 ASSERT_LE(0, ruleset_fd); 1279 enforce_ruleset(_metadata, ruleset_fd); 1280 ASSERT_EQ(0, close(ruleset_fd)); 1281 1282 set_cap(_metadata, CAP_SYS_ADMIN); 1283 ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL)); 1284 ASSERT_EQ(EPERM, errno); 1285 ASSERT_EQ(-1, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3)); 1286 ASSERT_EQ(EPERM, errno); 1287 clear_cap(_metadata, CAP_SYS_ADMIN); 1288 } 1289 1290 TEST_F_FORK(layout1, move_mount) 1291 { 1292 const struct rule rules[] = { 1293 { 1294 .path = dir_s3d2, 1295 .access = ACCESS_RO, 1296 }, 1297 {} 1298 }; 1299 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1300 1301 ASSERT_LE(0, ruleset_fd); 1302 1303 set_cap(_metadata, CAP_SYS_ADMIN); 1304 ASSERT_EQ(0, syscall(SYS_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1305 dir_s1d2, 0)) { 1306 TH_LOG("Failed to move mount: %s", strerror(errno)); 1307 } 1308 1309 ASSERT_EQ(0, syscall(SYS_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD, 1310 dir_s3d2, 0)); 1311 clear_cap(_metadata, CAP_SYS_ADMIN); 1312 1313 enforce_ruleset(_metadata, ruleset_fd); 1314 ASSERT_EQ(0, close(ruleset_fd)); 1315 1316 set_cap(_metadata, CAP_SYS_ADMIN); 1317 ASSERT_EQ(-1, syscall(SYS_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1318 dir_s1d2, 0)); 1319 ASSERT_EQ(EPERM, errno); 1320 clear_cap(_metadata, CAP_SYS_ADMIN); 1321 } 1322 1323 TEST_F_FORK(layout1, release_inodes) 1324 { 1325 const struct rule rules[] = { 1326 { 1327 .path = dir_s1d1, 1328 .access = ACCESS_RO, 1329 }, 1330 { 1331 .path = dir_s3d2, 1332 .access = ACCESS_RO, 1333 }, 1334 { 1335 .path = dir_s3d3, 1336 .access = ACCESS_RO, 1337 }, 1338 {} 1339 }; 1340 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1341 1342 ASSERT_LE(0, ruleset_fd); 1343 /* Unmount a file hierarchy while it is being used by a ruleset. */ 1344 set_cap(_metadata, CAP_SYS_ADMIN); 1345 ASSERT_EQ(0, umount(dir_s3d2)); 1346 clear_cap(_metadata, CAP_SYS_ADMIN); 1347 1348 enforce_ruleset(_metadata, ruleset_fd); 1349 ASSERT_EQ(0, close(ruleset_fd)); 1350 1351 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 1352 ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY)); 1353 /* This dir_s3d3 would not be allowed and does not exist anyway. */ 1354 ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY)); 1355 } 1356 1357 enum relative_access { 1358 REL_OPEN, 1359 REL_CHDIR, 1360 REL_CHROOT_ONLY, 1361 REL_CHROOT_CHDIR, 1362 }; 1363 1364 static void test_relative_path(struct __test_metadata *const _metadata, 1365 const enum relative_access rel) 1366 { 1367 /* 1368 * Common layer to check that chroot doesn't ignore it (i.e. a chroot 1369 * is not a disconnected root directory). 1370 */ 1371 const struct rule layer1_base[] = { 1372 { 1373 .path = TMP_DIR, 1374 .access = ACCESS_RO, 1375 }, 1376 {} 1377 }; 1378 const struct rule layer2_subs[] = { 1379 { 1380 .path = dir_s1d2, 1381 .access = ACCESS_RO, 1382 }, 1383 { 1384 .path = dir_s2d2, 1385 .access = ACCESS_RO, 1386 }, 1387 {} 1388 }; 1389 int dirfd, ruleset_fd; 1390 1391 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 1392 ASSERT_LE(0, ruleset_fd); 1393 enforce_ruleset(_metadata, ruleset_fd); 1394 ASSERT_EQ(0, close(ruleset_fd)); 1395 1396 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs); 1397 1398 ASSERT_LE(0, ruleset_fd); 1399 switch (rel) { 1400 case REL_OPEN: 1401 case REL_CHDIR: 1402 break; 1403 case REL_CHROOT_ONLY: 1404 ASSERT_EQ(0, chdir(dir_s2d2)); 1405 break; 1406 case REL_CHROOT_CHDIR: 1407 ASSERT_EQ(0, chdir(dir_s1d2)); 1408 break; 1409 default: 1410 ASSERT_TRUE(false); 1411 return; 1412 } 1413 1414 set_cap(_metadata, CAP_SYS_CHROOT); 1415 enforce_ruleset(_metadata, ruleset_fd); 1416 1417 switch (rel) { 1418 case REL_OPEN: 1419 dirfd = open(dir_s1d2, O_DIRECTORY); 1420 ASSERT_LE(0, dirfd); 1421 break; 1422 case REL_CHDIR: 1423 ASSERT_EQ(0, chdir(dir_s1d2)); 1424 dirfd = AT_FDCWD; 1425 break; 1426 case REL_CHROOT_ONLY: 1427 /* Do chroot into dir_s1d2 (relative to dir_s2d2). */ 1428 ASSERT_EQ(0, chroot("../../s1d1/s1d2")) { 1429 TH_LOG("Failed to chroot: %s", strerror(errno)); 1430 } 1431 dirfd = AT_FDCWD; 1432 break; 1433 case REL_CHROOT_CHDIR: 1434 /* Do chroot into dir_s1d2. */ 1435 ASSERT_EQ(0, chroot(".")) { 1436 TH_LOG("Failed to chroot: %s", strerror(errno)); 1437 } 1438 dirfd = AT_FDCWD; 1439 break; 1440 } 1441 1442 ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES, 1443 test_open_rel(dirfd, "..", O_RDONLY)); 1444 ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY)); 1445 1446 if (rel == REL_CHROOT_ONLY) { 1447 /* The current directory is dir_s2d2. */ 1448 ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY)); 1449 } else { 1450 /* The current directory is dir_s1d2. */ 1451 ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY)); 1452 } 1453 1454 if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) { 1455 /* Checks the root dir_s1d2. */ 1456 ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY)); 1457 ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY)); 1458 ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY)); 1459 ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY)); 1460 } 1461 1462 if (rel != REL_CHROOT_CHDIR) { 1463 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY)); 1464 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY)); 1465 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3", O_RDONLY)); 1466 1467 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY)); 1468 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY)); 1469 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3", O_RDONLY)); 1470 } 1471 1472 if (rel == REL_OPEN) 1473 ASSERT_EQ(0, close(dirfd)); 1474 ASSERT_EQ(0, close(ruleset_fd)); 1475 } 1476 1477 TEST_F_FORK(layout1, relative_open) 1478 { 1479 test_relative_path(_metadata, REL_OPEN); 1480 } 1481 1482 TEST_F_FORK(layout1, relative_chdir) 1483 { 1484 test_relative_path(_metadata, REL_CHDIR); 1485 } 1486 1487 TEST_F_FORK(layout1, relative_chroot_only) 1488 { 1489 test_relative_path(_metadata, REL_CHROOT_ONLY); 1490 } 1491 1492 TEST_F_FORK(layout1, relative_chroot_chdir) 1493 { 1494 test_relative_path(_metadata, REL_CHROOT_CHDIR); 1495 } 1496 1497 static void copy_binary(struct __test_metadata *const _metadata, 1498 const char *const dst_path) 1499 { 1500 int dst_fd, src_fd; 1501 struct stat statbuf; 1502 1503 dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC); 1504 ASSERT_LE(0, dst_fd) { 1505 TH_LOG("Failed to open \"%s\": %s", dst_path, 1506 strerror(errno)); 1507 } 1508 src_fd = open(BINARY_PATH, O_RDONLY | O_CLOEXEC); 1509 ASSERT_LE(0, src_fd) { 1510 TH_LOG("Failed to open \"" BINARY_PATH "\": %s", 1511 strerror(errno)); 1512 } 1513 ASSERT_EQ(0, fstat(src_fd, &statbuf)); 1514 ASSERT_EQ(statbuf.st_size, sendfile(dst_fd, src_fd, 0, 1515 statbuf.st_size)); 1516 ASSERT_EQ(0, close(src_fd)); 1517 ASSERT_EQ(0, close(dst_fd)); 1518 } 1519 1520 static void test_execute(struct __test_metadata *const _metadata, 1521 const int err, const char *const path) 1522 { 1523 int status; 1524 char *const argv[] = {(char *)path, NULL}; 1525 const pid_t child = fork(); 1526 1527 ASSERT_LE(0, child); 1528 if (child == 0) { 1529 ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL)) { 1530 TH_LOG("Failed to execute \"%s\": %s", path, 1531 strerror(errno)); 1532 }; 1533 ASSERT_EQ(err, errno); 1534 _exit(_metadata->passed ? 2 : 1); 1535 return; 1536 } 1537 ASSERT_EQ(child, waitpid(child, &status, 0)); 1538 ASSERT_EQ(1, WIFEXITED(status)); 1539 ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status)) { 1540 TH_LOG("Unexpected return code for \"%s\": %s", path, 1541 strerror(errno)); 1542 }; 1543 } 1544 1545 TEST_F_FORK(layout1, execute) 1546 { 1547 const struct rule rules[] = { 1548 { 1549 .path = dir_s1d2, 1550 .access = LANDLOCK_ACCESS_FS_EXECUTE, 1551 }, 1552 {} 1553 }; 1554 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1555 rules); 1556 1557 ASSERT_LE(0, ruleset_fd); 1558 copy_binary(_metadata, file1_s1d1); 1559 copy_binary(_metadata, file1_s1d2); 1560 copy_binary(_metadata, file1_s1d3); 1561 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 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 1567 test_execute(_metadata, EACCES, file1_s1d1); 1568 1569 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 1570 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 1571 test_execute(_metadata, 0, file1_s1d2); 1572 1573 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 1574 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 1575 test_execute(_metadata, 0, file1_s1d3); 1576 } 1577 1578 TEST_F_FORK(layout1, link) 1579 { 1580 const struct rule rules[] = { 1581 { 1582 .path = dir_s1d2, 1583 .access = LANDLOCK_ACCESS_FS_MAKE_REG, 1584 }, 1585 {} 1586 }; 1587 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1588 rules); 1589 1590 ASSERT_LE(0, ruleset_fd); 1591 1592 ASSERT_EQ(0, unlink(file1_s1d1)); 1593 ASSERT_EQ(0, unlink(file1_s1d2)); 1594 ASSERT_EQ(0, unlink(file1_s1d3)); 1595 1596 enforce_ruleset(_metadata, ruleset_fd); 1597 ASSERT_EQ(0, close(ruleset_fd)); 1598 1599 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 1600 ASSERT_EQ(EACCES, errno); 1601 /* Denies linking because of reparenting. */ 1602 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2)); 1603 ASSERT_EQ(EXDEV, errno); 1604 ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3)); 1605 ASSERT_EQ(EXDEV, errno); 1606 1607 ASSERT_EQ(0, link(file2_s1d2, file1_s1d2)); 1608 ASSERT_EQ(0, link(file2_s1d3, file1_s1d3)); 1609 } 1610 1611 TEST_F_FORK(layout1, rename_file) 1612 { 1613 const struct rule rules[] = { 1614 { 1615 .path = dir_s1d3, 1616 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1617 }, 1618 { 1619 .path = dir_s2d2, 1620 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1621 }, 1622 {} 1623 }; 1624 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1625 rules); 1626 1627 ASSERT_LE(0, ruleset_fd); 1628 1629 ASSERT_EQ(0, unlink(file1_s1d1)); 1630 ASSERT_EQ(0, unlink(file1_s1d2)); 1631 1632 enforce_ruleset(_metadata, ruleset_fd); 1633 ASSERT_EQ(0, close(ruleset_fd)); 1634 1635 /* 1636 * Tries to replace a file, from a directory that allows file removal, 1637 * but to a different directory (which also allows file removal). 1638 */ 1639 ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3)); 1640 ASSERT_EQ(EXDEV, errno); 1641 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3, 1642 RENAME_EXCHANGE)); 1643 ASSERT_EQ(EXDEV, errno); 1644 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3, 1645 RENAME_EXCHANGE)); 1646 ASSERT_EQ(EXDEV, errno); 1647 1648 /* 1649 * Tries to replace a file, from a directory that denies file removal, 1650 * to a different directory (which allows file removal). 1651 */ 1652 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 1653 ASSERT_EQ(EXDEV, errno); 1654 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3, 1655 RENAME_EXCHANGE)); 1656 ASSERT_EQ(EXDEV, errno); 1657 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3, 1658 RENAME_EXCHANGE)); 1659 ASSERT_EQ(EXDEV, errno); 1660 1661 /* Exchanges files and directories that partially allow removal. */ 1662 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1, 1663 RENAME_EXCHANGE)); 1664 ASSERT_EQ(EACCES, errno); 1665 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2, 1666 RENAME_EXCHANGE)); 1667 ASSERT_EQ(EACCES, errno); 1668 1669 /* Renames files with different parents. */ 1670 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2)); 1671 ASSERT_EQ(EXDEV, errno); 1672 ASSERT_EQ(0, unlink(file1_s1d3)); 1673 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3)); 1674 ASSERT_EQ(EXDEV, errno); 1675 1676 /* Exchanges and renames files with same parent. */ 1677 ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3, 1678 RENAME_EXCHANGE)); 1679 ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3)); 1680 1681 /* Exchanges files and directories with same parent, twice. */ 1682 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 1683 RENAME_EXCHANGE)); 1684 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3, 1685 RENAME_EXCHANGE)); 1686 } 1687 1688 TEST_F_FORK(layout1, rename_dir) 1689 { 1690 const struct rule rules[] = { 1691 { 1692 .path = dir_s1d2, 1693 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1694 }, 1695 { 1696 .path = dir_s2d1, 1697 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1698 }, 1699 {} 1700 }; 1701 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1702 rules); 1703 1704 ASSERT_LE(0, ruleset_fd); 1705 1706 /* Empties dir_s1d3 to allow renaming. */ 1707 ASSERT_EQ(0, unlink(file1_s1d3)); 1708 ASSERT_EQ(0, unlink(file2_s1d3)); 1709 1710 enforce_ruleset(_metadata, ruleset_fd); 1711 ASSERT_EQ(0, close(ruleset_fd)); 1712 1713 /* Exchanges and renames directory to a different parent. */ 1714 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, 1715 RENAME_EXCHANGE)); 1716 ASSERT_EQ(EXDEV, errno); 1717 ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3)); 1718 ASSERT_EQ(EXDEV, errno); 1719 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3, 1720 RENAME_EXCHANGE)); 1721 ASSERT_EQ(EXDEV, errno); 1722 1723 /* 1724 * Exchanges directory to the same parent, which doesn't allow 1725 * directory removal. 1726 */ 1727 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1, 1728 RENAME_EXCHANGE)); 1729 ASSERT_EQ(EACCES, errno); 1730 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2, 1731 RENAME_EXCHANGE)); 1732 ASSERT_EQ(EACCES, errno); 1733 1734 /* 1735 * Exchanges and renames directory to the same parent, which allows 1736 * directory removal. 1737 */ 1738 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2, 1739 RENAME_EXCHANGE)); 1740 ASSERT_EQ(0, unlink(dir_s1d3)); 1741 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 1742 ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3)); 1743 ASSERT_EQ(0, rmdir(dir_s1d3)); 1744 } 1745 1746 TEST_F_FORK(layout1, remove_dir) 1747 { 1748 const struct rule rules[] = { 1749 { 1750 .path = dir_s1d2, 1751 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, 1752 }, 1753 {} 1754 }; 1755 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1756 rules); 1757 1758 ASSERT_LE(0, ruleset_fd); 1759 1760 ASSERT_EQ(0, unlink(file1_s1d1)); 1761 ASSERT_EQ(0, unlink(file1_s1d2)); 1762 ASSERT_EQ(0, unlink(file1_s1d3)); 1763 ASSERT_EQ(0, unlink(file2_s1d3)); 1764 1765 enforce_ruleset(_metadata, ruleset_fd); 1766 ASSERT_EQ(0, close(ruleset_fd)); 1767 1768 ASSERT_EQ(0, rmdir(dir_s1d3)); 1769 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); 1770 ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR)); 1771 1772 /* dir_s1d2 itself cannot be removed. */ 1773 ASSERT_EQ(-1, rmdir(dir_s1d2)); 1774 ASSERT_EQ(EACCES, errno); 1775 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR)); 1776 ASSERT_EQ(EACCES, errno); 1777 ASSERT_EQ(-1, rmdir(dir_s1d1)); 1778 ASSERT_EQ(EACCES, errno); 1779 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR)); 1780 ASSERT_EQ(EACCES, errno); 1781 } 1782 1783 TEST_F_FORK(layout1, remove_file) 1784 { 1785 const struct rule rules[] = { 1786 { 1787 .path = dir_s1d2, 1788 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, 1789 }, 1790 {} 1791 }; 1792 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1793 rules); 1794 1795 ASSERT_LE(0, ruleset_fd); 1796 enforce_ruleset(_metadata, ruleset_fd); 1797 ASSERT_EQ(0, close(ruleset_fd)); 1798 1799 ASSERT_EQ(-1, unlink(file1_s1d1)); 1800 ASSERT_EQ(EACCES, errno); 1801 ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0)); 1802 ASSERT_EQ(EACCES, errno); 1803 ASSERT_EQ(0, unlink(file1_s1d2)); 1804 ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0)); 1805 } 1806 1807 static void test_make_file(struct __test_metadata *const _metadata, 1808 const __u64 access, const mode_t mode, const dev_t dev) 1809 { 1810 const struct rule rules[] = { 1811 { 1812 .path = dir_s1d2, 1813 .access = access, 1814 }, 1815 {} 1816 }; 1817 const int ruleset_fd = create_ruleset(_metadata, access, rules); 1818 1819 ASSERT_LE(0, ruleset_fd); 1820 1821 ASSERT_EQ(0, unlink(file1_s1d1)); 1822 ASSERT_EQ(0, unlink(file2_s1d1)); 1823 ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev)) { 1824 TH_LOG("Failed to make file \"%s\": %s", 1825 file2_s1d1, strerror(errno)); 1826 }; 1827 1828 ASSERT_EQ(0, unlink(file1_s1d2)); 1829 ASSERT_EQ(0, unlink(file2_s1d2)); 1830 1831 ASSERT_EQ(0, unlink(file1_s1d3)); 1832 ASSERT_EQ(0, unlink(file2_s1d3)); 1833 1834 enforce_ruleset(_metadata, ruleset_fd); 1835 ASSERT_EQ(0, close(ruleset_fd)); 1836 1837 ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev)); 1838 ASSERT_EQ(EACCES, errno); 1839 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 1840 ASSERT_EQ(EACCES, errno); 1841 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 1842 ASSERT_EQ(EACCES, errno); 1843 1844 ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev)) { 1845 TH_LOG("Failed to make file \"%s\": %s", 1846 file1_s1d2, strerror(errno)); 1847 }; 1848 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 1849 ASSERT_EQ(0, unlink(file2_s1d2)); 1850 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 1851 1852 ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev)); 1853 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 1854 ASSERT_EQ(0, unlink(file2_s1d3)); 1855 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 1856 } 1857 1858 TEST_F_FORK(layout1, make_char) 1859 { 1860 /* Creates a /dev/null device. */ 1861 set_cap(_metadata, CAP_MKNOD); 1862 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR, 1863 makedev(1, 3)); 1864 } 1865 1866 TEST_F_FORK(layout1, make_block) 1867 { 1868 /* Creates a /dev/loop0 device. */ 1869 set_cap(_metadata, CAP_MKNOD); 1870 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK, 1871 makedev(7, 0)); 1872 } 1873 1874 TEST_F_FORK(layout1, make_reg_1) 1875 { 1876 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0); 1877 } 1878 1879 TEST_F_FORK(layout1, make_reg_2) 1880 { 1881 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0); 1882 } 1883 1884 TEST_F_FORK(layout1, make_sock) 1885 { 1886 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0); 1887 } 1888 1889 TEST_F_FORK(layout1, make_fifo) 1890 { 1891 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0); 1892 } 1893 1894 TEST_F_FORK(layout1, make_sym) 1895 { 1896 const struct rule rules[] = { 1897 { 1898 .path = dir_s1d2, 1899 .access = LANDLOCK_ACCESS_FS_MAKE_SYM, 1900 }, 1901 {} 1902 }; 1903 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1904 rules); 1905 1906 ASSERT_LE(0, ruleset_fd); 1907 1908 ASSERT_EQ(0, unlink(file1_s1d1)); 1909 ASSERT_EQ(0, unlink(file2_s1d1)); 1910 ASSERT_EQ(0, symlink("none", file2_s1d1)); 1911 1912 ASSERT_EQ(0, unlink(file1_s1d2)); 1913 ASSERT_EQ(0, unlink(file2_s1d2)); 1914 1915 ASSERT_EQ(0, unlink(file1_s1d3)); 1916 ASSERT_EQ(0, unlink(file2_s1d3)); 1917 1918 enforce_ruleset(_metadata, ruleset_fd); 1919 ASSERT_EQ(0, close(ruleset_fd)); 1920 1921 ASSERT_EQ(-1, symlink("none", file1_s1d1)); 1922 ASSERT_EQ(EACCES, errno); 1923 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 1924 ASSERT_EQ(EACCES, errno); 1925 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1)); 1926 ASSERT_EQ(EACCES, errno); 1927 1928 ASSERT_EQ(0, symlink("none", file1_s1d2)); 1929 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); 1930 ASSERT_EQ(0, unlink(file2_s1d2)); 1931 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2)); 1932 1933 ASSERT_EQ(0, symlink("none", file1_s1d3)); 1934 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3)); 1935 ASSERT_EQ(0, unlink(file2_s1d3)); 1936 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3)); 1937 } 1938 1939 TEST_F_FORK(layout1, make_dir) 1940 { 1941 const struct rule rules[] = { 1942 { 1943 .path = dir_s1d2, 1944 .access = LANDLOCK_ACCESS_FS_MAKE_DIR, 1945 }, 1946 {} 1947 }; 1948 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 1949 rules); 1950 1951 ASSERT_LE(0, ruleset_fd); 1952 1953 ASSERT_EQ(0, unlink(file1_s1d1)); 1954 ASSERT_EQ(0, unlink(file1_s1d2)); 1955 ASSERT_EQ(0, unlink(file1_s1d3)); 1956 1957 enforce_ruleset(_metadata, ruleset_fd); 1958 ASSERT_EQ(0, close(ruleset_fd)); 1959 1960 /* Uses file_* as directory names. */ 1961 ASSERT_EQ(-1, mkdir(file1_s1d1, 0700)); 1962 ASSERT_EQ(EACCES, errno); 1963 ASSERT_EQ(0, mkdir(file1_s1d2, 0700)); 1964 ASSERT_EQ(0, mkdir(file1_s1d3, 0700)); 1965 } 1966 1967 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd, 1968 const int open_flags) 1969 { 1970 static const char path_template[] = "/proc/self/fd/%d"; 1971 char procfd_path[sizeof(path_template) + 10]; 1972 const int procfd_path_size = snprintf(procfd_path, sizeof(procfd_path), 1973 path_template, fd); 1974 1975 ASSERT_LT(procfd_path_size, sizeof(procfd_path)); 1976 return open(procfd_path, open_flags); 1977 } 1978 1979 TEST_F_FORK(layout1, proc_unlinked_file) 1980 { 1981 const struct rule rules[] = { 1982 { 1983 .path = file1_s1d2, 1984 .access = LANDLOCK_ACCESS_FS_READ_FILE, 1985 }, 1986 {} 1987 }; 1988 int reg_fd, proc_fd; 1989 const int ruleset_fd = create_ruleset(_metadata, 1990 LANDLOCK_ACCESS_FS_READ_FILE | 1991 LANDLOCK_ACCESS_FS_WRITE_FILE, rules); 1992 1993 ASSERT_LE(0, ruleset_fd); 1994 enforce_ruleset(_metadata, ruleset_fd); 1995 ASSERT_EQ(0, close(ruleset_fd)); 1996 1997 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 1998 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 1999 reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC); 2000 ASSERT_LE(0, reg_fd); 2001 ASSERT_EQ(0, unlink(file1_s1d2)); 2002 2003 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC); 2004 ASSERT_LE(0, proc_fd); 2005 ASSERT_EQ(0, close(proc_fd)); 2006 2007 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC); 2008 ASSERT_EQ(-1, proc_fd) { 2009 TH_LOG("Successfully opened /proc/self/fd/%d: %s", 2010 reg_fd, strerror(errno)); 2011 } 2012 ASSERT_EQ(EACCES, errno); 2013 2014 ASSERT_EQ(0, close(reg_fd)); 2015 } 2016 2017 TEST_F_FORK(layout1, proc_pipe) 2018 { 2019 int proc_fd; 2020 int pipe_fds[2]; 2021 char buf = '\0'; 2022 const struct rule rules[] = { 2023 { 2024 .path = dir_s1d2, 2025 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2026 LANDLOCK_ACCESS_FS_WRITE_FILE, 2027 }, 2028 {} 2029 }; 2030 /* Limits read and write access to files tied to the filesystem. */ 2031 const int ruleset_fd = create_ruleset(_metadata, rules[0].access, 2032 rules); 2033 2034 ASSERT_LE(0, ruleset_fd); 2035 enforce_ruleset(_metadata, ruleset_fd); 2036 ASSERT_EQ(0, close(ruleset_fd)); 2037 2038 /* Checks enforcement for normal files. */ 2039 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); 2040 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR)); 2041 2042 /* Checks access to pipes through FD. */ 2043 ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC)); 2044 ASSERT_EQ(1, write(pipe_fds[1], ".", 1)) { 2045 TH_LOG("Failed to write in pipe: %s", strerror(errno)); 2046 } 2047 ASSERT_EQ(1, read(pipe_fds[0], &buf, 1)); 2048 ASSERT_EQ('.', buf); 2049 2050 /* Checks write access to pipe through /proc/self/fd . */ 2051 proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC); 2052 ASSERT_LE(0, proc_fd); 2053 ASSERT_EQ(1, write(proc_fd, ".", 1)) { 2054 TH_LOG("Failed to write through /proc/self/fd/%d: %s", 2055 pipe_fds[1], strerror(errno)); 2056 } 2057 ASSERT_EQ(0, close(proc_fd)); 2058 2059 /* Checks read access to pipe through /proc/self/fd . */ 2060 proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC); 2061 ASSERT_LE(0, proc_fd); 2062 buf = '\0'; 2063 ASSERT_EQ(1, read(proc_fd, &buf, 1)) { 2064 TH_LOG("Failed to read through /proc/self/fd/%d: %s", 2065 pipe_fds[1], strerror(errno)); 2066 } 2067 ASSERT_EQ(0, close(proc_fd)); 2068 2069 ASSERT_EQ(0, close(pipe_fds[0])); 2070 ASSERT_EQ(0, close(pipe_fds[1])); 2071 } 2072 2073 FIXTURE(layout1_bind) { 2074 }; 2075 2076 FIXTURE_SETUP(layout1_bind) 2077 { 2078 prepare_layout(_metadata); 2079 2080 create_layout1(_metadata); 2081 2082 set_cap(_metadata, CAP_SYS_ADMIN); 2083 ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL)); 2084 clear_cap(_metadata, CAP_SYS_ADMIN); 2085 } 2086 2087 FIXTURE_TEARDOWN(layout1_bind) 2088 { 2089 set_cap(_metadata, CAP_SYS_ADMIN); 2090 EXPECT_EQ(0, umount(dir_s2d2)); 2091 clear_cap(_metadata, CAP_SYS_ADMIN); 2092 2093 remove_layout1(_metadata); 2094 2095 cleanup_layout(_metadata); 2096 } 2097 2098 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; 2099 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; 2100 2101 /* 2102 * layout1_bind hierarchy: 2103 * 2104 * tmp 2105 * ├── s1d1 2106 * │ ├── f1 2107 * │ ├── f2 2108 * │ └── s1d2 2109 * │ ├── f1 2110 * │ ├── f2 2111 * │ └── s1d3 2112 * │ ├── f1 2113 * │ └── f2 2114 * ├── s2d1 2115 * │ ├── f1 2116 * │ └── s2d2 2117 * │ ├── f1 2118 * │ ├── f2 2119 * │ └── s1d3 2120 * │ ├── f1 2121 * │ └── f2 2122 * └── s3d1 2123 * └── s3d2 2124 * └── s3d3 2125 */ 2126 2127 TEST_F_FORK(layout1_bind, no_restriction) 2128 { 2129 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 2130 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 2131 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY)); 2132 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2133 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY)); 2134 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 2135 2136 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY)); 2137 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY)); 2138 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY)); 2139 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY)); 2140 ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY)); 2141 ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY)); 2142 2143 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY)); 2144 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 2145 2146 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY)); 2147 } 2148 2149 TEST_F_FORK(layout1_bind, same_content_same_file) 2150 { 2151 /* 2152 * Sets access right on parent directories of both source and 2153 * destination mount points. 2154 */ 2155 const struct rule layer1_parent[] = { 2156 { 2157 .path = dir_s1d1, 2158 .access = ACCESS_RO, 2159 }, 2160 { 2161 .path = dir_s2d1, 2162 .access = ACCESS_RW, 2163 }, 2164 {} 2165 }; 2166 /* 2167 * Sets access rights on the same bind-mounted directories. The result 2168 * should be ACCESS_RW for both directories, but not both hierarchies 2169 * because of the first layer. 2170 */ 2171 const struct rule layer2_mount_point[] = { 2172 { 2173 .path = dir_s1d2, 2174 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2175 }, 2176 { 2177 .path = dir_s2d2, 2178 .access = ACCESS_RW, 2179 }, 2180 {} 2181 }; 2182 /* Only allow read-access to the s1d3 hierarchies. */ 2183 const struct rule layer3_source[] = { 2184 { 2185 .path = dir_s1d3, 2186 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2187 }, 2188 {} 2189 }; 2190 /* Removes all access rights. */ 2191 const struct rule layer4_destination[] = { 2192 { 2193 .path = bind_file1_s1d3, 2194 .access = LANDLOCK_ACCESS_FS_WRITE_FILE, 2195 }, 2196 {} 2197 }; 2198 int ruleset_fd; 2199 2200 /* Sets rules for the parent directories. */ 2201 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent); 2202 ASSERT_LE(0, ruleset_fd); 2203 enforce_ruleset(_metadata, ruleset_fd); 2204 ASSERT_EQ(0, close(ruleset_fd)); 2205 2206 /* Checks source hierarchy. */ 2207 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 2208 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 2209 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 2210 2211 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2212 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2213 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2214 2215 /* Checks destination hierarchy. */ 2216 ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR)); 2217 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 2218 2219 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 2220 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2221 2222 /* Sets rules for the mount points. */ 2223 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point); 2224 ASSERT_LE(0, ruleset_fd); 2225 enforce_ruleset(_metadata, ruleset_fd); 2226 ASSERT_EQ(0, close(ruleset_fd)); 2227 2228 /* Checks source hierarchy. */ 2229 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 2230 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 2231 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 2232 2233 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); 2234 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2235 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2236 2237 /* Checks destination hierarchy. */ 2238 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY)); 2239 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY)); 2240 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY)); 2241 2242 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR)); 2243 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2244 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 2245 2246 /* Sets a (shared) rule only on the source. */ 2247 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source); 2248 ASSERT_LE(0, ruleset_fd); 2249 enforce_ruleset(_metadata, ruleset_fd); 2250 ASSERT_EQ(0, close(ruleset_fd)); 2251 2252 /* Checks source hierarchy. */ 2253 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY)); 2254 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY)); 2255 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); 2256 2257 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); 2258 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 2259 ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY)); 2260 2261 /* Checks destination hierarchy. */ 2262 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY)); 2263 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY)); 2264 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 2265 2266 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY)); 2267 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 2268 ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 2269 2270 /* Sets a (shared) rule only on the destination. */ 2271 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination); 2272 ASSERT_LE(0, ruleset_fd); 2273 enforce_ruleset(_metadata, ruleset_fd); 2274 ASSERT_EQ(0, close(ruleset_fd)); 2275 2276 /* Checks source hierarchy. */ 2277 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); 2278 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY)); 2279 2280 /* Checks destination hierarchy. */ 2281 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY)); 2282 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY)); 2283 } 2284 2285 #define LOWER_BASE TMP_DIR "/lower" 2286 #define LOWER_DATA LOWER_BASE "/data" 2287 static const char lower_fl1[] = LOWER_DATA "/fl1"; 2288 static const char lower_dl1[] = LOWER_DATA "/dl1"; 2289 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; 2290 static const char lower_fo1[] = LOWER_DATA "/fo1"; 2291 static const char lower_do1[] = LOWER_DATA "/do1"; 2292 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; 2293 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; 2294 2295 static const char (*lower_base_files[])[] = { 2296 &lower_fl1, 2297 &lower_fo1, 2298 NULL 2299 }; 2300 static const char (*lower_base_directories[])[] = { 2301 &lower_dl1, 2302 &lower_do1, 2303 NULL 2304 }; 2305 static const char (*lower_sub_files[])[] = { 2306 &lower_dl1_fl2, 2307 &lower_do1_fo2, 2308 &lower_do1_fl3, 2309 NULL 2310 }; 2311 2312 #define UPPER_BASE TMP_DIR "/upper" 2313 #define UPPER_DATA UPPER_BASE "/data" 2314 #define UPPER_WORK UPPER_BASE "/work" 2315 static const char upper_fu1[] = UPPER_DATA "/fu1"; 2316 static const char upper_du1[] = UPPER_DATA "/du1"; 2317 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; 2318 static const char upper_fo1[] = UPPER_DATA "/fo1"; 2319 static const char upper_do1[] = UPPER_DATA "/do1"; 2320 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; 2321 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; 2322 2323 static const char (*upper_base_files[])[] = { 2324 &upper_fu1, 2325 &upper_fo1, 2326 NULL 2327 }; 2328 static const char (*upper_base_directories[])[] = { 2329 &upper_du1, 2330 &upper_do1, 2331 NULL 2332 }; 2333 static const char (*upper_sub_files[])[] = { 2334 &upper_du1_fu2, 2335 &upper_do1_fo2, 2336 &upper_do1_fu3, 2337 NULL 2338 }; 2339 2340 #define MERGE_BASE TMP_DIR "/merge" 2341 #define MERGE_DATA MERGE_BASE "/data" 2342 static const char merge_fl1[] = MERGE_DATA "/fl1"; 2343 static const char merge_dl1[] = MERGE_DATA "/dl1"; 2344 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; 2345 static const char merge_fu1[] = MERGE_DATA "/fu1"; 2346 static const char merge_du1[] = MERGE_DATA "/du1"; 2347 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; 2348 static const char merge_fo1[] = MERGE_DATA "/fo1"; 2349 static const char merge_do1[] = MERGE_DATA "/do1"; 2350 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; 2351 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; 2352 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; 2353 2354 static const char (*merge_base_files[])[] = { 2355 &merge_fl1, 2356 &merge_fu1, 2357 &merge_fo1, 2358 NULL 2359 }; 2360 static const char (*merge_base_directories[])[] = { 2361 &merge_dl1, 2362 &merge_du1, 2363 &merge_do1, 2364 NULL 2365 }; 2366 static const char (*merge_sub_files[])[] = { 2367 &merge_dl1_fl2, 2368 &merge_du1_fu2, 2369 &merge_do1_fo2, 2370 &merge_do1_fl3, 2371 &merge_do1_fu3, 2372 NULL 2373 }; 2374 2375 /* 2376 * layout2_overlay hierarchy: 2377 * 2378 * tmp 2379 * ├── lower 2380 * │ └── data 2381 * │ ├── dl1 2382 * │ │ └── fl2 2383 * │ ├── do1 2384 * │ │ ├── fl3 2385 * │ │ └── fo2 2386 * │ ├── fl1 2387 * │ └── fo1 2388 * ├── merge 2389 * │ └── data 2390 * │ ├── dl1 2391 * │ │ └── fl2 2392 * │ ├── do1 2393 * │ │ ├── fl3 2394 * │ │ ├── fo2 2395 * │ │ └── fu3 2396 * │ ├── du1 2397 * │ │ └── fu2 2398 * │ ├── fl1 2399 * │ ├── fo1 2400 * │ └── fu1 2401 * └── upper 2402 * ├── data 2403 * │ ├── do1 2404 * │ │ ├── fo2 2405 * │ │ └── fu3 2406 * │ ├── du1 2407 * │ │ └── fu2 2408 * │ ├── fo1 2409 * │ └── fu1 2410 * └── work 2411 * └── work 2412 */ 2413 2414 FIXTURE(layout2_overlay) { 2415 }; 2416 2417 FIXTURE_SETUP(layout2_overlay) 2418 { 2419 prepare_layout(_metadata); 2420 2421 create_directory(_metadata, LOWER_BASE); 2422 set_cap(_metadata, CAP_SYS_ADMIN); 2423 /* Creates tmpfs mount points to get deterministic overlayfs. */ 2424 ASSERT_EQ(0, mount("tmp", LOWER_BASE, "tmpfs", 0, "size=4m,mode=700")); 2425 clear_cap(_metadata, CAP_SYS_ADMIN); 2426 create_file(_metadata, lower_fl1); 2427 create_file(_metadata, lower_dl1_fl2); 2428 create_file(_metadata, lower_fo1); 2429 create_file(_metadata, lower_do1_fo2); 2430 create_file(_metadata, lower_do1_fl3); 2431 2432 create_directory(_metadata, UPPER_BASE); 2433 set_cap(_metadata, CAP_SYS_ADMIN); 2434 ASSERT_EQ(0, mount("tmp", UPPER_BASE, "tmpfs", 0, "size=4m,mode=700")); 2435 clear_cap(_metadata, CAP_SYS_ADMIN); 2436 create_file(_metadata, upper_fu1); 2437 create_file(_metadata, upper_du1_fu2); 2438 create_file(_metadata, upper_fo1); 2439 create_file(_metadata, upper_do1_fo2); 2440 create_file(_metadata, upper_do1_fu3); 2441 ASSERT_EQ(0, mkdir(UPPER_WORK, 0700)); 2442 2443 create_directory(_metadata, MERGE_DATA); 2444 set_cap(_metadata, CAP_SYS_ADMIN); 2445 set_cap(_metadata, CAP_DAC_OVERRIDE); 2446 ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0, 2447 "lowerdir=" LOWER_DATA 2448 ",upperdir=" UPPER_DATA 2449 ",workdir=" UPPER_WORK)); 2450 clear_cap(_metadata, CAP_DAC_OVERRIDE); 2451 clear_cap(_metadata, CAP_SYS_ADMIN); 2452 } 2453 2454 FIXTURE_TEARDOWN(layout2_overlay) 2455 { 2456 EXPECT_EQ(0, remove_path(lower_do1_fl3)); 2457 EXPECT_EQ(0, remove_path(lower_dl1_fl2)); 2458 EXPECT_EQ(0, remove_path(lower_fl1)); 2459 EXPECT_EQ(0, remove_path(lower_do1_fo2)); 2460 EXPECT_EQ(0, remove_path(lower_fo1)); 2461 set_cap(_metadata, CAP_SYS_ADMIN); 2462 EXPECT_EQ(0, umount(LOWER_BASE)); 2463 clear_cap(_metadata, CAP_SYS_ADMIN); 2464 EXPECT_EQ(0, remove_path(LOWER_BASE)); 2465 2466 EXPECT_EQ(0, remove_path(upper_do1_fu3)); 2467 EXPECT_EQ(0, remove_path(upper_du1_fu2)); 2468 EXPECT_EQ(0, remove_path(upper_fu1)); 2469 EXPECT_EQ(0, remove_path(upper_do1_fo2)); 2470 EXPECT_EQ(0, remove_path(upper_fo1)); 2471 EXPECT_EQ(0, remove_path(UPPER_WORK "/work")); 2472 set_cap(_metadata, CAP_SYS_ADMIN); 2473 EXPECT_EQ(0, umount(UPPER_BASE)); 2474 clear_cap(_metadata, CAP_SYS_ADMIN); 2475 EXPECT_EQ(0, remove_path(UPPER_BASE)); 2476 2477 set_cap(_metadata, CAP_SYS_ADMIN); 2478 EXPECT_EQ(0, umount(MERGE_DATA)); 2479 clear_cap(_metadata, CAP_SYS_ADMIN); 2480 EXPECT_EQ(0, remove_path(MERGE_DATA)); 2481 2482 cleanup_layout(_metadata); 2483 } 2484 2485 TEST_F_FORK(layout2_overlay, no_restriction) 2486 { 2487 ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY)); 2488 ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY)); 2489 ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY)); 2490 ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY)); 2491 ASSERT_EQ(0, test_open(lower_do1, O_RDONLY)); 2492 ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY)); 2493 ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY)); 2494 2495 ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY)); 2496 ASSERT_EQ(0, test_open(upper_du1, O_RDONLY)); 2497 ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY)); 2498 ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY)); 2499 ASSERT_EQ(0, test_open(upper_do1, O_RDONLY)); 2500 ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY)); 2501 ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY)); 2502 2503 ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY)); 2504 ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY)); 2505 ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY)); 2506 ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY)); 2507 ASSERT_EQ(0, test_open(merge_du1, O_RDONLY)); 2508 ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY)); 2509 ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY)); 2510 ASSERT_EQ(0, test_open(merge_do1, O_RDONLY)); 2511 ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY)); 2512 ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY)); 2513 ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY)); 2514 } 2515 2516 #define for_each_path(path_list, path_entry, i) \ 2517 for (i = 0, path_entry = *path_list[i]; path_list[i]; \ 2518 path_entry = *path_list[++i]) 2519 2520 TEST_F_FORK(layout2_overlay, same_content_different_file) 2521 { 2522 /* Sets access right on parent directories of both layers. */ 2523 const struct rule layer1_base[] = { 2524 { 2525 .path = LOWER_BASE, 2526 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2527 }, 2528 { 2529 .path = UPPER_BASE, 2530 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2531 }, 2532 { 2533 .path = MERGE_BASE, 2534 .access = ACCESS_RW, 2535 }, 2536 {} 2537 }; 2538 const struct rule layer2_data[] = { 2539 { 2540 .path = LOWER_DATA, 2541 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2542 }, 2543 { 2544 .path = UPPER_DATA, 2545 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2546 }, 2547 { 2548 .path = MERGE_DATA, 2549 .access = ACCESS_RW, 2550 }, 2551 {} 2552 }; 2553 /* Sets access right on directories inside both layers. */ 2554 const struct rule layer3_subdirs[] = { 2555 { 2556 .path = lower_dl1, 2557 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2558 }, 2559 { 2560 .path = lower_do1, 2561 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2562 }, 2563 { 2564 .path = upper_du1, 2565 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2566 }, 2567 { 2568 .path = upper_do1, 2569 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2570 }, 2571 { 2572 .path = merge_dl1, 2573 .access = ACCESS_RW, 2574 }, 2575 { 2576 .path = merge_du1, 2577 .access = ACCESS_RW, 2578 }, 2579 { 2580 .path = merge_do1, 2581 .access = ACCESS_RW, 2582 }, 2583 {} 2584 }; 2585 /* Tighten access rights to the files. */ 2586 const struct rule layer4_files[] = { 2587 { 2588 .path = lower_dl1_fl2, 2589 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2590 }, 2591 { 2592 .path = lower_do1_fo2, 2593 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2594 }, 2595 { 2596 .path = lower_do1_fl3, 2597 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2598 }, 2599 { 2600 .path = upper_du1_fu2, 2601 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2602 }, 2603 { 2604 .path = upper_do1_fo2, 2605 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2606 }, 2607 { 2608 .path = upper_do1_fu3, 2609 .access = LANDLOCK_ACCESS_FS_READ_FILE, 2610 }, 2611 { 2612 .path = merge_dl1_fl2, 2613 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2614 LANDLOCK_ACCESS_FS_WRITE_FILE, 2615 }, 2616 { 2617 .path = merge_du1_fu2, 2618 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2619 LANDLOCK_ACCESS_FS_WRITE_FILE, 2620 }, 2621 { 2622 .path = merge_do1_fo2, 2623 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2624 LANDLOCK_ACCESS_FS_WRITE_FILE, 2625 }, 2626 { 2627 .path = merge_do1_fl3, 2628 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2629 LANDLOCK_ACCESS_FS_WRITE_FILE, 2630 }, 2631 { 2632 .path = merge_do1_fu3, 2633 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2634 LANDLOCK_ACCESS_FS_WRITE_FILE, 2635 }, 2636 {} 2637 }; 2638 const struct rule layer5_merge_only[] = { 2639 { 2640 .path = MERGE_DATA, 2641 .access = LANDLOCK_ACCESS_FS_READ_FILE | 2642 LANDLOCK_ACCESS_FS_WRITE_FILE, 2643 }, 2644 {} 2645 }; 2646 int ruleset_fd; 2647 size_t i; 2648 const char *path_entry; 2649 2650 /* Sets rules on base directories (i.e. outside overlay scope). */ 2651 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 2652 ASSERT_LE(0, ruleset_fd); 2653 enforce_ruleset(_metadata, ruleset_fd); 2654 ASSERT_EQ(0, close(ruleset_fd)); 2655 2656 /* Checks lower layer. */ 2657 for_each_path(lower_base_files, path_entry, i) { 2658 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2659 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2660 } 2661 for_each_path(lower_base_directories, path_entry, i) { 2662 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2663 } 2664 for_each_path(lower_sub_files, path_entry, i) { 2665 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2666 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2667 } 2668 /* Checks upper layer. */ 2669 for_each_path(upper_base_files, path_entry, i) { 2670 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2671 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2672 } 2673 for_each_path(upper_base_directories, path_entry, i) { 2674 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2675 } 2676 for_each_path(upper_sub_files, path_entry, i) { 2677 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2678 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2679 } 2680 /* 2681 * Checks that access rights are independent from the lower and upper 2682 * layers: write access to upper files viewed through the merge point 2683 * is still allowed, and write access to lower file viewed (and copied) 2684 * through the merge point is still allowed. 2685 */ 2686 for_each_path(merge_base_files, path_entry, i) { 2687 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2688 } 2689 for_each_path(merge_base_directories, path_entry, i) { 2690 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2691 } 2692 for_each_path(merge_sub_files, path_entry, i) { 2693 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2694 } 2695 2696 /* Sets rules on data directories (i.e. inside overlay scope). */ 2697 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data); 2698 ASSERT_LE(0, ruleset_fd); 2699 enforce_ruleset(_metadata, ruleset_fd); 2700 ASSERT_EQ(0, close(ruleset_fd)); 2701 2702 /* Checks merge. */ 2703 for_each_path(merge_base_files, path_entry, i) { 2704 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2705 } 2706 for_each_path(merge_base_directories, path_entry, i) { 2707 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2708 } 2709 for_each_path(merge_sub_files, path_entry, i) { 2710 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2711 } 2712 2713 /* Same checks with tighter rules. */ 2714 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs); 2715 ASSERT_LE(0, ruleset_fd); 2716 enforce_ruleset(_metadata, ruleset_fd); 2717 ASSERT_EQ(0, close(ruleset_fd)); 2718 2719 /* Checks changes for lower layer. */ 2720 for_each_path(lower_base_files, path_entry, i) { 2721 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2722 } 2723 /* Checks changes for upper layer. */ 2724 for_each_path(upper_base_files, path_entry, i) { 2725 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2726 } 2727 /* Checks all merge accesses. */ 2728 for_each_path(merge_base_files, path_entry, i) { 2729 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 2730 } 2731 for_each_path(merge_base_directories, path_entry, i) { 2732 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2733 } 2734 for_each_path(merge_sub_files, path_entry, i) { 2735 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2736 } 2737 2738 /* Sets rules directly on overlayed files. */ 2739 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files); 2740 ASSERT_LE(0, ruleset_fd); 2741 enforce_ruleset(_metadata, ruleset_fd); 2742 ASSERT_EQ(0, close(ruleset_fd)); 2743 2744 /* Checks unchanged accesses on lower layer. */ 2745 for_each_path(lower_sub_files, path_entry, i) { 2746 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2747 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2748 } 2749 /* Checks unchanged accesses on upper layer. */ 2750 for_each_path(upper_sub_files, path_entry, i) { 2751 ASSERT_EQ(0, test_open(path_entry, O_RDONLY)); 2752 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY)); 2753 } 2754 /* Checks all merge accesses. */ 2755 for_each_path(merge_base_files, path_entry, i) { 2756 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 2757 } 2758 for_each_path(merge_base_directories, path_entry, i) { 2759 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2760 } 2761 for_each_path(merge_sub_files, path_entry, i) { 2762 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2763 } 2764 2765 /* Only allowes access to the merge hierarchy. */ 2766 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only); 2767 ASSERT_LE(0, ruleset_fd); 2768 enforce_ruleset(_metadata, ruleset_fd); 2769 ASSERT_EQ(0, close(ruleset_fd)); 2770 2771 /* Checks new accesses on lower layer. */ 2772 for_each_path(lower_sub_files, path_entry, i) { 2773 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2774 } 2775 /* Checks new accesses on upper layer. */ 2776 for_each_path(upper_sub_files, path_entry, i) { 2777 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY)); 2778 } 2779 /* Checks all merge accesses. */ 2780 for_each_path(merge_base_files, path_entry, i) { 2781 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR)); 2782 } 2783 for_each_path(merge_base_directories, path_entry, i) { 2784 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY)); 2785 } 2786 for_each_path(merge_sub_files, path_entry, i) { 2787 ASSERT_EQ(0, test_open(path_entry, O_RDWR)); 2788 } 2789 } 2790 2791 TEST_HARNESS_MAIN 2792