aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2009-10-27 10:47:58 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2009-10-27 10:47:58 +0000
commitd6e029adbef6c202441fc41b455610b4cc906ca5 (patch)
tree359a5b0885ae5a789f55ba40dc485621e67c34b1 /sys/kern/kern_sig.c
parent84440afb54cdee80c5515edf360a4c60d526d0ff (diff)
downloadsrc-d6e029adbef6c202441fc41b455610b4cc906ca5.tar.gz
src-d6e029adbef6c202441fc41b455610b4cc906ca5.zip
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
Notes
Notes: svn path=/head/; revision=198507
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c43
1 files changed, 22 insertions, 21 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index a453b555a76f..d0249f517dba 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)) {
/*