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