sigfastblock: fix delivery of the pending signals in single-threaded processes.

If single-threaded process receives a signal during critical section
established by sigfastblock(2) word, unblock did not caused signal
delivery because sigfastblock(SIGFASTBLOCK_UNBLOCK) failed to request
ast handling of the pending signals.

Set TDF_ASTPENDING | TDF_NEEDSIGCHK on unblock or when kernel forces
end of sigfastblock critical section, to cause syscall exit to recheck
and deliver any signal pending.

Reported by:	corydoras@ridiculousfish.com
PR:	246385
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Konstantin Belousov 2020-05-11 22:38:32 +00:00
parent f88ecf821e
commit fb3c434ba2

View File

@ -3976,6 +3976,22 @@ sigfastblock_fetch_sig(struct thread *td, bool sendsig, uint32_t *valp)
return (true);
}
static void
sigfastblock_resched(struct thread *td, bool resched)
{
struct proc *p;
if (resched) {
p = td->td_proc;
PROC_LOCK(p);
reschedule_signals(p, td->td_sigmask, 0);
PROC_UNLOCK(p);
}
thread_lock(td);
td->td_flags |= TDF_ASTPENDING | TDF_NEEDSIGCHK;
thread_unlock(td);
}
int
sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
{
@ -4046,11 +4062,8 @@ sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
* signals to current thread. But notify others about
* fake unblock.
*/
if (error == 0 && p->p_numthreads != 1) {
PROC_LOCK(p);
reschedule_signals(p, td->td_sigmask, 0);
PROC_UNLOCK(p);
}
sigfastblock_resched(td, error == 0 && p->p_numthreads != 1);
break;
case SIGFASTBLOCK_UNSETPTR:
@ -4079,7 +4092,6 @@ sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
void
sigfastblock_clear(struct thread *td)
{
struct proc *p;
bool resched;
if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0)
@ -4088,12 +4100,7 @@ sigfastblock_clear(struct thread *td)
resched = (td->td_pflags & TDP_SIGFASTPENDING) != 0 ||
SIGPENDING(td);
td->td_pflags &= ~(TDP_SIGFASTBLOCK | TDP_SIGFASTPENDING);
if (resched) {
p = td->td_proc;
PROC_LOCK(p);
reschedule_signals(p, td->td_sigmask, 0);
PROC_UNLOCK(p);
}
sigfastblock_resched(td, resched);
}
void