When executing the libc ieeefp/except regression test, the i386 kernel
cc -O2 -pipe -MD -MP -c /usr/src/regress/lib/libc/ieeefp/except/except.c
cc -o except except.o
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
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*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
mpi@ has added the KERNEL_ASSERT_LOCKED() two days ago in kern/kern_sig.c
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