aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2017-03-22 17:32:29 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-20 08:28:36 -0400
commite65c6aa108607501271f2af80f3947f315fb56ca (patch)
treeb5c37e7d96e7d3de237cdf961d5d0d19f7540ea3 /tools
parentacb6dc6aa7447828355a50cf5cb542bec1398aaf (diff)
selftests/x86/ldt_gdt_32: Work around a glibc sigaction() bug
commit 65973dd3fd31151823f4b8c289eebbb3fb7e6bc0 upstream. 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. The ldt_gdt self-test is 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 Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> 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: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Garnier <thgarnie@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/aaab0f9f93c9af25396f01232608c163a760a668.1490218061.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/x86/ldt_gdt.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
index 4af47079cf04..e717fed80219 100644
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -403,6 +403,51 @@ static void *threadproc(void *ctx)
403 } 403 }
404} 404}
405 405
406#ifdef __i386__
407
408#ifndef SA_RESTORE
409#define SA_RESTORER 0x04000000
410#endif
411
412/*
413 * The UAPI header calls this 'struct sigaction', which conflicts with
414 * glibc. Sigh.
415 */
416struct fake_ksigaction {
417 void *handler; /* the real type is nasty */
418 unsigned long sa_flags;
419 void (*sa_restorer)(void);
420 unsigned char sigset[8];
421};
422
423static void fix_sa_restorer(int sig)
424{
425 struct fake_ksigaction ksa;
426
427 if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {
428 /*
429 * glibc has a nasty bug: it sometimes writes garbage to
430 * sa_restorer. This interacts quite badly with anything
431 * that fiddles with SS because it can trigger legacy
432 * stack switching. Patch it up. See:
433 *
434 * https://sourceware.org/bugzilla/show_bug.cgi?id=21269
435 */
436 if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {
437 ksa.sa_restorer = NULL;
438 if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,
439 sizeof(ksa.sigset)) != 0)
440 err(1, "rt_sigaction");
441 }
442 }
443}
444#else
445static void fix_sa_restorer(int sig)
446{
447 /* 64-bit glibc works fine. */
448}
449#endif
450
406static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 451static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
407 int flags) 452 int flags)
408{ 453{
@@ -414,6 +459,7 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
414 if (sigaction(sig, &sa, 0)) 459 if (sigaction(sig, &sa, 0))
415 err(1, "sigaction"); 460 err(1, "sigaction");
416 461
462 fix_sa_restorer(sig);
417} 463}
418 464
419static jmp_buf jmpbuf; 465static jmp_buf jmpbuf;