| From 65973dd3fd31151823f4b8c289eebbb3fb7e6bc0 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Wed, 22 Mar 2017 14:32:29 -0700 |
| Subject: [PATCH] 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> |
| Cc: stable@vger.kernel.org |
| Link: http://lkml.kernel.org/r/aaab0f9f93c9af25396f01232608c163a760a668.1490218061.git.luto@kernel.org |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| |
| diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c |
| index f6121612e769..b9a22f18566a 100644 |
| --- a/tools/testing/selftests/x86/ldt_gdt.c |
| +++ b/tools/testing/selftests/x86/ldt_gdt.c |
| @@ -409,6 +409,51 @@ 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 char sigset[8]; |
| +}; |
| + |
| +static void fix_sa_restorer(int sig) |
| +{ |
| + 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. See: |
| + * |
| + * https://sourceware.org/bugzilla/show_bug.cgi?id=21269 |
| + */ |
| + if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) { |
| + ksa.sa_restorer = NULL; |
| + if (syscall(SYS_rt_sigaction, sig, &ksa, NULL, |
| + sizeof(ksa.sigset)) != 0) |
| + err(1, "rt_sigaction"); |
| + } |
| + } |
| +} |
| +#else |
| +static void fix_sa_restorer(int sig) |
| +{ |
| + /* 64-bit glibc works fine. */ |
| +} |
| +#endif |
| + |
| static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), |
| int flags) |
| { |
| @@ -420,6 +465,7 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), |
| if (sigaction(sig, &sa, 0)) |
| err(1, "sigaction"); |
| |
| + fix_sa_restorer(sig); |
| } |
| |
| static jmp_buf jmpbuf; |
| -- |
| 2.12.0 |
| |