linux/tools/testing/selftests/landlock/fs_test.c
<<
>>
Prefs
   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) */
  29static const char dir_s1d1[] = TMP_DIR "/s1d1";
  30static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
  31static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
  32static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
  33static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
  34static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
  35static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
  36static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
  37static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
  38
  39static const char dir_s2d1[] = TMP_DIR "/s2d1";
  40static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
  41static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
  42static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
  43static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
  44static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
  45static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
  46
  47static const char dir_s3d1[] = TMP_DIR "/s3d1";
  48/* dir_s3d2 is a mount point. */
  49static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
  50static 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
  77static 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
 102static 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
 112static 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
 122static 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
 151out:
 152        free(walker);
 153        return err;
 154}
 155
 156static 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
 173static 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
 181static 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
 203static 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
 224FIXTURE(layout1) {
 225};
 226
 227FIXTURE_SETUP(layout1)
 228{
 229        prepare_layout(_metadata);
 230
 231        create_layout1(_metadata);
 232}
 233
 234FIXTURE_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 */
 245static 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
 262static int test_open(const char *const path, const int flags)
 263{
 264        return test_open_rel(AT_FDCWD, path, flags);
 265}
 266
 267TEST_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
 290TEST_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
 399TEST_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
 429static 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
 450struct 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
 463static 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
 491static 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
 500TEST_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
 548TEST_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
 570TEST_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
 622TEST_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
 649TEST_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
 690TEST_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
 739TEST_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
 918TEST_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
1035TEST_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
1070TEST_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
1094TEST_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
1128TEST_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
1157TEST_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 */
1190TEST_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
1220TEST_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
1240TEST_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
1267TEST_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
1290TEST_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
1323TEST_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
1357enum relative_access {
1358        REL_OPEN,
1359        REL_CHDIR,
1360        REL_CHROOT_ONLY,
1361        REL_CHROOT_CHDIR,
1362};
1363
1364static 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
1477TEST_F_FORK(layout1, relative_open)
1478{
1479        test_relative_path(_metadata, REL_OPEN);
1480}
1481
1482TEST_F_FORK(layout1, relative_chdir)
1483{
1484        test_relative_path(_metadata, REL_CHDIR);
1485}
1486
1487TEST_F_FORK(layout1, relative_chroot_only)
1488{
1489        test_relative_path(_metadata, REL_CHROOT_ONLY);
1490}
1491
1492TEST_F_FORK(layout1, relative_chroot_chdir)
1493{
1494        test_relative_path(_metadata, REL_CHROOT_CHDIR);
1495}
1496
1497static 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
1520static 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
1545TEST_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
1578TEST_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
1611TEST_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
1688TEST_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
1746TEST_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
1783TEST_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
1807static 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
1858TEST_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
1866TEST_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
1874TEST_F_FORK(layout1, make_reg_1)
1875{
1876        test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
1877}
1878
1879TEST_F_FORK(layout1, make_reg_2)
1880{
1881        test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
1882}
1883
1884TEST_F_FORK(layout1, make_sock)
1885{
1886        test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
1887}
1888
1889TEST_F_FORK(layout1, make_fifo)
1890{
1891        test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
1892}
1893
1894TEST_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
1939TEST_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
1967static 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
1979TEST_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
2017TEST_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
2073FIXTURE(layout1_bind) {
2074};
2075
2076FIXTURE_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
2087FIXTURE_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
2098static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
2099static 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
2127TEST_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
2149TEST_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"
2287static const char lower_fl1[] = LOWER_DATA "/fl1";
2288static const char lower_dl1[] = LOWER_DATA "/dl1";
2289static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
2290static const char lower_fo1[] = LOWER_DATA "/fo1";
2291static const char lower_do1[] = LOWER_DATA "/do1";
2292static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
2293static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
2294
2295static const char (*lower_base_files[])[] = {
2296        &lower_fl1,
2297        &lower_fo1,
2298        NULL
2299};
2300static const char (*lower_base_directories[])[] = {
2301        &lower_dl1,
2302        &lower_do1,
2303        NULL
2304};
2305static 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"
2315static const char upper_fu1[] = UPPER_DATA "/fu1";
2316static const char upper_du1[] = UPPER_DATA "/du1";
2317static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
2318static const char upper_fo1[] = UPPER_DATA "/fo1";
2319static const char upper_do1[] = UPPER_DATA "/do1";
2320static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
2321static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
2322
2323static const char (*upper_base_files[])[] = {
2324        &upper_fu1,
2325        &upper_fo1,
2326        NULL
2327};
2328static const char (*upper_base_directories[])[] = {
2329        &upper_du1,
2330        &upper_do1,
2331        NULL
2332};
2333static 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"
2342static const char merge_fl1[] = MERGE_DATA "/fl1";
2343static const char merge_dl1[] = MERGE_DATA "/dl1";
2344static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
2345static const char merge_fu1[] = MERGE_DATA "/fu1";
2346static const char merge_du1[] = MERGE_DATA "/du1";
2347static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
2348static const char merge_fo1[] = MERGE_DATA "/fo1";
2349static const char merge_do1[] = MERGE_DATA "/do1";
2350static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
2351static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
2352static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
2353
2354static const char (*merge_base_files[])[] = {
2355        &merge_fl1,
2356        &merge_fu1,
2357        &merge_fo1,
2358        NULL
2359};
2360static const char (*merge_base_directories[])[] = {
2361        &merge_dl1,
2362        &merge_du1,
2363        &merge_do1,
2364        NULL
2365};
2366static 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
2414FIXTURE(layout2_overlay) {
2415};
2416
2417FIXTURE_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
2454FIXTURE_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
2485TEST_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
2520TEST_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
2791TEST_HARNESS_MAIN
2792