xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/x86/vdso_restorer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * vdso_restorer.c - tests vDSO-based signal restore
4*4882a593Smuzhiyun  * Copyright (c) 2015 Andrew Lutomirski
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This makes sure that sa_restorer == NULL keeps working on 32-bit
7*4882a593Smuzhiyun  * configurations.  Modern glibc doesn't use it under any circumstances,
8*4882a593Smuzhiyun  * so it's easy to overlook breakage.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * 64-bit userspace has never supported sa_restorer == NULL, so this is
11*4882a593Smuzhiyun  * 32-bit only.
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define _GNU_SOURCE
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <err.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <dlfcn.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <signal.h>
21*4882a593Smuzhiyun #include <unistd.h>
22*4882a593Smuzhiyun #include <syscall.h>
23*4882a593Smuzhiyun #include <sys/syscall.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Open-code this -- the headers are too messy to easily use them. */
26*4882a593Smuzhiyun struct real_sigaction {
27*4882a593Smuzhiyun 	void *handler;
28*4882a593Smuzhiyun 	unsigned long flags;
29*4882a593Smuzhiyun 	void *restorer;
30*4882a593Smuzhiyun 	unsigned int mask[2];
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun static volatile sig_atomic_t handler_called;
34*4882a593Smuzhiyun 
handler_with_siginfo(int sig,siginfo_t * info,void * ctx_void)35*4882a593Smuzhiyun static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	handler_called = 1;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
handler_without_siginfo(int sig)40*4882a593Smuzhiyun static void handler_without_siginfo(int sig)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	handler_called = 1;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
main()45*4882a593Smuzhiyun int main()
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	int nerrs = 0;
48*4882a593Smuzhiyun 	struct real_sigaction sa;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	void *vdso = dlopen("linux-vdso.so.1",
51*4882a593Smuzhiyun 			    RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
52*4882a593Smuzhiyun 	if (!vdso)
53*4882a593Smuzhiyun 		vdso = dlopen("linux-gate.so.1",
54*4882a593Smuzhiyun 			      RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
55*4882a593Smuzhiyun 	if (!vdso) {
56*4882a593Smuzhiyun 		printf("[SKIP]\tFailed to find vDSO.  Tests are not expected to work.\n");
57*4882a593Smuzhiyun 		return 0;
58*4882a593Smuzhiyun 	}
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	memset(&sa, 0, sizeof(sa));
61*4882a593Smuzhiyun 	sa.handler = handler_with_siginfo;
62*4882a593Smuzhiyun 	sa.flags = SA_SIGINFO;
63*4882a593Smuzhiyun 	sa.restorer = NULL;	/* request kernel-provided restorer */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	printf("[RUN]\tRaise a signal, SA_SIGINFO, sa.restorer == NULL\n");
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0)
68*4882a593Smuzhiyun 		err(1, "raw rt_sigaction syscall");
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	raise(SIGUSR1);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	if (handler_called) {
73*4882a593Smuzhiyun 		printf("[OK]\tSA_SIGINFO handler returned successfully\n");
74*4882a593Smuzhiyun 	} else {
75*4882a593Smuzhiyun 		printf("[FAIL]\tSA_SIGINFO handler was not called\n");
76*4882a593Smuzhiyun 		nerrs++;
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	printf("[RUN]\tRaise a signal, !SA_SIGINFO, sa.restorer == NULL\n");
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	sa.flags = 0;
82*4882a593Smuzhiyun 	sa.handler = handler_without_siginfo;
83*4882a593Smuzhiyun 	if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0)
84*4882a593Smuzhiyun 		err(1, "raw sigaction syscall");
85*4882a593Smuzhiyun 	handler_called = 0;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	raise(SIGUSR1);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (handler_called) {
90*4882a593Smuzhiyun 		printf("[OK]\t!SA_SIGINFO handler returned successfully\n");
91*4882a593Smuzhiyun 	} else {
92*4882a593Smuzhiyun 		printf("[FAIL]\t!SA_SIGINFO handler was not called\n");
93*4882a593Smuzhiyun 		nerrs++;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun }
96