304 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#ifdef __aarch64__4#include <asm/hwcap.h>5#endif6 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 021#endif22 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#endif294 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_MAIN304