summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_procdesc.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2012-09-01 11:21:56 +0000
committerpjd <pjd@FreeBSD.org>2012-09-01 11:21:56 +0000
commit09be0bbef152583f8fa989d7f9c3a7cd76b50d2a (patch)
treefd78400a68bac8d6f92a7aac54b9879ca9b1a260 /sys/kern/sys_procdesc.c
parent79fa964314bead3dd00a1a411724f8446667a8bc (diff)
downloadFreeBSD-src-09be0bbef152583f8fa989d7f9c3a7cd76b50d2a.zip
FreeBSD-src-09be0bbef152583f8fa989d7f9c3a7cd76b50d2a.tar.gz
Fix panic in procdesc that can be triggered in the following scenario:
1. Process A pdfork(2)s process B. 2. Process A passes process descriptor of B to unrelated process C. 3. Hit CTRL+C to terminate process A. Process B is also terminated with SIGINT. 4. init(8) collects status of process B. 5. Process C closes process descriptor associated with process B. When we have such order of events, init(8), by collecting status of process B, will call procdesc_reap(). This function sets pd_proc to NULL. Now when process C calls close on this process descriptor, procdesc_close() is called. Unfortunately procdesc_close() assumes that pd_proc points at a valid proc structure, but it was set to NULL earlier, so the kernel panics. The patch also adds setting 'p->p_procdesc' to NULL in procdesc_reap(), which I think should be done. MFC after: 1 week
Diffstat (limited to 'sys/kern/sys_procdesc.c')
-rw-r--r--sys/kern/sys_procdesc.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 0bf79b8..ac625f7 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -333,6 +333,7 @@ procdesc_reap(struct proc *p)
pd = p->p_procdesc;
pd->pd_proc = NULL;
+ p->p_procdesc = NULL;
procdesc_free(pd);
}
@@ -358,14 +359,20 @@ procdesc_close(struct file *fp, struct thread *td)
pd->pd_flags |= PDF_CLOSED;
PROCDESC_UNLOCK(pd);
p = pd->pd_proc;
- PROC_LOCK(p);
- if (p->p_state == PRS_ZOMBIE) {
+ if (p == NULL) {
+ /*
+ * This is the case where process' exit status was already
+ * collected and procdesc_reap() was already called.
+ */
+ sx_xunlock(&proctree_lock);
+ } else if (p->p_state == PRS_ZOMBIE) {
/*
* If the process is already dead and just awaiting reaping,
* do that now. This will release the process's reference to
* the process descriptor when it calls back into
* procdesc_reap().
*/
+ PROC_LOCK(p);
PROC_SLOCK(p);
proc_reap(curthread, p, NULL, 0, NULL);
} else {
@@ -376,6 +383,7 @@ procdesc_close(struct file *fp, struct thread *td)
* process from its descriptor so that its exit status will
* be reported normally.
*/
+ PROC_LOCK(p);
pd->pd_proc = NULL;
p->p_procdesc = NULL;
procdesc_free(pd);
OpenPOWER on IntegriCloud