diff options
author | kib <kib@FreeBSD.org> | 2009-10-27 10:47:58 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-10-27 10:47:58 +0000 |
commit | ce081b037e7a762f0dd090a207cafc5121f39f51 (patch) | |
tree | 359a5b0885ae5a789f55ba40dc485621e67c34b1 /sys/kern | |
parent | eb4c68098b66d84de3abc7be00acfdc6d2f8f980 (diff) | |
download | FreeBSD-src-ce081b037e7a762f0dd090a207cafc5121f39f51.zip FreeBSD-src-ce081b037e7a762f0dd090a207cafc5121f39f51.tar.gz |
In r197963, a race with thread being selected for signal delivery
while in kernel mode, and later changing signal mask to block the
signal, was fixed for sigprocmask(2) and ptread_exit(3). The same race
exists for sigreturn(2), setcontext(2) and swapcontext(2) syscalls.
Use kern_sigprocmask() instead of direct manipulation of td_sigmask to
reschedule newly blocked signals, closing the race.
Reviewed by: davidxu
Tested by: pho
MFC after: 1 month
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_context.c | 12 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 43 |
2 files changed, 26 insertions, 29 deletions
diff --git a/sys/kern/kern_context.c b/sys/kern/kern_context.c index f951fca..6628eb6 100644 --- a/sys/kern/kern_context.c +++ b/sys/kern/kern_context.c @@ -89,10 +89,8 @@ setcontext(struct thread *td, struct setcontext_args *uap) if (ret == 0) { ret = set_mcontext(td, &uc.uc_mcontext); if (ret == 0) { - SIG_CANTMASK(uc.uc_sigmask); - PROC_LOCK(td->td_proc); - td->td_sigmask = uc.uc_sigmask; - PROC_UNLOCK(td->td_proc); + kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, + NULL, 0); } } } @@ -118,10 +116,8 @@ swapcontext(struct thread *td, struct swapcontext_args *uap) if (ret == 0) { ret = set_mcontext(td, &uc.uc_mcontext); if (ret == 0) { - SIG_CANTMASK(uc.uc_sigmask); - PROC_LOCK(td->td_proc); - td->td_sigmask = uc.uc_sigmask; - PROC_UNLOCK(td->td_proc); + kern_sigprocmask(td, SIG_SETMASK, + &uc.uc_sigmask, NULL, 0); } } } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index a453b55..d0249f5 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1396,15 +1396,11 @@ osigblock(td, uap) register struct thread *td; struct osigblock_args *uap; { - struct proc *p = td->td_proc; - sigset_t set; + sigset_t set, oset; OSIG2SIG(uap->mask, set); - SIG_CANTMASK(set); - PROC_LOCK(p); - SIG2OSIG(td->td_sigmask, td->td_retval[0]); - SIGSETOR(td->td_sigmask, set); - PROC_UNLOCK(p); + kern_sigprocmask(td, SIG_BLOCK, &set, &oset, 0); + SIG2OSIG(oset, td->td_retval[0]); return (0); } @@ -1418,16 +1414,11 @@ osigsetmask(td, uap) struct thread *td; struct osigsetmask_args *uap; { - struct proc *p = td->td_proc; - sigset_t set; + sigset_t set, oset; OSIG2SIG(uap->mask, set); - SIG_CANTMASK(set); - PROC_LOCK(p); - SIG2OSIG(td->td_sigmask, td->td_retval[0]); - SIGSETLO(td->td_sigmask, set); - signotify(td); - PROC_UNLOCK(p); + kern_sigprocmask(td, SIG_SETMASK, &set, &oset, 0); + SIG2OSIG(oset, td->td_retval[0]); return (0); } #endif /* COMPAT_43 */ @@ -1845,6 +1836,7 @@ void trapsignal(struct thread *td, ksiginfo_t *ksi) { struct sigacts *ps; + sigset_t mask; struct proc *p; int sig; int code; @@ -1868,8 +1860,11 @@ trapsignal(struct thread *td, ksiginfo_t *ksi) (*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)) - SIGADDSET(td->td_sigmask, sig); + if (!SIGISMEMBER(ps->ps_signodefer, sig)) { + SIGEMPTYSET(mask); + SIGADDSET(mask, sig); + kern_sigprocmask(td, SIG_BLOCK, &mask, NULL, 0); + } if (SIGISMEMBER(ps->ps_sigreset, sig)) { /* * See kern_sigaction() for origin of this code. @@ -2683,7 +2678,7 @@ postsig(sig) struct sigacts *ps; sig_t action; ksiginfo_t ksi; - sigset_t returnmask; + sigset_t returnmask, mask; KASSERT(sig != 0, ("postsig")); @@ -2738,9 +2733,15 @@ postsig(sig) } else returnmask = td->td_sigmask; - SIGSETOR(td->td_sigmask, ps->ps_catchmask[_SIG_IDX(sig)]); - if (!SIGISMEMBER(ps->ps_signodefer, sig)) - SIGADDSET(td->td_sigmask, sig); + kern_sigprocmask(td, SIG_BLOCK, + &ps->ps_catchmask[_SIG_IDX(sig)], NULL, + SIGPROCMASK_PROC_LOCKED); + if (!SIGISMEMBER(ps->ps_signodefer, sig)) { + SIGEMPTYSET(mask); + SIGADDSET(mask, sig); + kern_sigprocmask(td, SIG_BLOCK, &mask, NULL, + SIGPROCMASK_PROC_LOCKED); + } if (SIGISMEMBER(ps->ps_sigreset, sig)) { /* |