diff options
author | Andy Lutomirski <luto@kernel.org> | 2016-01-12 14:56:15 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-13 04:34:40 -0500 |
commit | 65cacec1ba908a153cfb19c4de596a108f95970c (patch) | |
tree | d14443d39d595e39158ab97cbacca7b9fd736485 /tools | |
parent | 2f0c0b2d96b1205efb14347009748d786c2d9ba5 (diff) |
selftests/x86: Test __kernel_sigreturn and __kernel_rt_sigreturn
The vdso-based sigreturn mechanism is fragile and isn't used by
modern glibc so, if we break it, we'll only notice when someone
tests an unusual libc.
Add an explicit selftest.
[ I wrote this while debugging a Bionic breakage -- my first guess
was that I had somehow messed up sigreturn. I've caused problems in
that code before, and it's really easy to fail to notice it because
there's nothing on a modern distro that needs vdso-based sigreturn. ]
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/32946d714156879cd8e5d8eab044cd07557ed558.1452628504.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/selftests/x86/Makefile | 3 | ||||
-rw-r--r-- | tools/testing/selftests/x86/vdso_restorer.c | 88 |
2 files changed, 90 insertions, 1 deletions
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 398bb0e6e38c..d0c473f65850 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -7,7 +7,8 @@ include ../lib.mk | |||
7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall | 7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall |
8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ | 8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ |
9 | test_FCMOV test_FCOMI test_FISTTP \ | 9 | test_FCMOV test_FCOMI test_FISTTP \ |
10 | ldt_gdt | 10 | ldt_gdt \ |
11 | vdso_restorer | ||
11 | 12 | ||
12 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) | 13 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) |
13 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) | 14 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) |
diff --git a/tools/testing/selftests/x86/vdso_restorer.c b/tools/testing/selftests/x86/vdso_restorer.c new file mode 100644 index 000000000000..cb038424a403 --- /dev/null +++ b/tools/testing/selftests/x86/vdso_restorer.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * vdso_restorer.c - tests vDSO-based signal restore | ||
3 | * Copyright (c) 2015 Andrew Lutomirski | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * This makes sure that sa_restorer == NULL keeps working on 32-bit | ||
15 | * configurations. Modern glibc doesn't use it under any circumstances, | ||
16 | * so it's easy to overlook breakage. | ||
17 | * | ||
18 | * 64-bit userspace has never supported sa_restorer == NULL, so this is | ||
19 | * 32-bit only. | ||
20 | */ | ||
21 | |||
22 | #define _GNU_SOURCE | ||
23 | |||
24 | #include <err.h> | ||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | #include <signal.h> | ||
28 | #include <unistd.h> | ||
29 | #include <syscall.h> | ||
30 | #include <sys/syscall.h> | ||
31 | |||
32 | /* Open-code this -- the headers are too messy to easily use them. */ | ||
33 | struct real_sigaction { | ||
34 | void *handler; | ||
35 | unsigned long flags; | ||
36 | void *restorer; | ||
37 | unsigned int mask[2]; | ||
38 | }; | ||
39 | |||
40 | static volatile sig_atomic_t handler_called; | ||
41 | |||
42 | static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void) | ||
43 | { | ||
44 | handler_called = 1; | ||
45 | } | ||
46 | |||
47 | static void handler_without_siginfo(int sig) | ||
48 | { | ||
49 | handler_called = 1; | ||
50 | } | ||
51 | |||
52 | int main() | ||
53 | { | ||
54 | int nerrs = 0; | ||
55 | struct real_sigaction sa; | ||
56 | |||
57 | memset(&sa, 0, sizeof(sa)); | ||
58 | sa.handler = handler_with_siginfo; | ||
59 | sa.flags = SA_SIGINFO; | ||
60 | sa.restorer = NULL; /* request kernel-provided restorer */ | ||
61 | |||
62 | if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0) | ||
63 | err(1, "raw rt_sigaction syscall"); | ||
64 | |||
65 | raise(SIGUSR1); | ||
66 | |||
67 | if (handler_called) { | ||
68 | printf("[OK]\tSA_SIGINFO handler returned successfully\n"); | ||
69 | } else { | ||
70 | printf("[FAIL]\tSA_SIGINFO handler was not called\n"); | ||
71 | nerrs++; | ||
72 | } | ||
73 | |||
74 | sa.flags = 0; | ||
75 | sa.handler = handler_without_siginfo; | ||
76 | if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0) | ||
77 | err(1, "raw sigaction syscall"); | ||
78 | handler_called = 0; | ||
79 | |||
80 | raise(SIGUSR1); | ||
81 | |||
82 | if (handler_called) { | ||
83 | printf("[OK]\t!SA_SIGINFO handler returned successfully\n"); | ||
84 | } else { | ||
85 | printf("[FAIL]\t!SA_SIGINFO handler was not called\n"); | ||
86 | nerrs++; | ||
87 | } | ||
88 | } | ||