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
This commit is contained in:
Konstantin Belousov 2017-03-12 13:58:51 +00:00
parent 2b6d1a639b
commit 9a2dde8013
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315159

View File

@ -189,6 +189,7 @@ exit1(struct thread *td, int rval, int signo)
{
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 signo)
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 signo)
kern_psignal(q, SIGKILL);
}
PROC_UNLOCK(q);
if (ksi != NULL)
ksiginfo_free(ksi);
}
/*