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 bool pwrite_wrapper(int fd, void *buf, size_t count, const char *msg) 189 { 190 int ret = pwrite(fd, buf, count, 0); 191 192 if (ret != count) { 193 ksft_perror(msg); 194 return false; 195 } 196 return true; 197 } 198 199 static void test_tagged_addr_abi_sysctl(void) 200 { 201 char *err_pwrite_msg = "failed to write to /proc/sys/abi/tagged_addr_disabled\n"; 202 char value; 203 int fd; 204 205 ksft_print_msg("Testing tagged address ABI sysctl\n"); 206 207 fd = open("/proc/sys/abi/tagged_addr_disabled", O_WRONLY); 208 if (fd < 0) { 209 ksft_test_result_skip("failed to open sysctl file\n"); 210 ksft_test_result_skip("failed to open sysctl file\n"); 211 return; 212 } 213 214 value = '1'; 215 if (!pwrite_wrapper(fd, &value, 1, "write '1'")) 216 ksft_test_result_fail(err_pwrite_msg); 217 else 218 ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == -EINVAL, 219 "sysctl disabled\n"); 220 221 value = '0'; 222 if (!pwrite_wrapper(fd, &value, 1, "write '0'")) 223 ksft_test_result_fail(err_pwrite_msg); 224 else 225 ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == 0, 226 "sysctl enabled\n"); 227 228 set_tagged_addr_ctrl(0, false); 229 230 close(fd); 231 } 232 233 static void test_tagged_addr_abi_pmlen(int pmlen) 234 { 235 int i, *p, ret; 236 237 i = ~pmlen; 238 239 if (pmlen) { 240 p = (int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen)); 241 242 ret = set_tagged_addr_ctrl(pmlen, false); 243 if (ret) 244 return ksft_test_result_error("PMLEN=%d ABI disabled setup (%d)\n", 245 pmlen, ret); 246 247 ret = write(pipefd[1], p, sizeof(*p)); 248 if (ret >= 0 || errno != EFAULT) 249 return ksft_test_result_fail("PMLEN=%d ABI disabled write\n", pmlen); 250 251 ret = read(dev_zero, p, sizeof(*p)); 252 if (ret >= 0 || errno != EFAULT) 253 return ksft_test_result_fail("PMLEN=%d ABI disabled read\n", pmlen); 254 255 if (i != ~pmlen) 256 return ksft_test_result_fail("PMLEN=%d ABI disabled value\n", pmlen); 257 258 ret = set_tagged_addr_ctrl(pmlen, true); 259 if (ret) 260 return ksft_test_result_error("PMLEN=%d ABI enabled setup (%d)\n", 261 pmlen, ret); 262 263 ret = write(pipefd[1], p, sizeof(*p)); 264 if (ret != sizeof(*p)) 265 return ksft_test_result_fail("PMLEN=%d ABI enabled write\n", pmlen); 266 267 ret = read(dev_zero, p, sizeof(*p)); 268 if (ret != sizeof(*p)) 269 return ksft_test_result_fail("PMLEN=%d ABI enabled read\n", pmlen); 270 271 if (i) 272 return ksft_test_result_fail("PMLEN=%d ABI enabled value\n", pmlen); 273 274 i = ~pmlen; 275 } else { 276 /* The tagged address ABI cannot be enabled when PMLEN == 0. */ 277 ret = set_tagged_addr_ctrl(pmlen, true); 278 if (ret != -EINVAL) 279 return ksft_test_result_error("PMLEN=%d ABI setup (%d)\n", 280 pmlen, ret); 281 } 282 283 p = (int *)((uintptr_t)&i | 1UL << (__riscv_xlen - pmlen - 1)); 284 285 ret = write(pipefd[1], p, sizeof(*p)); 286 if (ret >= 0 || errno != EFAULT) 287 return ksft_test_result_fail("PMLEN=%d invalid tag write (%d)\n", pmlen, errno); 288 289 ret = read(dev_zero, p, sizeof(*p)); 290 if (ret >= 0 || errno != EFAULT) 291 return ksft_test_result_fail("PMLEN=%d invalid tag read\n", pmlen); 292 293 if (i != ~pmlen) 294 return ksft_test_result_fail("PMLEN=%d invalid tag value\n", pmlen); 295 296 ksft_test_result_pass("PMLEN=%d tagged address ABI\n", pmlen); 297 } 298 299 static void test_tagged_addr_abi(void) 300 { 301 ksft_print_msg("Testing tagged address ABI\n"); 302 303 test_tagged_addr_abi_pmlen(0); 304 test_tagged_addr_abi_pmlen(min_pmlen); 305 test_tagged_addr_abi_pmlen(max_pmlen); 306 } 307 308 static struct test_info { 309 unsigned int nr_tests; 310 void (*test_fn)(void); 311 } tests[] = { 312 { .nr_tests = 17 * 3, test_pmlen }, 313 { .nr_tests = 3, test_dereference }, 314 { .nr_tests = 2, test_fork_exec }, 315 { .nr_tests = 2, test_tagged_addr_abi_sysctl }, 316 { .nr_tests = 3, test_tagged_addr_abi }, 317 }; 318 319 int main(int argc, char **argv) 320 { 321 unsigned int plan = 0; 322 int ret; 323 324 /* Check if this is the child process after execve(). */ 325 if (!argv[0][0]) 326 return execve_child(); 327 328 dev_zero = open("/dev/zero", O_RDWR); 329 if (dev_zero < 0) 330 return 1; 331 332 /* Write to a pipe so the kernel must dereference the buffer pointer. */ 333 ret = pipe(pipefd); 334 if (ret) 335 return 1; 336 337 ksft_print_header(); 338 339 for (int i = 0; i < ARRAY_SIZE(tests); i++) 340 plan += tests[i].nr_tests; 341 342 ksft_set_plan(plan); 343 344 for (int i = 0; i < ARRAY_SIZE(tests); i++) 345 tests[i].test_fn(); 346 347 ksft_finished(); 348 } 349