summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-08-29 08:38:34 +0000
committerkib <kib@FreeBSD.org>2014-08-29 08:38:34 +0000
commita1ef6db10241687eef4d1d32a208835662206c80 (patch)
tree1bb3b17928e47fdcefe0b1b376ce0327b22e652c /sys/kern
parent3d7b436d95767c10fbb99055ec2d6c9b80fe4823 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/kern/kern_sig.c77
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;
OpenPOWER on IntegriCloud