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
This commit is contained in:
Pawel Jakub Dawidek 2012-09-01 11:21:56 +00:00
parent 98e695d7fd
commit 707641ec28
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=239989

View File

@ -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);