diff options
author | kib <kib@FreeBSD.org> | 2014-08-29 08:38:34 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2014-08-29 08:38:34 +0000 |
commit | a1ef6db10241687eef4d1d32a208835662206c80 (patch) | |
tree | 1bb3b17928e47fdcefe0b1b376ce0327b22e652c /sys/kern/kern_sig.c | |
parent | 3d7b436d95767c10fbb99055ec2d6c9b80fe4823 (diff) | |
download | FreeBSD-src-a1ef6db10241687eef4d1d32a208835662206c80.zip FreeBSD-src-a1ef6db10241687eef4d1d32a208835662206c80.tar.gz |
MFC r270321:
Ensure that sigaction flags for signal, which disposition is reset to
ignored or default, are not leaking.
MFC r270504:
Revert the handling of all siginfo sa_flags except SA_SIGINFO to the
pre-r270321 state.
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r-- | sys/kern/kern_sig.c | 77 |
1 files changed, 44 insertions, 33 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 11e0fdb..45e12c4 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -626,6 +626,20 @@ sig_ffs(sigset_t *set) return (0); } +static bool +sigact_flag_test(struct sigaction *act, int flag) +{ + + /* + * SA_SIGINFO is reset when signal disposition is set to + * ignore or default. Other flags are kept according to user + * settings. + */ + return ((act->sa_flags & flag) != 0 && (flag != SA_SIGINFO || + ((__sighandler_t *)act->sa_sigaction != SIG_IGN && + (__sighandler_t *)act->sa_sigaction != SIG_DFL))); +} + /* * kern_sigaction * sigaction @@ -688,7 +702,7 @@ kern_sigaction(td, sig, act, oact, flags) ps->ps_catchmask[_SIG_IDX(sig)] = act->sa_mask; SIG_CANTMASK(ps->ps_catchmask[_SIG_IDX(sig)]); - if (act->sa_flags & SA_SIGINFO) { + if (sigact_flag_test(act, SA_SIGINFO)) { ps->ps_sigact[_SIG_IDX(sig)] = (__sighandler_t *)act->sa_sigaction; SIGADDSET(ps->ps_siginfo, sig); @@ -696,19 +710,19 @@ kern_sigaction(td, sig, act, oact, flags) ps->ps_sigact[_SIG_IDX(sig)] = act->sa_handler; SIGDELSET(ps->ps_siginfo, sig); } - if (!(act->sa_flags & SA_RESTART)) + if (!sigact_flag_test(act, SA_RESTART)) SIGADDSET(ps->ps_sigintr, sig); else SIGDELSET(ps->ps_sigintr, sig); - if (act->sa_flags & SA_ONSTACK) + if (sigact_flag_test(act, SA_ONSTACK)) SIGADDSET(ps->ps_sigonstack, sig); else SIGDELSET(ps->ps_sigonstack, sig); - if (act->sa_flags & SA_RESETHAND) + if (sigact_flag_test(act, SA_RESETHAND)) SIGADDSET(ps->ps_sigreset, sig); else SIGDELSET(ps->ps_sigreset, sig); - if (act->sa_flags & SA_NODEFER) + if (sigact_flag_test(act, SA_NODEFER)) SIGADDSET(ps->ps_signodefer, sig); else SIGDELSET(ps->ps_signodefer, sig); @@ -909,14 +923,31 @@ siginit(p) PROC_LOCK(p); ps = p->p_sigacts; mtx_lock(&ps->ps_mtx); - for (i = 1; i <= NSIG; i++) - if (sigprop(i) & SA_IGNORE && i != SIGCONT) + for (i = 1; i <= NSIG; i++) { + if (sigprop(i) & SA_IGNORE && i != SIGCONT) { SIGADDSET(ps->ps_sigignore, i); + } + } mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p); } /* + * Reset specified signal to the default disposition. + */ +static void +sigdflt(struct sigacts *ps, int sig) +{ + + mtx_assert(&ps->ps_mtx, MA_OWNED); + SIGDELSET(ps->ps_sigcatch, sig); + if ((sigprop(sig) & SA_IGNORE) != 0 && sig != SIGCONT) + SIGADDSET(ps->ps_sigignore, sig); + ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; + SIGDELSET(ps->ps_siginfo, sig); +} + +/* * Reset signals for an exec of the specified process. */ void @@ -937,13 +968,9 @@ execsigs(struct proc *p) mtx_lock(&ps->ps_mtx); while (SIGNOTEMPTY(ps->ps_sigcatch)) { sig = sig_ffs(&ps->ps_sigcatch); - SIGDELSET(ps->ps_sigcatch, sig); - if (sigprop(sig) & SA_IGNORE) { - if (sig != SIGCONT) - SIGADDSET(ps->ps_sigignore, sig); + sigdflt(ps, sig); + if ((sigprop(sig) & SA_IGNORE) != 0) sigqueue_delete_proc(p, sig); - } - ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; } /* * Reset stack state to the user stack. @@ -1901,16 +1928,8 @@ trapsignal(struct thread *td, ksiginfo_t *ksi) SIGADDSET(mask, sig); 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. - */ - SIGDELSET(ps->ps_sigcatch, sig); - if (sig != SIGCONT && - sigprop(sig) & SA_IGNORE) - SIGADDSET(ps->ps_sigignore, sig); - ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; - } + if (SIGISMEMBER(ps->ps_sigreset, sig)) + sigdflt(ps, sig); mtx_unlock(&ps->ps_mtx); } else { /* @@ -2853,16 +2872,8 @@ postsig(sig) 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. - */ - SIGDELSET(ps->ps_sigcatch, sig); - if (sig != SIGCONT && - sigprop(sig) & SA_IGNORE) - SIGADDSET(ps->ps_sigignore, sig); - ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; - } + if (SIGISMEMBER(ps->ps_sigreset, sig)) + sigdflt(ps, sig); td->td_ru.ru_nsignals++; if (p->p_sig == sig) { p->p_code = 0; |