lkml.org 
[lkml]   [1999]   [Jan]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectMemory/Filesystem corruption caused by bttv SOLVED! [PATCH]
Hi Alan, Linus!

If you experienced random oopses, random filesystem corruption or
the like and you are by any chance using a bttv card you may want
to apply the patch attached to get rid of the problems. (I dont
know, if this is a brown paperbag one - for me it is :))

Now, the reason for the problems is that the bttv driver deallocates
the grabbing buffer at device close() time which is bad, as the
bttv card seems to go on with grabbing (proved by the attached program).
Also the memory mappings stay intact, so after the close() you have
access to memory you dont own anymore -> security hole (proved by
the attached program).

The simple fix is to move the buffer freeing code to bttv_release
(i.e. to driver closedown time). The downside is of course that
the buffer may now never be deallocated.

The attached program does prove the security hole by just opening
/dev/video0, mmapping the memory and closing /dev/video0. After
some time you can notice changes in mmapped memory -> proved.
The attached program also proves the memory corruption bug. Just
issue while true; do ./bttvtest 1; done and do some memory allocating
things (f.i. find /). BUT BEWARE! THIS WILL USUALLY CAUSE OOPSES,
MEMORY AND FILESYSTEM CORRUPTION! (this will happen after only a few
seconds) so, unmount/remount ro all your filesystems! (Alt-Sysrq-u is
your friend).

Richard.

PS: bttv and memory/filesystem corruption seems to be a quite regular
pattern these days - I wonder how many of these strange oops
reports will go away by applying the patch...

PS2: if you are not convinced that this will be a problem in real
life (without this sort of stress test program) I can tell you
it does for me. Just think of developing a grabbing program -
you will likely start/stop it many times and after a few
hours you will be convinced...

--
Richard Guenther <richard.guenther@student.uni-tuebingen.de>
PGP: 2E829319 - 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57
WWW: http://www.anatom.uni-tuebingen.de/~richi/
--- linux-2.2.0/drivers/char/bttv.c.original Sat Jan 30 12:14:34 1999
+++ linux-2.2.0/drivers/char/bttv.c Sat Jan 30 12:34:35 1999
@@ -1535,7 +1535,7 @@
users+=bttvs[i].user;
if (users==1)
find_vga();
- btv->fbuffer=NULL;
+ /* btv->fbuffer=NULL; */
if (!btv->fbuffer)
btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
if (!btv->fbuffer)
@@ -1560,9 +1560,9 @@
btv->cap&=~3;
bt848_set_risc_jmps(btv);

- if(btv->fbuffer)
+/* if(btv->fbuffer)
rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
- btv->fbuffer=0;
+ btv->fbuffer=0; */
MOD_DEC_USE_COUNT;
}

@@ -3712,6 +3712,9 @@
if (btv->vbibuf)
vfree((void *) btv->vbibuf);

+ if(btv->fbuffer)
+ rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
+ btv->fbuffer=0;

free_irq(btv->irq,btv);
DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include "videodev.h"

#define BTTV_MAX_FBUF 0x151000

int access_mem(char *mem, int size)
{
int i, retval=0;
volatile int j;

for (i=0; i<size; i++)
if ((j = ((volatile char *)mem)[i]) != 0)
return retval = 1;
return retval;
}

int main(int argc, char **argv)
{
int fd, cnt, g0, g1, which;
char *map;
struct video_mmap vmap;
struct timeval start, stop;

if (argc < 2) {
fprintf(stderr, "Usage: %s which\n", argv[0]);
exit(0);
}
which = atoi(argv[1]);
if (which != 0 && which != 1)
exit(-1);

if ((fd = open("/dev/video0", O_RDWR)) == -1) {
perror("open /dev/video0");
goto _out;
}

map = mmap(0, BTTV_MAX_FBUF*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if ((int)map == -1) {
perror("mmap");
goto _close_vid;
}
memset(map, 0, BTTV_MAX_FBUF*2);

vmap.height = 576;
vmap.width = 768;
vmap.format = VIDEO_PALETTE_RGB24;


if (which == 0) {
/*
* show security flaw (read mem after close)
* ideally, we could loop over open(), mmap() and close()
* and get just every mem mapped to our process after
* some time??
*/
if (close(fd) == -1)
perror("close");
cnt = 0;
while (1) {
if (access_mem(map, BTTV_MAX_FBUF*2)) {
fprintf(stderr, "ARGH! mem modified after %i runs!\n", cnt);
break;
}
cnt++;
}

} else if (which == 1) {
/*
* show memory corruption!! (be careful!)
* with CORRUPT defined you should be able to crash your
* machine with starting bttvtest for a few times...
*/
#define CORRUPT
gettimeofday(&start, NULL);
vmap.frame = 0;
if (ioctl(fd, VIDIOCMCAPTURE, &vmap) == -1)
perror("VIDIOCMCAPTURE");
vmap.frame = 1;
if (ioctl(fd, VIDIOCMCAPTURE, &vmap) == -1)
perror("VIDIOCMCAPTURE");
if (close(fd) == -1)
perror("close");
gettimeofday(&stop, NULL);

#ifndef CORRUPT
/* here, grabbing should just have started or never start */
g0 = access_mem(map, BTTV_MAX_FBUF);
g1 = access_mem(map+BTTV_MAX_FBUF, BTTV_MAX_FBUF);
#endif

fprintf(stderr, "2 times VIDIOCMCAPTURE + close lasts %i us\n",
(stop.tv_sec-start.tv_sec)*1000000
+ (stop.tv_usec-start.tv_usec));
#ifndef CORRUPT
usleep(2*40000);

/* here grabbing should be finished */
if (g1 != access_mem(map+BTTV_MAX_FBUF, BTTV_MAX_FBUF))
fprintf(stderr, "Grabbing to frame 1 started after close!??\n");
if (g0 != access_mem(map, BTTV_MAX_FBUF))
fprintf(stderr, "Grabbing to frame 0 started after close!??\n");
#endif
}

_munmap_fbuf:
if (munmap(map, BTTV_MAX_FBUF*2) == -1)
perror("munmap");
_close_vid:
if (close(fd) == -1)
perror("close");
_out:
return 0;
}


\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.020 / U:0.620 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site