kern/142082: [patch] [panic] linuxulator: getppid: use after free

Gleb Kurtsou gleb.kurtsou at gmail.com
Mon Dec 28 14:20:03 UTC 2009


The following reply was made to PR kern/142082; it has been noted by GNATS.

From: Gleb Kurtsou <gleb.kurtsou at gmail.com>
To: Lucius Windschuh <lwindschuh at googlemail.com>
Cc: bug-followup at freebsd.org
Subject: Re: kern/142082: [patch] [panic] linuxulator: getppid: use after
 free
Date: Mon, 28 Dec 2009 16:12:51 +0200

 --9jxsPFA5p3P2qPhR
 Content-Type: text/plain; charset=utf-8
 Content-Disposition: inline
 
 On (28/12/2009 13:39), Lucius Windschuh wrote:
 > Hi Gleb,
 > I have a question on the proposed patch: Is this code path which you
 > extend by querying and setting p->p_emuldata protected by a lock which
 > I don't see and which prevents two threads from running
 > linux_proc_exit and linux_getppid in parallel?
 > 
 > Else, I think that we have a short time window after free()ing em in
 > linux_proc_exit and before clearing p->p_emuldata, where it looks like
 > the emuldata is valid, but already freed. This would cause a panic or
 > undefined bahaviour, again. Although the time frame is very small.
 Thanks, for a point. I've updated the patch a bit to set p_emuldata=NULL
 with PROC_LOCK held. That should fix this particular race.
 
 But there's still a race documented in linux_proc_exec (XXX comment):
 p_emuldata can be dereferenced after being set to NULL. That's what
 p_emuldata check is for. Not sure about the rest of the code though,
 getppid is a bit special here.
 
 > 
 > Regards
 > 
 > Lucius
 
 --9jxsPFA5p3P2qPhR
 Content-Type: text/plain; charset=utf-8
 Content-Disposition: attachment; filename="linuxulator-getppid-use_after_free.patch-2.txt"
 
 commit 09d5cc62f82b251eaf2c3548a026ed09c10cbbae
 Author: Gleb Kurtsou <gleb.kurtsou at gmail.com>
 Date:   Mon Dec 28 16:08:44 2009 +0200
 
     linuxulator: getppid: fix use after free panic
 
 diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
 index dc81553..5086047 100644
 --- a/sys/compat/linux/linux_emul.c
 +++ b/sys/compat/linux/linux_emul.c
 @@ -202,6 +202,9 @@ linux_proc_exit(void *arg __unused, struct proc *p)
  
  		error = copyout(&null, child_clear_tid, sizeof(null));
  		if (error) {
 +			PROC_LOCK(p);
 +			p->p_emuldata = NULL;
 +			PROC_UNLOCK(p);
  			free(em, M_LINUX);
  			return;
  		}
 @@ -223,6 +226,9 @@ linux_proc_exit(void *arg __unused, struct proc *p)
  	}
  
  	/* clean the stuff up */
 +	PROC_LOCK(p);
 +	p->p_emuldata = NULL;
 +	PROC_UNLOCK(p);
  	free(em, M_LINUX);
  
  	/* this is a little weird but rewritten from exit1() */
 @@ -267,17 +273,17 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
   		 * time so some other process might reference it and try to
   		 * access its p->p_emuldata and panicing on a NULL reference.
  		 */
 +
 +		PROC_LOCK(p);
  		em = em_find(p, EMUL_DONTLOCK);
 +		p->p_emuldata = NULL;
 +		PROC_UNLOCK(p);
  
  		KASSERT(em != NULL, ("proc_exec: emuldata not found.\n"));
  
  		EMUL_SHARED_WLOCK(&emul_shared_lock);
  		LIST_REMOVE(em, threads);
  
 -		PROC_LOCK(p);
 -		p->p_emuldata = NULL;
 -		PROC_UNLOCK(p);
 -
  		em->shared->refs--;
  		if (em->shared->refs == 0) {
  			EMUL_SHARED_WUNLOCK(&emul_shared_lock);
 diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
 index 1d5eaf8..bd8be89 100644
 --- a/sys/compat/linux/linux_misc.c
 +++ b/sys/compat/linux/linux_misc.c
 @@ -1581,10 +1581,8 @@ linux_getppid(struct thread *td, struct linux_getppid_args *args)
  	PROC_UNLOCK(p);
  
  	/* if its also linux process */
 -	if (pp->p_sysent == &elf_linux_sysvec) {
 -		em = em_find(pp, EMUL_DONTLOCK);
 -		KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
 -
 +	if (pp->p_sysent == &elf_linux_sysvec &&
 +	    (em = em_find(pp, EMUL_DONTLOCK)) != NULL) {
  		td->td_retval[0] = em->shared->group_pid;
  	} else
  		td->td_retval[0] = pp->p_pid;
 
 --9jxsPFA5p3P2qPhR--


More information about the freebsd-emulation mailing list