1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <setjmp.h> 6 #include <signal.h> 7 #include <stdbool.h> 8 #include <sys/prctl.h> 9 #include <sys/wait.h> 10 #include <unistd.h> 11 12 #include "../../kselftest.h" 13 14 #ifndef PR_PMLEN_SHIFT 15 #define PR_PMLEN_SHIFT 24 16 #endif 17 #ifndef PR_PMLEN_MASK 18 #define PR_PMLEN_MASK (0x7fUL << PR_PMLEN_SHIFT) 19 #endif 20 21 static int dev_zero; 22 23 static int pipefd[2]; 24 25 static sigjmp_buf jmpbuf; 26 27 static void sigsegv_handler(int sig) 28 { 29 siglongjmp(jmpbuf, 1); 30 } 31 32 static int min_pmlen; 33 static int max_pmlen; 34 35 static inline bool valid_pmlen(int pmlen) 36 { 37 return pmlen == 0 || pmlen == 7 || pmlen == 16; 38 } 39 40 static void test_pmlen(void) 41 { 42 ksft_print_msg("Testing available PMLEN values\n"); 43 44 for (int request = 0; request <= 16; request++) { 45 int pmlen, ret; 46 47 ret = prctl(PR_SET_TAGGED_ADDR_CTRL, request << PR_PMLEN_SHIFT, 0, 0, 0); 48 if (ret) 49 goto pr_set_error; 50 51 ret = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); 52 ksft_test_result(ret >= 0, "PMLEN=%d PR_GET_TAGGED_ADDR_CTRL\n", request); 53 if (ret < 0) 54 goto pr_get_error; 55 56 pmlen = (ret & PR_PMLEN_MASK) >> PR_PMLEN_SHIFT; 57 ksft_test_result(pmlen >= request, "PMLEN=%d constraint\n", request); 58 ksft_test_result(valid_pmlen(pmlen), "PMLEN=%d validity\n", request); 59 60 if (min_pmlen == 0) 61 min_pmlen = pmlen; 62 if (max_pmlen < pmlen) 63 max_pmlen = pmlen; 64 65 continue; 66 67 pr_set_error: 68 ksft_test_result_skip("PMLEN=%d PR_GET_TAGGED_ADDR_CTRL\n", request); 69 pr_get_error: 70 ksft_test_result_skip("PMLEN=%d constraint\n", request); 71 ksft_test_result_skip("PMLEN=%d validity\n", request); 72 } 73 74 if (max_pmlen == 0) 75 ksft_exit_fail_msg("Failed to enable pointer masking\n"); 76 } 77 78 static int set_tagged_addr_ctrl(int pmlen, bool tagged_addr_abi) 79 { 80 int arg, ret; 81 82 arg = pmlen << PR_PMLEN_SHIFT | tagged_addr_abi; 83 ret = prctl(PR_SET_TAGGED_ADDR_CTRL, arg, 0, 0, 0); 84 if (!ret) { 85 ret = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); 86 if (ret == arg) 87 return 0; 88 } 89 90 return ret < 0 ? -errno : -ENODATA; 91 } 92 93 static void test_dereference_pmlen(int pmlen) 94 { 95 static volatile int i; 96 volatile int *p; 97 int ret; 98 99 ret = set_tagged_addr_ctrl(pmlen, false); 100 if (ret) 101 return ksft_test_result_error("PMLEN=%d setup (%d)\n", pmlen, ret); 102 103 i = pmlen; 104 105 if (pmlen) { 106 p = (volatile int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen)); 107 108 /* These dereferences should succeed. */ 109 if (sigsetjmp(jmpbuf, 1)) 110 return ksft_test_result_fail("PMLEN=%d valid tag\n", pmlen); 111 if (*p != pmlen) 112 return ksft_test_result_fail("PMLEN=%d bad value\n", pmlen); 113 ++*p; 114 } 115 116 p = (volatile int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen - 1)); 117 118 /* These dereferences should raise SIGSEGV. */ 119 if (sigsetjmp(jmpbuf, 1)) 120 return ksft_test_result_pass("PMLEN=%d dereference\n", pmlen); 121 ++*p; 122 ksft_test_result_fail("PMLEN=%d invalid tag\n", pmlen); 123 } 124 125 static void test_dereference(void) 126 { 127 ksft_print_msg("Testing userspace pointer dereference\n"); 128 129 signal(SIGSEGV, sigsegv_handler); 130 131 test_dereference_pmlen(0); 132 test_dereference_pmlen(min_pmlen); 133 test_dereference_pmlen(max_pmlen); 134 135 signal(SIGSEGV, SIG_DFL); 136 } 137 138 static void execve_child_sigsegv_handler(int sig) 139 { 140 exit(42); 141 } 142 143 static int execve_child(void) 144 { 145 static volatile int i; 146 volatile int *p = (volatile int *)((uintptr_t)&i | 1UL << (__riscv_xlen - 7)); 147 148 signal(SIGSEGV, execve_child_sigsegv_handler); 149 150 /* This dereference should raise SIGSEGV. */ 151 return *p; 152 } 153 154 static void test_fork_exec(void) 155 { 156 int ret, status; 157 158 ksft_print_msg("Testing fork/exec behavior\n"); 159 160 ret = set_tagged_addr_ctrl(min_pmlen, false); 161 if (ret) 162 return ksft_test_result_error("setup (%d)\n", ret); 163 164 if (fork()) { 165 wait(&status); 166 ksft_test_result(WIFEXITED(status) && WEXITSTATUS(status) == 42, 167 "dereference after fork\n"); 168 } else { 169 static volatile int i = 42; 170 volatile int *p; 171 172 p = (volatile int *)((uintptr_t)&i | 1UL << (__riscv_xlen - min_pmlen)); 173 174 /* This dereference should succeed. */ 175 exit(*p); 176 } 177 178 if (fork()) { 179 wait(&status); 180 ksft_test_result(WIFEXITED(status) && WEXITSTATUS(status) == 42, 181 "dereference after fork+exec\n"); 182 } else { 183 /* Will call execve_child(). */ 184 execve("/proc/self/exe", (char *const []) { "", NULL }, NULL); 185 } 186 } 187 188 static void test_tagged_addr_abi_sysctl(void) 189 { 190 char value; 191 int fd; 192 193 ksft_print_msg("Testing tagged address ABI sysctl\n"); 194 195 fd = open("/proc/sys/abi/tagged_addr_disabled", O_WRONLY); 196 if (fd < 0) { 197 ksft_test_result_skip("failed to open sysctl file\n"); 198 ksft_test_result_skip("failed to open sysctl file\n"); 199 return; 200 } 201 202 value = '1'; 203 pwrite(fd, &value, 1, 0); 204 ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == -EINVAL, 205 "sysctl disabled\n"); 206 207 value = '0'; 208 pwrite(fd, &value, 1, 0); 209 ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == 0, 210 "sysctl enabled\n"); 211 212 set_tagged_addr_ctrl(0, false); 213 214 close(fd); 215 } 216 217 static void test_tagged_addr_abi_pmlen(int pmlen) 218 { 219 int i, *p, ret; 220 221 i = ~pmlen; 222 223 if (pmlen) { 224 p = (int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen)); 225 226 ret = set_tagged_addr_ctrl(pmlen, false); 227 if (ret) 228 return ksft_test_result_error("PMLEN=%d ABI disabled setup (%d)\n", 229 pmlen, ret); 230 231 ret = write(pipefd[1], p, sizeof(*p)); 232 if (ret >= 0 || errno != EFAULT) 233 return ksft_test_result_fail("PMLEN=%d ABI disabled write\n", pmlen); 234 235 ret = read(dev_zero, p, sizeof(*p)); 236 if (ret >= 0 || errno != EFAULT) 237 return ksft_test_result_fail("PMLEN=%d ABI disabled read\n", pmlen); 238 239 if (i != ~pmlen) 240 return ksft_test_result_fail("PMLEN=%d ABI disabled value\n", pmlen); 241 242 ret = set_tagged_addr_ctrl(pmlen, true); 243 if (ret) 244 return ksft_test_result_error("PMLEN=%d ABI enabled setup (%d)\n", 245 pmlen, ret); 246 247 ret = write(pipefd[1], p, sizeof(*p)); 248 if (ret != sizeof(*p)) 249 return ksft_test_result_fail("PMLEN=%d ABI enabled write\n", pmlen); 250 251 ret = read(dev_zero, p, sizeof(*p)); 252 if (ret != sizeof(*p)) 253 return ksft_test_result_fail("PMLEN=%d ABI enabled read\n", pmlen); 254 255 if (i) 256 return ksft_test_result_fail("PMLEN=%d ABI enabled value\n", pmlen); 257 258 i = ~pmlen; 259 } else { 260 /* The tagged address ABI cannot be enabled when PMLEN == 0. */ 261 ret = set_tagged_addr_ctrl(pmlen, true); 262 if (ret != -EINVAL) 263 return ksft_test_result_error("PMLEN=%d ABI setup (%d)\n", 264 pmlen, ret); 265 } 266 267 p = (int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen - 1)); 268 269 ret = write(pipefd[1], p, sizeof(*p)); 270 if (ret >= 0 || errno != EFAULT) 271 return ksft_test_result_fail("PMLEN=%d invalid tag write (%d)\n", pmlen, errno); 272 273 ret = read(dev_zero, p, sizeof(*p)); 274 if (ret >= 0 || errno != EFAULT) 275 return ksft_test_result_fail("PMLEN=%d invalid tag read\n", pmlen); 276 277 if (i != ~pmlen) 278 return ksft_test_result_fail("PMLEN=%d invalid tag value\n", pmlen); 279 280 ksft_test_result_pass("PMLEN=%d tagged address ABI\n", pmlen); 281 } 282 283 static void test_tagged_addr_abi(void) 284 { 285 ksft_print_msg("Testing tagged address ABI\n"); 286 287 test_tagged_addr_abi_pmlen(0); 288 test_tagged_addr_abi_pmlen(min_pmlen); 289 test_tagged_addr_abi_pmlen(max_pmlen); 290 } 291 292 static struct test_info { 293 unsigned int nr_tests; 294 void (*test_fn)(void); 295 } tests[] = { 296 { .nr_tests = 17 * 3, test_pmlen }, 297 { .nr_tests = 3, test_dereference }, 298 { .nr_tests = 2, test_fork_exec }, 299 { .nr_tests = 2, test_tagged_addr_abi_sysctl }, 300 { .nr_tests = 3, test_tagged_addr_abi }, 301 }; 302 303 int main(int argc, char **argv) 304 { 305 unsigned int plan = 0; 306 int ret; 307 308 /* Check if this is the child process after execve(). */ 309 if (!argv[0][0]) 310 return execve_child(); 311 312 dev_zero = open("/dev/zero", O_RDWR); 313 if (dev_zero < 0) 314 return 1; 315 316 /* Write to a pipe so the kernel must dereference the buffer pointer. */ 317 ret = pipe(pipefd); 318 if (ret) 319 return 1; 320 321 ksft_print_header(); 322 323 for (int i = 0; i < ARRAY_SIZE(tests); i++) 324 plan += tests[i].nr_tests; 325 326 ksft_set_plan(plan); 327 328 for (int i = 0; i < ARRAY_SIZE(tests); i++) 329 tests[i].test_fn(); 330 331 ksft_finished(); 332 } 333