Trapsignal() and postsig() call kern_sigprocmask() with both process

lock and curproc->p_sigacts->ps_mtx. Reschedule_signals may need to have
ps_mtx locked to decide and wakeup a thread, causing recursion on the
mutex.

Inform kern_sigprocmask() and reschedule_signals() about lock state
of the ps_mtx by new flag SIGPROCMASK_PS_LOCKED to avoid recursion.

Reported and tested by:	keramida
MFC after:	1 month
This commit is contained in:
Konstantin Belousov 2009-10-30 10:10:39 +00:00
parent 6bd41d5bc2
commit 80a8b0f3bf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=198670
2 changed files with 17 additions and 20 deletions

View file

@ -220,7 +220,7 @@ static int sigproptbl[NSIG] = {
SA_KILL|SA_PROC, /* SIGUSR2 */
};
static void reschedule_signals(struct proc *p, sigset_t block);
static void reschedule_signals(struct proc *p, sigset_t block, int flags);
static void
sigqueue_start(void)
@ -1024,7 +1024,7 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset,
* possibly waking it up.
*/
if (p->p_numthreads != 1)
reschedule_signals(p, new_block);
reschedule_signals(p, new_block, flags);
if (!(flags & SIGPROCMASK_PROC_LOCKED))
PROC_UNLOCK(p);
@ -1859,13 +1859,11 @@ trapsignal(struct thread *td, ksiginfo_t *ksi)
#endif
(*p->p_sysent->sv_sendsig)(ps->ps_sigact[_SIG_IDX(sig)],
ksi, &td->td_sigmask);
SIGSETOR(td->td_sigmask, ps->ps_catchmask[_SIG_IDX(sig)]);
if (!SIGISMEMBER(ps->ps_signodefer, sig)) {
SIGEMPTYSET(mask);
mask = ps->ps_catchmask[_SIG_IDX(sig)];
if (!SIGISMEMBER(ps->ps_signodefer, sig))
SIGADDSET(mask, sig);
kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
SIGPROCMASK_PROC_LOCKED);
}
kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED);
if (SIGISMEMBER(ps->ps_sigreset, sig)) {
/*
* See kern_sigaction() for origin of this code.
@ -2401,7 +2399,7 @@ ptracestop(struct thread *td, int sig)
}
static void
reschedule_signals(struct proc *p, sigset_t block)
reschedule_signals(struct proc *p, sigset_t block, int flags)
{
struct sigacts *ps;
struct thread *td;
@ -2419,12 +2417,14 @@ reschedule_signals(struct proc *p, sigset_t block)
td = sigtd(p, i, 0);
signotify(td);
mtx_lock(&ps->ps_mtx);
if (!(flags & SIGPROCMASK_PS_LOCKED))
mtx_lock(&ps->ps_mtx);
if (p->p_flag & P_TRACED || SIGISMEMBER(ps->ps_sigcatch, i))
tdsigwakeup(td, i, SIG_CATCH,
(SIGISMEMBER(ps->ps_sigintr, i) ? EINTR :
ERESTART));
mtx_unlock(&ps->ps_mtx);
if (!(flags & SIGPROCMASK_PS_LOCKED))
mtx_unlock(&ps->ps_mtx);
}
}
@ -2452,7 +2452,7 @@ tdsigcleanup(struct thread *td)
SIGFILLSET(unblocked);
SIGSETNAND(unblocked, td->td_sigmask);
SIGFILLSET(td->td_sigmask);
reschedule_signals(p, unblocked);
reschedule_signals(p, unblocked, 0);
}
@ -2734,15 +2734,11 @@ postsig(sig)
} else
returnmask = td->td_sigmask;
kern_sigprocmask(td, SIG_BLOCK,
&ps->ps_catchmask[_SIG_IDX(sig)], NULL,
SIGPROCMASK_PROC_LOCKED);
if (!SIGISMEMBER(ps->ps_signodefer, sig)) {
SIGEMPTYSET(mask);
mask = ps->ps_catchmask[_SIG_IDX(sig)];
if (!SIGISMEMBER(ps->ps_signodefer, sig))
SIGADDSET(mask, sig);
kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
SIGPROCMASK_PROC_LOCKED);
}
kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED);
if (SIGISMEMBER(ps->ps_sigreset, sig)) {
/*

View file

@ -319,6 +319,7 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */
/* flags for kern_sigprocmask */
#define SIGPROCMASK_OLD 0x0001
#define SIGPROCMASK_PROC_LOCKED 0x0002
#define SIGPROCMASK_PS_LOCKED 0x0004
/*
* Machine-independent functions: