From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752354AbcALT4V (ORCPT ); Tue, 12 Jan 2016 14:56:21 -0500 Received: from mail.kernel.org ([198.145.29.136]:51152 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751451AbcALT4U (ORCPT ); Tue, 12 Jan 2016 14:56:20 -0500 From: Andy Lutomirski To: x86@kernel.org Cc: Borislav Petkov , Shuah Khan , linux-kernel@vger.kernel.org, Andy Lutomirski Subject: [PATCH v2] selftests/x86: Test __kernel_sigreturn and __kernel_rt_sigreturn Date: Tue, 12 Jan 2016 11:56:15 -0800 Message-Id: <32946d714156879cd8e5d8eab044cd07557ed558.1452628504.git.luto@kernel.org> X-Mailer: git-send-email 2.5.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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. Cc: Shuah Khan Signed-off-by: Andy Lutomirski --- I wrote this while debugging the 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. Changes from v1: Add missing handler_called = 0 (rdd) tools/testing/selftests/x86/Makefile | 3 +- tools/testing/selftests/x86/vdso_restorer.c | 88 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/vdso_restorer.c 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 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) 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 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +/* 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++; + } +} -- 2.5.0