1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <err.h> 5 #include <errno.h> 6 #include <setjmp.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <stdbool.h> 10 #include <unistd.h> 11 #include <x86intrin.h> 12 13 #include <sys/auxv.h> 14 #include <sys/mman.h> 15 #include <sys/shm.h> 16 #include <sys/syscall.h> 17 #include <sys/wait.h> 18 19 #include "helpers.h" 20 #include "xstate.h" 21 22 #ifndef __x86_64__ 23 # error This test is 64-bit only 24 #endif 25 26 /* err() exits and will not return */ 27 #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) 28 29 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) 30 #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) 31 #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) 32 33 struct xstate_info xtiledata; 34 35 /* The helpers for managing XSAVE buffer and tile states: */ 36 37 struct xsave_buffer *stashed_xsave; 38 39 static void init_stashed_xsave(void) 40 { 41 stashed_xsave = alloc_xbuf(); 42 if (!stashed_xsave) 43 fatal_error("failed to allocate stashed_xsave\n"); 44 clear_xstate_header(stashed_xsave); 45 } 46 47 static void free_stashed_xsave(void) 48 { 49 free(stashed_xsave); 50 } 51 52 /* Work around printf() being unsafe in signals: */ 53 #define SIGNAL_BUF_LEN 1000 54 char signal_message_buffer[SIGNAL_BUF_LEN]; 55 void sig_print(char *msg) 56 { 57 int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1; 58 59 strncat(signal_message_buffer, msg, left); 60 } 61 62 static volatile bool noperm_signaled; 63 static int noperm_errs; 64 /* 65 * Signal handler for when AMX is used but 66 * permission has not been obtained. 67 */ 68 static void handle_noperm(int sig, siginfo_t *si, void *ctx_void) 69 { 70 ucontext_t *ctx = (ucontext_t *)ctx_void; 71 void *xbuf = ctx->uc_mcontext.fpregs; 72 struct _fpx_sw_bytes *sw_bytes; 73 uint64_t features; 74 75 /* Reset the signal message buffer: */ 76 signal_message_buffer[0] = '\0'; 77 sig_print("\tAt SIGILL handler,\n"); 78 79 if (si->si_code != ILL_ILLOPC) { 80 noperm_errs++; 81 sig_print("[FAIL]\tInvalid signal code.\n"); 82 } else { 83 sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n"); 84 } 85 86 sw_bytes = get_fpx_sw_bytes(xbuf); 87 /* 88 * Without permission, the signal XSAVE buffer should not 89 * have room for AMX register state (aka. xtiledata). 90 * Check that the size does not overlap with where xtiledata 91 * will reside. 92 * 93 * This also implies that no state components *PAST* 94 * XTILEDATA (features >=19) can be present in the buffer. 95 */ 96 if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) { 97 sig_print("[OK]\tValid xstate size\n"); 98 } else { 99 noperm_errs++; 100 sig_print("[FAIL]\tInvalid xstate size\n"); 101 } 102 103 features = get_fpx_sw_bytes_features(xbuf); 104 /* 105 * Without permission, the XTILEDATA feature 106 * bit should not be set. 107 */ 108 if ((features & XFEATURE_MASK_XTILEDATA) == 0) { 109 sig_print("[OK]\tValid xstate mask\n"); 110 } else { 111 noperm_errs++; 112 sig_print("[FAIL]\tInvalid xstate mask\n"); 113 } 114 115 noperm_signaled = true; 116 ctx->uc_mcontext.gregs[REG_RIP] += 3; /* Skip the faulting XRSTOR */ 117 } 118 119 /* Return true if XRSTOR is successful; otherwise, false. */ 120 static inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask) 121 { 122 noperm_signaled = false; 123 xrstor(xbuf, mask); 124 125 /* Print any messages produced by the signal code: */ 126 printf("%s", signal_message_buffer); 127 /* 128 * Reset the buffer to make sure any future printing 129 * only outputs new messages: 130 */ 131 signal_message_buffer[0] = '\0'; 132 133 if (noperm_errs) 134 fatal_error("saw %d errors in noperm signal handler\n", noperm_errs); 135 136 return !noperm_signaled; 137 } 138 139 /* 140 * Use XRSTOR to populate the XTILEDATA registers with 141 * random data. 142 * 143 * Return true if successful; otherwise, false. 144 */ 145 static inline bool load_rand_tiledata(struct xsave_buffer *xbuf) 146 { 147 clear_xstate_header(xbuf); 148 set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA); 149 set_rand_data(&xtiledata, xbuf); 150 return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA); 151 } 152 153 enum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED }; 154 155 /* arch_prctl() and sigaltstack() test */ 156 157 #define ARCH_GET_XCOMP_SUPP 0x1021 158 #define ARCH_GET_XCOMP_PERM 0x1022 159 #define ARCH_REQ_XCOMP_PERM 0x1023 160 161 static void req_xtiledata_perm(void) 162 { 163 syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 164 } 165 166 static void validate_req_xcomp_perm(enum expected_result exp) 167 { 168 unsigned long bitmask, expected_bitmask; 169 long rc; 170 171 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 172 if (rc) { 173 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 174 } else if (!(bitmask & XFEATURE_MASK_XTILECFG)) { 175 fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off."); 176 } 177 178 rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 179 if (exp == FAIL_EXPECTED) { 180 if (rc) { 181 printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n"); 182 return; 183 } 184 185 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n"); 186 } else if (rc) { 187 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n"); 188 } 189 190 expected_bitmask = bitmask | XFEATURE_MASK_XTILEDATA; 191 192 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 193 if (rc) { 194 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 195 } else if (bitmask != expected_bitmask) { 196 fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n", 197 bitmask, expected_bitmask); 198 } else { 199 printf("\tARCH_REQ_XCOMP_PERM is successful.\n"); 200 } 201 } 202 203 static void validate_xcomp_perm(enum expected_result exp) 204 { 205 bool load_success = load_rand_tiledata(stashed_xsave); 206 207 if (exp == FAIL_EXPECTED) { 208 if (load_success) { 209 noperm_errs++; 210 printf("[FAIL]\tLoad tiledata succeeded.\n"); 211 } else { 212 printf("[OK]\tLoad tiledata failed.\n"); 213 } 214 } else if (exp == SUCCESS_EXPECTED) { 215 if (load_success) { 216 printf("[OK]\tLoad tiledata succeeded.\n"); 217 } else { 218 noperm_errs++; 219 printf("[FAIL]\tLoad tiledata failed.\n"); 220 } 221 } 222 } 223 224 #ifndef AT_MINSIGSTKSZ 225 # define AT_MINSIGSTKSZ 51 226 #endif 227 228 static void *alloc_altstack(unsigned int size) 229 { 230 void *altstack; 231 232 altstack = mmap(NULL, size, PROT_READ | PROT_WRITE, 233 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 234 235 if (altstack == MAP_FAILED) 236 fatal_error("mmap() for altstack"); 237 238 return altstack; 239 } 240 241 static void setup_altstack(void *addr, unsigned long size, enum expected_result exp) 242 { 243 stack_t ss; 244 int rc; 245 246 memset(&ss, 0, sizeof(ss)); 247 ss.ss_size = size; 248 ss.ss_sp = addr; 249 250 rc = sigaltstack(&ss, NULL); 251 252 if (exp == FAIL_EXPECTED) { 253 if (rc) { 254 printf("[OK]\tsigaltstack() failed.\n"); 255 } else { 256 fatal_error("sigaltstack() succeeded unexpectedly.\n"); 257 } 258 } else if (rc) { 259 fatal_error("sigaltstack()"); 260 } 261 } 262 263 static void test_dynamic_sigaltstack(void) 264 { 265 unsigned int small_size, enough_size; 266 unsigned long minsigstksz; 267 void *altstack; 268 269 minsigstksz = getauxval(AT_MINSIGSTKSZ); 270 printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz); 271 /* 272 * getauxval() itself can return 0 for failure or 273 * success. But, in this case, AT_MINSIGSTKSZ 274 * will always return a >=0 value if implemented. 275 * Just check for 0. 276 */ 277 if (minsigstksz == 0) { 278 printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n"); 279 return; 280 } 281 282 enough_size = minsigstksz * 2; 283 284 altstack = alloc_altstack(enough_size); 285 printf("\tAllocate memory for altstack (%u bytes).\n", enough_size); 286 287 /* 288 * Try setup_altstack() with a size which can not fit 289 * XTILEDATA. ARCH_REQ_XCOMP_PERM should fail. 290 */ 291 small_size = minsigstksz - xtiledata.size; 292 printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size); 293 setup_altstack(altstack, small_size, SUCCESS_EXPECTED); 294 validate_req_xcomp_perm(FAIL_EXPECTED); 295 296 /* 297 * Try setup_altstack() with a size derived from 298 * AT_MINSIGSTKSZ. It should be more than large enough 299 * and thus ARCH_REQ_XCOMP_PERM should succeed. 300 */ 301 printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size); 302 setup_altstack(altstack, enough_size, SUCCESS_EXPECTED); 303 validate_req_xcomp_perm(SUCCESS_EXPECTED); 304 305 /* 306 * Try to coerce setup_altstack() to again accept a 307 * too-small altstack. This ensures that big-enough 308 * sigaltstacks can not shrink to a too-small value 309 * once XTILEDATA permission is established. 310 */ 311 printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size); 312 setup_altstack(altstack, small_size, FAIL_EXPECTED); 313 } 314 315 static void test_dynamic_state(void) 316 { 317 pid_t parent, child, grandchild; 318 319 parent = fork(); 320 if (parent < 0) { 321 /* fork() failed */ 322 fatal_error("fork"); 323 } else if (parent > 0) { 324 int status; 325 /* fork() succeeded. Now in the parent. */ 326 327 wait(&status); 328 if (!WIFEXITED(status) || WEXITSTATUS(status)) 329 fatal_error("arch_prctl test parent exit"); 330 return; 331 } 332 /* fork() succeeded. Now in the child . */ 333 334 printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n"); 335 336 printf("\tFork a child.\n"); 337 child = fork(); 338 if (child < 0) { 339 fatal_error("fork"); 340 } else if (child > 0) { 341 int status; 342 343 wait(&status); 344 if (!WIFEXITED(status) || WEXITSTATUS(status)) 345 fatal_error("arch_prctl test child exit"); 346 _exit(0); 347 } 348 349 /* 350 * The permission request should fail without an 351 * XTILEDATA-compatible signal stack 352 */ 353 printf("\tTest XCOMP_PERM at child.\n"); 354 validate_xcomp_perm(FAIL_EXPECTED); 355 356 /* 357 * Set up an XTILEDATA-compatible signal stack and 358 * also obtain permission to populate XTILEDATA. 359 */ 360 printf("\tTest dynamic sigaltstack at child:\n"); 361 test_dynamic_sigaltstack(); 362 363 /* Ensure that XTILEDATA can be populated. */ 364 printf("\tTest XCOMP_PERM again at child.\n"); 365 validate_xcomp_perm(SUCCESS_EXPECTED); 366 367 printf("\tFork a grandchild.\n"); 368 grandchild = fork(); 369 if (grandchild < 0) { 370 /* fork() failed */ 371 fatal_error("fork"); 372 } else if (!grandchild) { 373 /* fork() succeeded. Now in the (grand)child. */ 374 printf("\tTest XCOMP_PERM at grandchild.\n"); 375 376 /* 377 * Ensure that the grandchild inherited 378 * permission and a compatible sigaltstack: 379 */ 380 validate_xcomp_perm(SUCCESS_EXPECTED); 381 } else { 382 int status; 383 /* fork() succeeded. Now in the parent. */ 384 385 wait(&status); 386 if (!WIFEXITED(status) || WEXITSTATUS(status)) 387 fatal_error("fork test grandchild"); 388 } 389 390 _exit(0); 391 } 392 393 static inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2) 394 { 395 return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset], 396 &xbuf2->bytes[xtiledata.xbuf_offset], 397 xtiledata.size); 398 } 399 400 /* 401 * Save current register state and compare it to @xbuf1.' 402 * 403 * Returns false if @xbuf1 matches the registers. 404 * Returns true if @xbuf1 differs from the registers. 405 */ 406 static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1) 407 { 408 struct xsave_buffer *xbuf2; 409 int ret; 410 411 xbuf2 = alloc_xbuf(); 412 if (!xbuf2) 413 fatal_error("failed to allocate XSAVE buffer\n"); 414 415 xsave(xbuf2, XFEATURE_MASK_XTILEDATA); 416 ret = __compare_tiledata_state(xbuf1, xbuf2); 417 418 free(xbuf2); 419 420 if (ret == 0) 421 return false; 422 return true; 423 } 424 425 static inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf) 426 { 427 int ret = __validate_tiledata_regs(xbuf); 428 429 if (ret == 0) 430 fatal_error("TILEDATA registers did not change"); 431 } 432 433 /* tiledata inheritance test */ 434 435 static void test_fork(void) 436 { 437 pid_t child, grandchild; 438 439 child = fork(); 440 if (child < 0) { 441 /* fork() failed */ 442 fatal_error("fork"); 443 } else if (child > 0) { 444 /* fork() succeeded. Now in the parent. */ 445 int status; 446 447 wait(&status); 448 if (!WIFEXITED(status) || WEXITSTATUS(status)) 449 fatal_error("fork test child"); 450 return; 451 } 452 /* fork() succeeded. Now in the child. */ 453 printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n"); 454 455 load_rand_tiledata(stashed_xsave); 456 457 grandchild = fork(); 458 if (grandchild < 0) { 459 /* fork() failed */ 460 fatal_error("fork"); 461 } else if (grandchild > 0) { 462 /* fork() succeeded. Still in the first child. */ 463 int status; 464 465 wait(&status); 466 if (!WIFEXITED(status) || WEXITSTATUS(status)) 467 fatal_error("fork test grand child"); 468 _exit(0); 469 } 470 /* fork() succeeded. Now in the (grand)child. */ 471 472 /* 473 * TILEDATA registers are not preserved across fork(). 474 * Ensure that their value has changed: 475 */ 476 validate_tiledata_regs_changed(stashed_xsave); 477 478 _exit(0); 479 } 480 481 int main(void) 482 { 483 unsigned long features; 484 long rc; 485 486 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); 487 if (rc || (features & XFEATURE_MASK_XTILE) != XFEATURE_MASK_XTILE) { 488 ksft_print_msg("no AMX support\n"); 489 return KSFT_SKIP; 490 } 491 492 xtiledata = get_xstate_info(XFEATURE_XTILEDATA); 493 if (!xtiledata.size || !xtiledata.xbuf_offset) { 494 fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", 495 xtiledata.size, xtiledata.xbuf_offset); 496 } 497 498 init_stashed_xsave(); 499 sethandler(SIGILL, handle_noperm, 0); 500 501 test_dynamic_state(); 502 503 /* Request permission for the following tests */ 504 req_xtiledata_perm(); 505 506 test_fork(); 507 508 /* 509 * Perform generic xstate tests for context switching, ptrace, 510 * and signal. 511 */ 512 test_xstate(XFEATURE_XTILEDATA); 513 514 clearhandler(SIGILL); 515 free_stashed_xsave(); 516 517 return 0; 518 } 519