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 80 static 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 89 static 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 99 static 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 106 static 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__)) 140 static void disable_caps(struct __test_metadata *const _metadata) 141 { 142 _init_caps(_metadata, false); 143 } 144 145 __attribute__((__unused__)) 146 static void drop_caps(struct __test_metadata *const _metadata) 147 { 148 _init_caps(_metadata, true); 149 } 150 151 static 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__)) 172 static 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__)) 179 static void clear_cap(struct __test_metadata *const _metadata, 180 const cap_value_t caps) 181 { 182 _effective_cap(_metadata, caps, CAP_CLEAR); 183 } 184