Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v6.11-rc7 303 lines 6.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2 3#ifdef __aarch64__ 4#include <asm/hwcap.h> 5#endif 6 7#include <linux/mman.h> 8#include <linux/prctl.h> 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <sys/auxv.h> 13#include <sys/prctl.h> 14#include <sys/wait.h> 15#include <unistd.h> 16 17#include "../kselftest_harness.h" 18 19#ifndef __aarch64__ 20# define PROT_BTI 0 21#endif 22 23TEST(prctl_flags) 24{ 25 EXPECT_LT(prctl(PR_SET_MDWE, PR_MDWE_NO_INHERIT, 0L, 0L, 7L), 0); 26 EXPECT_EQ(errno, EINVAL); 27 28 EXPECT_LT(prctl(PR_SET_MDWE, 7L, 0L, 0L, 0L), 0); 29 EXPECT_EQ(errno, EINVAL); 30 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 7L, 0L, 0L), 0); 31 EXPECT_EQ(errno, EINVAL); 32 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 7L, 0L), 0); 33 EXPECT_EQ(errno, EINVAL); 34 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 0L, 7L), 0); 35 EXPECT_EQ(errno, EINVAL); 36 37 EXPECT_LT(prctl(PR_GET_MDWE, 7L, 0L, 0L, 0L), 0); 38 EXPECT_EQ(errno, EINVAL); 39 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 7L, 0L, 0L), 0); 40 EXPECT_EQ(errno, EINVAL); 41 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 7L, 0L), 0); 42 EXPECT_EQ(errno, EINVAL); 43 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 0L, 7L), 0); 44 EXPECT_EQ(errno, EINVAL); 45} 46 47FIXTURE(consecutive_prctl_flags) {}; 48FIXTURE_SETUP(consecutive_prctl_flags) {} 49FIXTURE_TEARDOWN(consecutive_prctl_flags) {} 50 51FIXTURE_VARIANT(consecutive_prctl_flags) 52{ 53 unsigned long first_flags; 54 unsigned long second_flags; 55 bool should_work; 56}; 57 58FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_no_flags) 59{ 60 .first_flags = 0, 61 .second_flags = 0, 62 .should_work = true, 63}; 64 65FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_exec_gain) 66{ 67 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN, 68 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN, 69 .should_work = true, 70}; 71 72FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_both_flags) 73{ 74 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 75 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 76 .should_work = true, 77}; 78 79FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe) 80{ 81 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN, 82 .second_flags = 0, 83 .should_work = false, 84}; 85 86FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe_no_inherit) 87{ 88 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 89 .second_flags = 0, 90 .should_work = false, 91}; 92 93FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_no_inherit) 94{ 95 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 96 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN, 97 .should_work = false, 98}; 99 100FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_enable_no_inherit) 101{ 102 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN, 103 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 104 .should_work = false, 105}; 106 107TEST_F(consecutive_prctl_flags, two_prctls) 108{ 109 int ret; 110 111 EXPECT_EQ(prctl(PR_SET_MDWE, variant->first_flags, 0L, 0L, 0L), 0); 112 113 ret = prctl(PR_SET_MDWE, variant->second_flags, 0L, 0L, 0L); 114 if (variant->should_work) { 115 EXPECT_EQ(ret, 0); 116 117 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L); 118 ASSERT_EQ(ret, variant->second_flags); 119 } else { 120 EXPECT_NE(ret, 0); 121 ASSERT_EQ(errno, EPERM); 122 } 123} 124 125FIXTURE(mdwe) 126{ 127 void *p; 128 int flags; 129 size_t size; 130 pid_t pid; 131}; 132 133FIXTURE_VARIANT(mdwe) 134{ 135 bool enabled; 136 bool forked; 137 bool inherit; 138}; 139 140FIXTURE_VARIANT_ADD(mdwe, stock) 141{ 142 .enabled = false, 143 .forked = false, 144 .inherit = false, 145}; 146 147FIXTURE_VARIANT_ADD(mdwe, enabled) 148{ 149 .enabled = true, 150 .forked = false, 151 .inherit = true, 152}; 153 154FIXTURE_VARIANT_ADD(mdwe, inherited) 155{ 156 .enabled = true, 157 .forked = true, 158 .inherit = true, 159}; 160 161FIXTURE_VARIANT_ADD(mdwe, not_inherited) 162{ 163 .enabled = true, 164 .forked = true, 165 .inherit = false, 166}; 167 168static bool executable_map_should_fail(const FIXTURE_VARIANT(mdwe) *variant) 169{ 170 return variant->enabled && (!variant->forked || variant->inherit); 171} 172 173FIXTURE_SETUP(mdwe) 174{ 175 unsigned long mdwe_flags; 176 int ret, status; 177 178 self->p = NULL; 179 self->flags = MAP_SHARED | MAP_ANONYMOUS; 180 self->size = getpagesize(); 181 182 if (!variant->enabled) 183 return; 184 185 mdwe_flags = PR_MDWE_REFUSE_EXEC_GAIN; 186 if (!variant->inherit) 187 mdwe_flags |= PR_MDWE_NO_INHERIT; 188 189 ret = prctl(PR_SET_MDWE, mdwe_flags, 0L, 0L, 0L); 190 ASSERT_EQ(ret, 0) { 191 TH_LOG("PR_SET_MDWE failed or unsupported"); 192 } 193 194 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L); 195 ASSERT_EQ(ret, mdwe_flags); 196 197 if (variant->forked) { 198 self->pid = fork(); 199 ASSERT_GE(self->pid, 0) { 200 TH_LOG("fork failed\n"); 201 } 202 203 if (self->pid > 0) { 204 ret = waitpid(self->pid, &status, 0); 205 ASSERT_TRUE(WIFEXITED(status)); 206 exit(WEXITSTATUS(status)); 207 } 208 } 209} 210 211FIXTURE_TEARDOWN(mdwe) 212{ 213 if (self->p && self->p != MAP_FAILED) 214 munmap(self->p, self->size); 215} 216 217TEST_F(mdwe, mmap_READ_EXEC) 218{ 219 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0); 220 EXPECT_NE(self->p, MAP_FAILED); 221} 222 223TEST_F(mdwe, mmap_WRITE_EXEC) 224{ 225 self->p = mmap(NULL, self->size, PROT_WRITE | PROT_EXEC, self->flags, 0, 0); 226 if (executable_map_should_fail(variant)) { 227 EXPECT_EQ(self->p, MAP_FAILED); 228 } else { 229 EXPECT_NE(self->p, MAP_FAILED); 230 } 231} 232 233TEST_F(mdwe, mprotect_stay_EXEC) 234{ 235 int ret; 236 237 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0); 238 ASSERT_NE(self->p, MAP_FAILED); 239 240 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC); 241 EXPECT_EQ(ret, 0); 242} 243 244TEST_F(mdwe, mprotect_add_EXEC) 245{ 246 int ret; 247 248 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0); 249 ASSERT_NE(self->p, MAP_FAILED); 250 251 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC); 252 if (executable_map_should_fail(variant)) { 253 EXPECT_LT(ret, 0); 254 } else { 255 EXPECT_EQ(ret, 0); 256 } 257} 258 259TEST_F(mdwe, mprotect_WRITE_EXEC) 260{ 261 int ret; 262 263 self->p = mmap(NULL, self->size, PROT_WRITE, self->flags, 0, 0); 264 ASSERT_NE(self->p, MAP_FAILED); 265 266 ret = mprotect(self->p, self->size, PROT_WRITE | PROT_EXEC); 267 if (executable_map_should_fail(variant)) { 268 EXPECT_LT(ret, 0); 269 } else { 270 EXPECT_EQ(ret, 0); 271 } 272} 273 274TEST_F(mdwe, mmap_FIXED) 275{ 276 void *p; 277 278 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0); 279 ASSERT_NE(self->p, MAP_FAILED); 280 281 /* MAP_FIXED unmaps the existing page before mapping which is allowed */ 282 p = mmap(self->p, self->size, PROT_READ | PROT_EXEC, 283 self->flags | MAP_FIXED, 0, 0); 284 EXPECT_EQ(p, self->p); 285} 286 287TEST_F(mdwe, arm64_BTI) 288{ 289 int ret; 290 291#ifdef __aarch64__ 292 if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI)) 293#endif 294 SKIP(return, "HWCAP2_BTI not supported"); 295 296 self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0); 297 ASSERT_NE(self->p, MAP_FAILED); 298 299 ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI); 300 EXPECT_EQ(ret, 0); 301} 302 303TEST_HARNESS_MAIN