panic i386 trapsignal kernel lock

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

panic i386 trapsignal kernel lock

Alexander Bluhm

When executing the libc ieeefp/except regression test, the i386 kernel

root@ot2:/usr/src/regress/lib/libc/ieeefp/except# make
cc -O2 -pipe   -MD -MP  -c /usr/src/regress/lib/libc/ieeefp/except/except.c
cc   -o except except.o
./except fltdiv

panic: kernel diagnostic assertion "_kernel_lock_held()" failed: file "/usr/src/sys/kern/kern_sig.c", line 759
Stopped at      db_enter+0x4:   popl    %ebp
*109367   7430      0         0x3          0    1  except
 294693    586      0     0x14000 0x40000200    0  softclock
db_enter() at db_enter+0x4
panic() at panic+0xcc
__assert(d09d4b80,d0a4b8f7,2f7,d0bdc81f) at __assert+0x19
trapsignal(d6f5a708,8,2,3,168337af) at trapsignal+0x2b1
npxintr(f55b4f04) at npxintr+0x19d
end of kernel

OpenBSD 6.2-current (GENERIC.MP) #406: Tue Feb 27 14:55:44 MST 2018
    [hidden email]:/usr/src/sys/arch/i386/compile/GENERIC.MP

mpi@ has added the KERNEL_ASSERT_LOCKED() two days ago in kern/kern_sig.c

revision 1.216
date: 2018/02/26 13:33:25;  author: mpi;  state: Exp;  lines: +41 -34;  commitid: Fy7O7T6htGPpvssI;
Fix a TOCTOU race that causes signals to be delivered more than once.

The race is only triggerable if one of the threads of a multi-threaded
program is in the middle of a NOLOCK syscall when a signal is received.

The problem is that `ps_sigact' is shared between threads so its access
should be serialized.  In the case of SA_RESETHAND, the handler is reset
when a signal is delivered, so delivering the signal twice would put the
process in an "impossible" state where some threads were stopped and some
were waiting for the others to die.

Serialize signal checking & processing with the KERNEL_LOCK() for now,
and introduce postsig_done() gypped from FreeBSD, to make sure the lock
is held when resetting the handler.

Bug report from espie@, ok visa@

Is there just a kernel lock missing around trapsignal() in npxintr()?
And what about psignal(), in other places it is called with kernel


Index: arch/i386/isa/npx.c
RCS file: /data/mirror/openbsd/cvs/src/sys/arch/i386/isa/npx.c,v
retrieving revision 1.63
diff -u -p -r1.63 npx.c
--- arch/i386/isa/npx.c 30 Dec 2017 20:46:59 -0000 1.63
+++ arch/i386/isa/npx.c 28 Feb 2018 20:28:54 -0000
@@ -528,7 +528,9 @@ npxintr(void *arg)
  code = x86fpflags_to_siginfo(addr->sv_87.sv_ex_sw);
  sv.sival_int = frame->if_eip;
  trapsignal(p, SIGFPE, T_ARITHTRAP, code, sv);
  } else {
  * Nested interrupt.  These losers occur when:
@@ -544,7 +546,9 @@ npxintr(void *arg)
  * Treat them like a true async interrupt.
  psignal(p, SIGFPE);
  return (1);