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