linux/arch/x86
Roland McGrath eca91e7838 x86_64: fix delayed signals
On three of the several paths in entry_64.S that call
do_notify_resume() on the way back to user mode, we fail to properly
check again for newly-arrived work that requires another call to
do_notify_resume() before going to user mode.  These paths set the
mask to check only _TIF_NEED_RESCHED, but this is wrong.  The other
paths that lead to do_notify_resume() do this correctly already, and
entry_32.S does it correctly in all cases.

All paths back to user mode have to check all the _TIF_WORK_MASK
flags at the last possible stage, with interrupts disabled.
Otherwise, we miss any flags (TIF_SIGPENDING for example) that were
set any time after we entered do_notify_resume().  More work flags
can be set (or left set) synchronously inside do_notify_resume(), as
TIF_SIGPENDING can be, or asynchronously by interrupts or other CPUs
(which then send an asynchronous interrupt).

There are many different scenarios that could hit this bug, most of
them races.  The simplest one to demonstrate does not require any
race: when one signal has done handler setup at the check before
returning from a syscall, and there is another signal pending that
should be handled.  The second signal's handler should interrupt the
first signal handler before it actually starts (so the interrupted PC
is still at the handler's entry point).  Instead, it runs away until
the next kernel entry (next syscall, tick, etc).

This test behaves correctly on 32-bit kernels, and fails on 64-bit
(either 32-bit or 64-bit test binary).  With this fix, it works.

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <signal.h>
    #include <string.h>
    #include <sys/ucontext.h>

    #ifndef REG_RIP
    #define REG_RIP REG_EIP
    #endif

    static sig_atomic_t hit1, hit2;

    static void
    handler (int sig, siginfo_t *info, void *ctx)
    {
      ucontext_t *uc = ctx;

      if ((void *) uc->uc_mcontext.gregs[REG_RIP] == &handler)
        {
          if (sig == SIGUSR1)
            hit1 = 1;
          else
            hit2 = 1;
        }

      printf ("%s at %#lx\n", strsignal (sig),
              uc->uc_mcontext.gregs[REG_RIP]);
    }

    int
    main (void)
    {
      struct sigaction sa;
      sigset_t set;

      sigemptyset (&sa.sa_mask);
      sa.sa_flags = SA_SIGINFO;
      sa.sa_sigaction = &handler;

      if (sigaction (SIGUSR1, &sa, NULL)
          || sigaction (SIGUSR2, &sa, NULL))
        return 2;

      sigemptyset (&set);
      sigaddset (&set, SIGUSR1);
      sigaddset (&set, SIGUSR2);
      if (sigprocmask (SIG_BLOCK, &set, NULL))
        return 3;

      printf ("main at %p, handler at %p\n", &main, &handler);

      raise (SIGUSR1);
      raise (SIGUSR2);

      if (sigprocmask (SIG_UNBLOCK, &set, NULL))
        return 4;

      if (hit1 + hit2 == 1)
        {
          puts ("PASS");
          return 0;
        }

      puts ("FAIL");
      return 1;
    }

Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-07-12 07:11:10 +02:00
..
boot Merge branch 'x86/mpparse' into x86/devel 2008-07-08 11:14:58 +02:00
configs x86: defconfig updates 2008-05-12 21:28:12 +02:00
crypto [CRYPTO] aes-x86-32: Remove unused return code 2008-04-21 10:19:21 +08:00
ia32 x86: rename threadinfo to TI. 2008-07-09 09:14:02 +02:00
kernel x86_64: fix delayed signals 2008-07-12 07:11:10 +02:00
kvm KVM: Make kvm host use the paravirt clocksource structs 2008-06-24 21:02:32 +03:00
lguest x86, VisWS: turn into generic arch, eliminate Kconfig specials 2008-07-10 18:55:47 +02:00
lib x86: fix compile error in current tip.git 2008-07-10 21:55:59 +02:00
mach-default x86, VisWS: turn into generic arch, eliminate Kconfig specials 2008-07-10 18:55:47 +02:00
mach-es7000 x86: make generic arch support NUMAQ 2008-06-10 11:34:42 +02:00
mach-generic x86: make generic arch support NUMAQ, fix 2008-07-08 10:35:45 +02:00
mach-rdc321x x86, rdc321x: remove watchdog file 2008-04-17 17:40:50 +02:00
mach-voyager x86: cleanup machine_specific_memory_setup, v2 2008-07-08 10:39:01 +02:00
math-emu x86: coding style fixes to arch/x86/math-emu/reg_constant 2008-06-18 15:00:13 +02:00
mm x86: introduce max_low_pfn_mapped for 64-bit 2008-07-11 10:24:04 +02:00
oprofile x86/oprofile: disable preemption in nmi_shutdown 2008-06-24 13:48:29 +02:00
pci Merge branch 'x86/generalize-visws' into x86/core 2008-07-11 21:22:18 +02:00
power x86: remove end_pfn in 64bit 2008-07-08 13:10:38 +02:00
vdso x86_64: vdso32 cleanup using feature flags 2008-07-11 15:44:58 +02:00
video x86: video/fbdev.c: add MODULE_LICENSE 2008-05-04 20:04:46 +02:00
xen x86: rename paravirtualized TSC functions 2008-07-09 07:43:28 +02:00
Kconfig x86, VisWS: fix pci_direct_conf1 dependency 2008-07-10 20:10:48 +02:00
Kconfig.cpu x86: mark x86_64 as having a working WP. 2008-07-09 09:14:21 +02:00
Kconfig.debug Merge branch 'x86/numa' into x86/devel 2008-07-08 11:59:23 +02:00
Makefile x86, VisWS: turn into generic arch, remove leftover files 2008-07-10 18:55:45 +02:00
Makefile_32.cpu x86: move i386 and x86_64 Makefiles to arch/x86 2007-10-25 22:27:34 +02:00