xref: /illumos-gate/usr/src/test/os-tests/tests/xsave/signal_restore.c (revision 763f1f5f97e4c16840af2ced98915f0ed0f46616)
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