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