Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Dec 2009 20:02:05 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/142082: [patch] [panic] linuxulator: getppid: use after free
Message-ID:  <200912272002.nBRK25I2016747@www.freebsd.org>
Resent-Message-ID: <200912272010.nBRKA2RZ022313@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         142082
>Category:       kern
>Synopsis:       [patch] [panic] linuxulator: getppid: use after free
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Dec 27 20:10:01 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Gleb Kurtsou
>Release:        
>Organization:
>Environment:
FreeBSD tops 9.0-CURRENT FreeBSD 9.0-CURRENT #0 r199870+5a33f3d: Thu Dec 24 08:46:34 EET 2009     root@tops:/usr/obj/usr/freebsd-src/local/sys/TOPS  amd64
>Description:
Process that caused panic was skype. I've seen the panic only once. Looks like one threads calls exec while another calls getppid. emuldata is getting freed by exec handler, but pointer to it remains active for a small period of time (proc struct gets unlocked). 

Unread portion of the kernel message buffer:

Fatal trap 9: general protection fault while in kernel mode
cpuid = 0; apic id = 00
instruction pointer	= 0x20:0xffffffff8053cffe
stack pointer	        = 0x28:0xffffff80e605eb00
frame pointer	        = 0x28:0xffffff80e605eb30
code segment		= base 0x0, limit 0xfffff, type 0x1b
			= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= 15730 (bash)
trap number		= 9
panic: general protection fault
cpuid = 0
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2a
panic() at panic+0x17d
trap_fatal() at trap_fatal+0x2ad
trap() at trap+0xfa
calltrap() at calltrap+0x8
--- trap 0x9, rip = 0xffffffff8053cffe, rsp = 0xffffff80e605eb00, rbp = 0xffffff80e605eb30 ---
linux_getppid() at linux_getppid+0x141
ia32_syscall() at ia32_syscall+0x15f
Xint0x80_syscall() at Xint0x80_syscall+0x95
--- syscall (64, Linux ELF32, linux_getppid), rip = 0x281e1777, rsp = 0xffffd5ec, rbp = 0xffffd618 ---
Uptime: 2h26m34s
Physical memory: 3047 MB
Dumping 2645 MB: 2630 2614 (CTRL-C to abort)  (CTRL-C to abort)  (CTRL-C to abort)  (CTRL-C to abort)  2598 2582 2566 2550 2534 2518 2502 2486 2470 2454 2438 2422 2406 2390 2374 2358 2342 2326 2310 2294 2278 2262 2246 2230 2214 2198 2182 2166 2150 2134 2118 2102 2086 2070 2054 2038 2022 2006 1990 1974 1958 1942 1926 1910 1894 1878 1862 1846 1830 1814 1798 1782 1766 1750 1734 1718 1702 1686 1670 1654 1638 1622 1606 1590 1574 1558 1542 1526 1510 1494 1478 1462 1446 1430 1414 1398 1382 1366 1350 1334 1318 1302 1286 1270 1254 1238 1222 1206 1190 1174 1158 1142 1126 1110 1094 1078 1062 1046 1030 1014 998 982 966 950 934 918 902 886 870 854 838 822 806 790 774 758 742 726 710 694 678 662 646 630 614 598 582 566 550 534 518 502 486 470 454 438 422 406 390 374 358 342 326 310 294 278 262 246 230 214 198 182 166 150 134 118 102 86 70 54 38 22 6

Reading symbols from /boot/kernel/zfs.ko...Reading symbols from /.bootfs/boot/kernel/zfs.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/zfs.ko
Reading symbols from /boot/kernel/opensolaris.ko...Reading symbols from /.bootfs/boot/kernel/opensolaris.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/opensolaris.ko
Reading symbols from /boot/modules/nvidia.ko...done.
Loaded symbols for /boot/modules/nvidia.ko
Reading symbols from /boot/kernel/linprocfs.ko...Reading symbols from /.bootfs/boot/kernel/linprocfs.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/linprocfs.ko
Reading symbols from /boot/kernel/tmpfs.ko...Reading symbols from /.bootfs/boot/kernel/tmpfs.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/tmpfs.ko
Reading symbols from /boot/kernel/pf.ko...Reading symbols from /.bootfs/boot/kernel/pf.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/pf.ko
Reading symbols from /boot/kernel/pefs.ko...Reading symbols from /.bootfs/boot/kernel/pefs.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/pefs.ko
#0  doadump () at pcpu.h:223
223	pcpu.h: No such file or directory.
	in pcpu.h
