Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/x86/ldt_gdt_32: Work around a glibc sigaction() bug

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>

authored by

Andy Lutomirski and committed by
Ingo Molnar
65973dd3 ef37bc36

+46
+46
tools/testing/selftests/x86/ldt_gdt.c
··· 409 409 } 410 410 } 411 411 412 + #ifdef __i386__ 413 + 414 + #ifndef SA_RESTORE 415 + #define SA_RESTORER 0x04000000 416 + #endif 417 + 418 + /* 419 + * The UAPI header calls this 'struct sigaction', which conflicts with 420 + * glibc. Sigh. 421 + */ 422 + struct fake_ksigaction { 423 + void *handler; /* the real type is nasty */ 424 + unsigned long sa_flags; 425 + void (*sa_restorer)(void); 426 + unsigned char sigset[8]; 427 + }; 428 + 429 + static void fix_sa_restorer(int sig) 430 + { 431 + struct fake_ksigaction ksa; 432 + 433 + if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) { 434 + /* 435 + * glibc has a nasty bug: it sometimes writes garbage to 436 + * sa_restorer. This interacts quite badly with anything 437 + * that fiddles with SS because it can trigger legacy 438 + * stack switching. Patch it up. See: 439 + * 440 + * https://sourceware.org/bugzilla/show_bug.cgi?id=21269 441 + */ 442 + if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) { 443 + ksa.sa_restorer = NULL; 444 + if (syscall(SYS_rt_sigaction, sig, &ksa, NULL, 445 + sizeof(ksa.sigset)) != 0) 446 + err(1, "rt_sigaction"); 447 + } 448 + } 449 + } 450 + #else 451 + static void fix_sa_restorer(int sig) 452 + { 453 + /* 64-bit glibc works fine. */ 454 + } 455 + #endif 456 + 412 457 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 413 458 int flags) 414 459 { ··· 465 420 if (sigaction(sig, &sa, 0)) 466 421 err(1, "sigaction"); 467 422 423 + fix_sa_restorer(sig); 468 424 } 469 425 470 426 static jmp_buf jmpbuf;