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, 7L, 0L, 0L, 0L), 0); 26 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 7L, 0L, 0L), 0); 27 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 7L, 0L), 0); 28 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 0L, 7L), 0); 29 30 EXPECT_LT(prctl(PR_GET_MDWE, 7L, 0L, 0L, 0L), 0); 31 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 7L, 0L, 0L), 0); 32 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 7L, 0L), 0); 33 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 0L, 7L), 0); 34} 35 36FIXTURE(mdwe) 37{ 38 void *p; 39 int flags; 40 size_t size; 41 pid_t pid; 42}; 43 44FIXTURE_VARIANT(mdwe) 45{ 46 bool enabled; 47 bool forked; 48}; 49 50FIXTURE_VARIANT_ADD(mdwe, stock) 51{ 52 .enabled = false, 53 .forked = false, 54}; 55 56FIXTURE_VARIANT_ADD(mdwe, enabled) 57{ 58 .enabled = true, 59 .forked = false, 60}; 61 62FIXTURE_VARIANT_ADD(mdwe, forked) 63{ 64 .enabled = true, 65 .forked = true, 66}; 67 68FIXTURE_SETUP(mdwe) 69{ 70 int ret, status; 71 72 self->p = NULL; 73 self->flags = MAP_SHARED | MAP_ANONYMOUS; 74 self->size = getpagesize(); 75 76 if (!variant->enabled) 77 return; 78 79 ret = prctl(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0L, 0L, 0L); 80 ASSERT_EQ(ret, 0) { 81 TH_LOG("PR_SET_MDWE failed or unsupported"); 82 } 83 84 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L); 85 ASSERT_EQ(ret, 1); 86 87 if (variant->forked) { 88 self->pid = fork(); 89 ASSERT_GE(self->pid, 0) { 90 TH_LOG("fork failed\n"); 91 } 92 93 if (self->pid > 0) { 94 ret = waitpid(self->pid, &status, 0); 95 ASSERT_TRUE(WIFEXITED(status)); 96 exit(WEXITSTATUS(status)); 97 } 98 } 99} 100 101FIXTURE_TEARDOWN(mdwe) 102{ 103 if (self->p && self->p != MAP_FAILED) 104 munmap(self->p, self->size); 105} 106 107TEST_F(mdwe, mmap_READ_EXEC) 108{ 109 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0); 110 EXPECT_NE(self->p, MAP_FAILED); 111} 112 113TEST_F(mdwe, mmap_WRITE_EXEC) 114{ 115 self->p = mmap(NULL, self->size, PROT_WRITE | PROT_EXEC, self->flags, 0, 0); 116 if (variant->enabled) { 117 EXPECT_EQ(self->p, MAP_FAILED); 118 } else { 119 EXPECT_NE(self->p, MAP_FAILED); 120 } 121} 122 123TEST_F(mdwe, mprotect_stay_EXEC) 124{ 125 int ret; 126 127 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0); 128 ASSERT_NE(self->p, MAP_FAILED); 129 130 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC); 131 EXPECT_EQ(ret, 0); 132} 133 134TEST_F(mdwe, mprotect_add_EXEC) 135{ 136 int ret; 137 138 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0); 139 ASSERT_NE(self->p, MAP_FAILED); 140 141 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC); 142 if (variant->enabled) { 143 EXPECT_LT(ret, 0); 144 } else { 145 EXPECT_EQ(ret, 0); 146 } 147} 148 149TEST_F(mdwe, mprotect_WRITE_EXEC) 150{ 151 int ret; 152 153 self->p = mmap(NULL, self->size, PROT_WRITE, self->flags, 0, 0); 154 ASSERT_NE(self->p, MAP_FAILED); 155 156 ret = mprotect(self->p, self->size, PROT_WRITE | PROT_EXEC); 157 if (variant->enabled) { 158 EXPECT_LT(ret, 0); 159 } else { 160 EXPECT_EQ(ret, 0); 161 } 162} 163 164TEST_F(mdwe, mmap_FIXED) 165{ 166 void *p; 167 168 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0); 169 ASSERT_NE(self->p, MAP_FAILED); 170 171 /* MAP_FIXED unmaps the existing page before mapping which is allowed */ 172 p = mmap(self->p, self->size, PROT_READ | PROT_EXEC, 173 self->flags | MAP_FIXED, 0, 0); 174 EXPECT_EQ(p, self->p); 175} 176 177TEST_F(mdwe, arm64_BTI) 178{ 179 int ret; 180 181#ifdef __aarch64__ 182 if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI)) 183#endif 184 SKIP(return, "HWCAP2_BTI not supported"); 185 186 self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0); 187 ASSERT_NE(self->p, MAP_FAILED); 188 189 ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI); 190 EXPECT_EQ(ret, 0); 191} 192 193TEST_HARNESS_MAIN 194