forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/32946d714156879cd8e5d8eab044cd07557ed558.1452628504.git.luto@kernel.org Signed-off-by: Ingo Molnar <[email protected]>
- Loading branch information
Showing
2 changed files
with
90 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* vdso_restorer.c - tests vDSO-based signal restore | ||
* Copyright (c) 2015 Andrew Lutomirski | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms and conditions of the GNU General Public License, | ||
* version 2, as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* This makes sure that sa_restorer == NULL keeps working on 32-bit | ||
* configurations. Modern glibc doesn't use it under any circumstances, | ||
* so it's easy to overlook breakage. | ||
* | ||
* 64-bit userspace has never supported sa_restorer == NULL, so this is | ||
* 32-bit only. | ||
*/ | ||
|
||
#define _GNU_SOURCE | ||
|
||
#include <err.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <signal.h> | ||
#include <unistd.h> | ||
#include <syscall.h> | ||
#include <sys/syscall.h> | ||
|
||
/* Open-code this -- the headers are too messy to easily use them. */ | ||
struct real_sigaction { | ||
void *handler; | ||
unsigned long flags; | ||
void *restorer; | ||
unsigned int mask[2]; | ||
}; | ||
|
||
static volatile sig_atomic_t handler_called; | ||
|
||
static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void) | ||
{ | ||
handler_called = 1; | ||
} | ||
|
||
static void handler_without_siginfo(int sig) | ||
{ | ||
handler_called = 1; | ||
} | ||
|
||
int main() | ||
{ | ||
int nerrs = 0; | ||
struct real_sigaction sa; | ||
|
||
memset(&sa, 0, sizeof(sa)); | ||
sa.handler = handler_with_siginfo; | ||
sa.flags = SA_SIGINFO; | ||
sa.restorer = NULL; /* request kernel-provided restorer */ | ||
|
||
if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0) | ||
err(1, "raw rt_sigaction syscall"); | ||
|
||
raise(SIGUSR1); | ||
|
||
if (handler_called) { | ||
printf("[OK]\tSA_SIGINFO handler returned successfully\n"); | ||
} else { | ||
printf("[FAIL]\tSA_SIGINFO handler was not called\n"); | ||
nerrs++; | ||
} | ||
|
||
sa.flags = 0; | ||
sa.handler = handler_without_siginfo; | ||
if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0) | ||
err(1, "raw sigaction syscall"); | ||
handler_called = 0; | ||
|
||
raise(SIGUSR1); | ||
|
||
if (handler_called) { | ||
printf("[OK]\t!SA_SIGINFO handler returned successfully\n"); | ||
} else { | ||
printf("[FAIL]\t!SA_SIGINFO handler was not called\n"); | ||
nerrs++; | ||
} | ||
} |