Bug 142082 - [patch] [panic] linuxulator: getppid: use after free
Summary: [patch] [panic] linuxulator: getppid: use after free
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 1.0-CURRENT
Hardware: Any Any
: Normal Affects Only Me
Assignee: Dmitry Chagin
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-12-27 20:10 UTC by Gleb Kurtsou
Modified: 2016-01-09 21:23 UTC (History)
0 users

See Also:


Attachments
file.diff (1.44 KB, patch)
2009-12-27 20:10 UTC, Gleb Kurtsou
no flags Details | Diff
linuxulator-getppid-use_after_free.patch-2.txt (2.09 KB, text/plain; charset=utf-8)
2009-12-28 14:12 UTC, Gleb Kurtsou
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Gleb Kurtsou freebsd_committer freebsd_triage 2009-12-27 20:10:01 UTC
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 rx0, 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

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

Patch attached with submission follows:
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2009-12-27 22:58:50 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-emulation

Over to maintainer(s).
Comment 2 Gleb Kurtsou 2009-12-28 14:12:51 UTC
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
Comment 3 Dmitry Chagin freebsd_committer freebsd_triage 2010-07-05 22:43:12 UTC
Responsible Changed
From-To: freebsd-emulation->dchagin


Grab.
Comment 4 Dmitry Chagin freebsd_committer freebsd_triage 2016-01-09 21:23:27 UTC
so, fix of that panic was a primary goal of a lemul project. lemul merged to the stable/10. I think PR may be closed. ugh