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 23 TEST(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 36 FIXTURE(mdwe) 37 { 38 void *p; 39 int flags; 40 size_t size; 41 pid_t pid; 42 }; 43 44 FIXTURE_VARIANT(mdwe) 45 { 46 bool enabled; 47 bool forked; 48 }; 49 50 FIXTURE_VARIANT_ADD(mdwe, stock) 51 { 52 .enabled = false, 53 .forked = false, 54 }; 55 56 FIXTURE_VARIANT_ADD(mdwe, enabled) 57 { 58 .enabled = true, 59 .forked = false, 60 }; 61 62 FIXTURE_VARIANT_ADD(mdwe, forked) 63 { 64 .enabled = true, 65 .forked = true, 66 }; 67 68 FIXTURE_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 101 FIXTURE_TEARDOWN(mdwe) 102 { 103 if (self->p && self->p != MAP_FAILED) 104 munmap(self->p, self->size); 105 } 106 107 TEST_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 113 TEST_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 123 TEST_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 134 TEST_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 149 TEST_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 164 TEST_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 177 TEST_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 193 TEST_HARNESS_MAIN 194