Skip to content

Commit

Permalink
selftests/x86: Test __kernel_sigreturn and __kernel_rt_sigreturn
Browse files Browse the repository at this point in the history
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
amluto authored and Ingo Molnar committed Jan 13, 2016
1 parent 2f0c0b2 commit 65cacec
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 1 deletion.
3 changes: 2 additions & 1 deletion tools/testing/selftests/x86/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ include ../lib.mk
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
ldt_gdt
ldt_gdt \
vdso_restorer

TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
Expand Down
88 changes: 88 additions & 0 deletions tools/testing/selftests/x86/vdso_restorer.c
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++;
}
}

0 comments on commit 65cacec

Please sign in to comment.