linux/tools/testing/selftests/landlock/common.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Landlock test helpers
   4 *
   5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
   6 * Copyright © 2019-2020 ANSSI
   7 * Copyright © 2021 Microsoft Corporation
   8 */
   9
  10#include <errno.h>
  11#include <linux/landlock.h>
  12#include <sys/capability.h>
  13#include <sys/syscall.h>
  14#include <sys/types.h>
  15#include <sys/wait.h>
  16#include <unistd.h>
  17
  18#include "../kselftest_harness.h"
  19
  20#ifndef ARRAY_SIZE
  21#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  22#endif
  23
  24/*
  25 * TEST_F_FORK() is useful when a test drop privileges but the corresponding
  26 * FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory
  27 * where write actions are denied).  For convenience, FIXTURE_TEARDOWN() is
  28 * also called when the test failed, but not when FIXTURE_SETUP() failed.  For
  29 * this to be possible, we must not call abort() but instead exit smoothly
  30 * (hence the step print).
  31 */
  32#define TEST_F_FORK(fixture_name, test_name) \
  33        static void fixture_name##_##test_name##_child( \
  34                struct __test_metadata *_metadata, \
  35                FIXTURE_DATA(fixture_name) *self, \
  36                const FIXTURE_VARIANT(fixture_name) *variant); \
  37        TEST_F(fixture_name, test_name) \
  38        { \
  39                int status; \
  40                const pid_t child = fork(); \
  41                if (child < 0) \
  42                        abort(); \
  43                if (child == 0) { \
  44                        _metadata->no_print = 1; \
  45                        fixture_name##_##test_name##_child(_metadata, self, variant); \
  46                        if (_metadata->skip) \
  47                                _exit(255); \
  48                        if (_metadata->passed) \
  49                                _exit(0); \
  50                        _exit(_metadata->step); \
  51                } \
  52                if (child != waitpid(child, &status, 0)) \
  53                        abort(); \
  54                if (WIFSIGNALED(status) || !WIFEXITED(status)) { \
  55                        _metadata->passed = 0; \
  56                        _metadata->step = 1; \
  57                        return; \
  58                } \
  59                switch (WEXITSTATUS(status)) { \
  60                case 0: \
  61                        _metadata->passed = 1; \
  62                        break; \
  63                case 255: \
  64                        _metadata->passed = 1; \
  65                        _metadata->skip = 1; \
  66                        break; \
  67                default: \
  68                        _metadata->passed = 0; \
  69                        _metadata->step = WEXITSTATUS(status); \
  70                        break; \
  71                } \
  72        } \
  73        static void fixture_name##_##test_name##_child( \
  74                struct __test_metadata __attribute__((unused)) *_metadata, \
  75                FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \
  76                const FIXTURE_VARIANT(fixture_name) \
  77                        __attribute__((unused)) *variant)
  78
  79#ifndef landlock_create_ruleset
  80static inline int landlock_create_ruleset(
  81                const struct landlock_ruleset_attr *const attr,
  82                const size_t size, const __u32 flags)
  83{
  84        return syscall(__NR_landlock_create_ruleset, attr, size, flags);
  85}
  86#endif
  87
  88#ifndef landlock_add_rule
  89static inline int landlock_add_rule(const int ruleset_fd,
  90                const enum landlock_rule_type rule_type,
  91                const void *const rule_attr, const __u32 flags)
  92{
  93        return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type,
  94                        rule_attr, flags);
  95}
  96#endif
  97
  98#ifndef landlock_restrict_self
  99static inline int landlock_restrict_self(const int ruleset_fd,
 100                const __u32 flags)
 101{
 102        return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
 103}
 104#endif
 105
 106static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
 107{
 108        cap_t cap_p;
 109        /* Only these three capabilities are useful for the tests. */
 110        const cap_value_t caps[] = {
 111                CAP_DAC_OVERRIDE,
 112                CAP_MKNOD,
 113                CAP_SYS_ADMIN,
 114                CAP_SYS_CHROOT,
 115        };
 116
 117        cap_p = cap_get_proc();
 118        EXPECT_NE(NULL, cap_p) {
 119                TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
 120        }
 121        EXPECT_NE(-1, cap_clear(cap_p)) {
 122                TH_LOG("Failed to cap_clear: %s", strerror(errno));
 123        }
 124        if (!drop_all) {
 125                EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED,
 126                                        ARRAY_SIZE(caps), caps, CAP_SET)) {
 127                        TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
 128                }
 129        }
 130        EXPECT_NE(-1, cap_set_proc(cap_p)) {
 131                TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
 132        }
 133        EXPECT_NE(-1, cap_free(cap_p)) {
 134                TH_LOG("Failed to cap_free: %s", strerror(errno));
 135        }
 136}
 137
 138/* We cannot put such helpers in a library because of kselftest_harness.h . */
 139__attribute__((__unused__))
 140static void disable_caps(struct __test_metadata *const _metadata)
 141{
 142        _init_caps(_metadata, false);
 143}
 144
 145__attribute__((__unused__))
 146static void drop_caps(struct __test_metadata *const _metadata)
 147{
 148        _init_caps(_metadata, true);
 149}
 150
 151static void _effective_cap(struct __test_metadata *const _metadata,
 152                const cap_value_t caps, const cap_flag_value_t value)
 153{
 154        cap_t cap_p;
 155
 156        cap_p = cap_get_proc();
 157        EXPECT_NE(NULL, cap_p) {
 158                TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
 159        }
 160        EXPECT_NE(-1, cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &caps, value)) {
 161                TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
 162        }
 163        EXPECT_NE(-1, cap_set_proc(cap_p)) {
 164                TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
 165        }
 166        EXPECT_NE(-1, cap_free(cap_p)) {
 167                TH_LOG("Failed to cap_free: %s", strerror(errno));
 168        }
 169}
 170
 171__attribute__((__unused__))
 172static void set_cap(struct __test_metadata *const _metadata,
 173                const cap_value_t caps)
 174{
 175        _effective_cap(_metadata, caps, CAP_SET);
 176}
 177
 178__attribute__((__unused__))
 179static void clear_cap(struct __test_metadata *const _metadata,
 180                const cap_value_t caps)
 181{
 182        _effective_cap(_metadata, caps, CAP_CLEAR);
 183}
 184