sigfastblock: do not skip cursig/postsig loop in ast()

Even if sigfastblock block is non-zero, non-blockable signals must be
checked on ast and delivered now.  This also affects debugger ability
to attach, because issignal() also calls ptracestop() if there is
a pending stop for debugee.

Instead of checking for sigfastblock, and either setting PENDING flag
for usermode or doing signal delivery loop, always do the loop after
checking, and then handle PENDING bit. issignal() already does the right
thing for fast-blocked case, allowing only STOPs and SIGKILL delivery to
happen.

Reported by:	Vasily Postnicov <shamaz.mazum@gmail.com>, markj
Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D28089
This commit is contained in:
Konstantin Belousov 2021-01-11 03:22:44 +02:00
parent 513320c0f1
commit 57f22c828e

View File

@ -204,6 +204,7 @@ ast(struct trapframe *framep)
struct thread *td;
struct proc *p;
int flags, sig;
bool resched_sigs;
td = curthread;
p = td->td_proc;
@ -316,27 +317,24 @@ ast(struct trapframe *framep)
if (flags & TDF_NEEDSIGCHK || p->p_pendingcnt > 0 ||
!SIGISEMPTY(p->p_siglist)) {
sigfastblock_fetch(td);
if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0 &&
td->td_sigblock_val != 0) {
sigfastblock_setpend(td, true);
} else {
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
while ((sig = cursig(td)) != 0) {
KASSERT(sig >= 0, ("sig %d", sig));
postsig(sig);
}
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
while ((sig = cursig(td)) != 0) {
KASSERT(sig >= 0, ("sig %d", sig));
postsig(sig);
}
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
resched_sigs = true;
} else {
resched_sigs = false;
}
/*
* Handle deferred update of the fast sigblock value, after
* the postsig() loop was performed.
*/
if (td->td_pflags & TDP_SIGFASTPENDING)
sigfastblock_setpend(td, false);
sigfastblock_setpend(td, resched_sigs);
#ifdef KTRACE
KTRUSERRET(td);