diff options
author | pjd <pjd@FreeBSD.org> | 2012-09-01 11:21:56 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2012-09-01 11:21:56 +0000 |
commit | 09be0bbef152583f8fa989d7f9c3a7cd76b50d2a (patch) | |
tree | fd78400a68bac8d6f92a7aac54b9879ca9b1a260 /sys/kern/sys_procdesc.c | |
parent | 79fa964314bead3dd00a1a411724f8446667a8bc (diff) | |
download | FreeBSD-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.c | 12 |
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); |