(kgdb) bt
#0  doadump () at pcpu.h:223
#1  0xffffffff803273fd in boot (howto=260) at /usr/freebsd-src/local/sys/kern/kern_shutdown.c:416
#2  0xffffffff8032787b in panic (fmt=Variable "fmt" is not available.
) at /usr/freebsd-src/local/sys/kern/kern_shutdown.c:579
#3  0xffffffff80504403 in trap_fatal (frame=0x9, eva=Variable "eva" is not available.
) at /usr/freebsd-src/local/sys/amd64/amd64/trap.c:858
#4  0xffffffff80504d5c in trap (frame=0xffffff80e605ea50) at /usr/freebsd-src/local/sys/amd64/amd64/trap.c:647
#5  0xffffffff804ebe93 in calltrap () at /usr/freebsd-src/local/sys/amd64/amd64/exception.S:224
#6  0xffffffff8053cffe in linux_getppid (td=0xffffff0005dafa80, args=Variable "args" is not available.
)
    at /usr/freebsd-src/local/sys/compat/linux/linux_misc.c:1588
#7  0xffffffff80527bb2 in ia32_syscall (frame=0xffffff80e605ec80)
    at /usr/freebsd-src/local/sys/amd64/ia32/ia32_syscall.c:182
#8  0xffffffff804ec395 in Xint0x80_syscall () at ia32_exception.S:72
#9  0x00000000281e1777 in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb) fr 6
#6  0xffffffff8053cffe in linux_getppid (td=0xffffff0005dafa80, args=Variable "args" is not available.
)
    at /usr/freebsd-src/local/sys/compat/linux/linux_misc.c:1588
warning: Source file is more recent than executable.

1588			td->td_retval[0] = em->shared->group_pid;

(kgdb) l
1583		/* if its also linux process */
1584		if (pp->p_sysent == &elf_linux_sysvec) {
1585			em = em_find(pp, EMUL_DONTLOCK);
1586			KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
1587	
1588			td->td_retval[0] = em->shared->group_pid;
1589		} else
1590			td->td_retval[0] = pp->p_pid;
1591	
1592		PROC_UNLOCK(pp);

(kgdb) p *em
$1 = {pid = -559038242, child_set_tid = 0xdeadc0dedeadc0de, child_clear_tid = 0xdeadc0dedeadc0de, 
  shared = 0xdeadc0dedeadc0de, pdeath_signal = -559038242, used_requeue = -559038242, 
  robust_futexes = 0xdeadc0dedeadc0de, threads = {le_next = 0xdeadc0dedeadc0de, le_prev = 0xffffffff80a3c500}}

(kgdb) p (struct linux_emuldata *)p->p_emul
There is no member named p_emul.

(kgdb) p (struct linux_emuldata *)p->p_emuldata 
$2 = (struct linux_emuldata *) 0xffffff003e8a8240

(kgdb) p (struct linux_emuldata *)p->p_emuldata
$3 = {pid = 15730, child_set_tid = 0x0, child_clear_tid = 0x0, shared = 0xffffff005ed3a160, pdeath_signal = 0, 
  used_requeue = 0, robust_futexes = 0x0, threads = {le_next = 0x0, le_prev = 0xffffff005ed3a168}}

(kgdb) p *(struct linux_emuldata *)p->p_emuldata
$4 = {pid = -559038242, child_set_tid = 0xdeadc0dedeadc0de, child_clear_tid = 0xdeadc0dedeadc0de, 
  shared = 0xdeadc0dedeadc0de, pdeath_signal = -559038242, used_requeue = -559038242, 
  robust_futexes = 0xdeadc0dedeadc0de, threads = {le_next = 0xdeadc0dedeadc0de, le_prev = 0xffffffff80a3c500}}

(kgdb) p/x p->p_flag
$5 = 0x10004000
          ^^^ P_EXEC

(kgdb) p/x pp->p_flag
$6 = 0x10002000
          ^^^ P_WEXIT



>How-To-Repeat:

>Fix:
Patch set p->emuldata=NULL after free and checks p->emuldata!=NULL in getppid instead of panicing.

Patch attached with submission follows:

diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
index dc81553..88c0064 100644
--- a/sys/compat/linux/linux_emul.c
+++ b/sys/compat/linux/linux_emul.c
@@ -203,6 +203,7 @@ linux_proc_exit(void *arg __unused, struct proc *p)
 		error = copyout(&null, child_clear_tid, sizeof(null));
 		if (error) {
 			free(em, M_LINUX);
+			p->p_emuldata = NULL;
 			return;
 		}
 
@@ -224,6 +225,7 @@ linux_proc_exit(void *arg __unused, struct proc *p)
 
 	/* clean the stuff up */
 	free(em, M_LINUX);
+	p->p_emuldata = NULL;
 
 	/* this is a little weird but rewritten from exit1() */
 	sx_xlock(&proctree_lock);
@@ -286,6 +288,7 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
 			EMUL_SHARED_WUNLOCK(&emul_shared_lock);
 
 		free(em, M_LINUX);
+		p->p_emuldata = NULL;
 	}
 }
 
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;


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912272002.nBRK25I2016747>