Author: kib
Date: Fri Aug 29 08:38:34 2014
New Revision: 270788
URL: http://svnweb.freebsd.org/changeset/base/270788

Log:
  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.

Modified:
  stable/10/sys/kern/kern_sig.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/kern/kern_sig.c
==============================================================================
--- stable/10/sys/kern/kern_sig.c       Fri Aug 29 08:33:32 2014        
(r270787)
+++ stable/10/sys/kern/kern_sig.c       Fri Aug 29 08:38:34 2014        
(r270788)
@@ -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
                        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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to