Author: kib
Date: Sun Mar 12 13:58:51 2017
New Revision: 315159
URL: https://svnweb.freebsd.org/changeset/base/315159

Log:
  Avoid reusing p_ksi while it is on queue.
  
  When sending SIGCHLD informing reaper that a zombie was reparented to
  it, we might race with the situation where the previous parent still
  not finished delivering SIGCHLD and having its p_ksi structure on the
  signal queue.  While on queue, the ksi should not be used for another
  send.
  
  Fix this by copying p_ksi into newly allocated ksi, which is directly
  put onto reaper sigqueue.  The later ensures that siginfo for reaper
  SIGCHLD is always present, similar to guarantees for siginfo of child.
  
  Reported by:  bdrewery
  Discussed with:       jilles
  Sponsored by: The FreeBSD Foundation
  MFC after:    1 week

Modified:
  head/sys/kern/kern_exit.c

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c   Sun Mar 12 13:53:13 2017        (r315158)
+++ head/sys/kern/kern_exit.c   Sun Mar 12 13:58:51 2017        (r315159)
@@ -189,6 +189,7 @@ exit1(struct thread *td, int rval, int s
 {
        struct proc *p, *nq, *q, *t;
        struct thread *tdt;
+       ksiginfo_t *ksi, *ksi1;
 
        mtx_assert(&Giant, MA_NOTOWNED);
        KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo));
@@ -449,14 +450,32 @@ exit1(struct thread *td, int rval, int s
                wakeup(q->p_reaper);
        for (; q != NULL; q = nq) {
                nq = LIST_NEXT(q, p_sibling);
+               ksi = ksiginfo_alloc(TRUE);
                PROC_LOCK(q);
                q->p_sigparent = SIGCHLD;
 
                if (!(q->p_flag & P_TRACED)) {
                        proc_reparent(q, q->p_reaper);
                        if (q->p_state == PRS_ZOMBIE) {
+                               /*
+                                * Inform reaper about the reparented
+                                * zombie, since wait(2) has something
+                                * new to report.  Guarantee queueing
+                                * of the SIGCHLD signal, similar to
+                                * the _exit() behaviour, by providing
+                                * our ksiginfo.  Ksi is freed by the
+                                * signal delivery.
+                                */
+                               if (q->p_ksi == NULL) {
+                                       ksi1 = NULL;
+                               } else {
+                                       ksiginfo_copy(q->p_ksi, ksi);
+                                       ksi->ksi_flags |= KSI_INS;
+                                       ksi1 = ksi;
+                                       ksi = NULL;
+                               }
                                PROC_LOCK(q->p_reaper);
-                               pksignal(q->p_reaper, SIGCHLD, q->p_ksi);
+                               pksignal(q->p_reaper, SIGCHLD, ksi1);
                                PROC_UNLOCK(q->p_reaper);
                        }
                } else {
@@ -489,6 +508,8 @@ exit1(struct thread *td, int rval, int s
                        kern_psignal(q, SIGKILL);
                }
                PROC_UNLOCK(q);
+               if (ksi != NULL)
+                       ksiginfo_free(ksi);
        }
 
        /*
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to