1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2023 Oxide Comptuer Company 14 */ 15 16 /* 17 * Verify that the FPU contents are correctly restored after taking a signal. We 18 * do this by going through and setting up a signal handler for SIGINFO and then 19 * we do the following as tightly as possible: overwriting the FPU contents and 20 * then calling thr_kill(). As part of the regression for #15254, we also 21 * purposefully go off CPU in the signal handler to try to wreak havoc. 22 */ 23 24 #include <err.h> 25 #include <stdlib.h> 26 #include <ucontext.h> 27 #include <limits.h> 28 #include <signal.h> 29 #include <thread.h> 30 #include <string.h> 31 #include <time.h> 32 #include <unistd.h> 33 34 #include "xsave_util.h" 35 36 static xsu_fpu_t init_vals, signal_vals, found; 37 static volatile int exit_status = EXIT_SUCCESS; 38 static volatile int took_sig = 0; 39 static uint32_t sr_hwsup; 40 41 static void 42 signal_restore_siginfo(int sig, siginfo_t *sip, void *ucp) 43 { 44 struct timespec ts; 45 took_sig = 1; 46 47 ts.tv_sec = 0; 48 ts.tv_nsec = 10 * MILLISEC; 49 50 /* 51 * yield doesn't guarantee that we go off CPU, but try a few anyways. 52 * There's a slight chance that nanosleep will modify the FPU state, but 53 * we can hope we're lucky and that the libc function won't. 54 */ 55 xsu_setfpu(&signal_vals, sr_hwsup); 56 yield(); 57 yield(); 58 (void) nanosleep(&ts, NULL); 59 xsu_getfpu(&found, sr_hwsup); 60 61 if (xsu_same(&signal_vals, &found, sr_hwsup)) { 62 (void) printf("TEST PASSED: FPU contents didn't change in " 63 "signal handler\n"); 64 } else { 65 warnx("TEST FAILED: FPU contents changed in signal handler!"); 66 exit_status = EXIT_FAILURE; 67 } 68 69 } 70 71 int 72 main(void) 73 { 74 int ret; 75 thread_t self = thr_self(); 76 uint32_t start = arc4random(); 77 uint32_t hwsup = xsu_hwsupport(); 78 struct sigaction sa; 79 80 sr_hwsup = hwsup; 81 sa.sa_sigaction = signal_restore_siginfo; 82 sa.sa_flags = SA_RESETHAND; 83 84 if (sigaction(SIGINFO, &sa, NULL) != 0) { 85 errx(EXIT_FAILURE, "TEST FAILED: failed to set up signal " 86 "handler"); 87 } 88 89 (void) printf("filling starting at 0x%x\n", start); 90 xsu_fill(&init_vals, hwsup, start); 91 xsu_fill(&signal_vals, hwsup, start + INT_MAX); 92 93 (void) memset(&sa, 0, sizeof (struct sigaction)); 94 95 xsu_setfpu(&init_vals, hwsup); 96 ret = thr_kill(self, SIGINFO); 97 xsu_getfpu(&found, hwsup); 98 99 if (ret != 0) { 100 errc(EXIT_FAILURE, ret, "TEST FAILED: failed to deliver " 101 "signal"); 102 } 103 104 if (took_sig == 0) { 105 errx(EXIT_FAILURE, "TEST FAILED: signal handler did not run"); 106 } 107 108 (void) printf("TEST PASSED: SIGINFO successfully delivered\n"); 109 110 if (xsu_same(&init_vals, &found, hwsup)) { 111 (void) printf("TEST PASSED: FPU contents successfully " 112 "restored\n"); 113 } else { 114 warnx("TEST FAILED: FPU contents were not restored!"); 115 exit_status = EXIT_FAILURE; 116 } 117 118 return (exit_status); 119 } 120