Date: Sun, 12 Mar 2017 13:58:51 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r315159 - head/sys/kern Message-ID: <201703121358.v2CDwpxU074833@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703121358.v2CDwpxU074833>