Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758189AbdCUQjp (ORCPT ); Tue, 21 Mar 2017 12:39:45 -0400 Received: from mail.kernel.org ([198.145.29.136]:36792 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757077AbdCUQji (ORCPT ); Tue, 21 Mar 2017 12:39:38 -0400 From: Andy Lutomirski To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Borislav Petkov , Andy Lutomirski , stable@vger.kernel.org Subject: [PATCH] selftests/x86/ldt_gdt_32: Work around a glibc sigaction bug Date: Tue, 21 Mar 2017 09:39:33 -0700 Message-Id: <371a5620248568efaf31dd9d897af3775725d9b8.1490114317.git.luto@kernel.org> X-Mailer: git-send-email 2.9.3 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2469 Lines: 81 i386 glibc is buggy and calls the sigaction syscall incorrectly. This is asymptomatic for normal programs, but it blows up on programs that do evil things with segmentation. ldt_gdt an example of such an evil program. This doesn't appear to be a regression -- I think I just got lucky with the uninitialized memory that glibc threw at the kernel when I wrote the test. This hackish fix manually issues sigaction(2) syscalls to undo the damage. Without the fix, ldt_gdt_32 segfaults; with the fix, it passes for me. See https://sourceware.org/bugzilla/show_bug.cgi?id=21269 Cc: stable@vger.kernel.org Signed-off-by: Andy Lutomirski --- I'll see about factoring out sethandler(), etc into a separate file soon. In the mean time, this at least makes the test pass. tools/testing/selftests/x86/ldt_gdt.c | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c index f6121612e769..18e6ae1f1bb6 100644 --- a/tools/testing/selftests/x86/ldt_gdt.c +++ b/tools/testing/selftests/x86/ldt_gdt.c @@ -409,6 +409,24 @@ static void *threadproc(void *ctx) } } +#ifdef __i386__ + +#ifndef SA_RESTORE +#define SA_RESTORER 0x04000000 +#endif + +/* + * The UAPI header calls this 'struct sigaction', which conflicts with + * glibc. Sigh. + */ +struct fake_ksigaction { + void *handler; /* the real type is nasty */ + unsigned long sa_flags; + void (*sa_restorer)(void); + unsigned long sigset1, sigset2; +}; +#endif + static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags) { @@ -420,6 +438,24 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), if (sigaction(sig, &sa, 0)) err(1, "sigaction"); +#ifdef __i386__ + struct fake_ksigaction ksa; + if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) { + /* + * glibc has a nasty bug: it sometimes writes garbage to + * sa_restorer. This interacts quite badly with anything + * that fiddles with SS because it can trigger legacy + * stack switching. Patch it up. + */ + printf("%d asdf %lx %p\n", sig, ksa.sa_flags, ksa.sa_restorer); + if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) { + printf("asdffff\n"); + ksa.sa_restorer = NULL; + if (syscall(SYS_rt_sigaction, sig, &ksa, NULL, 8) != 0) + err(1, "rt_sigaction"); + } + } +#endif } static jmp_buf jmpbuf; -- 2.9.3