Messages in this thread Patch in this message | | | Date | Sat, 30 Jan 1999 12:16:45 +0100 (MET) | From | Richard Guenther <> | Subject | Memory/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; }
| |