[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-video
Subject:    Memory/Filesystem corruption caused by bttv SOLVED! [PATCH]
From:       Richard Guenther <zxmpm11 () student ! uni-tuebingen ! de>
Date:       1999-01-30 11:16:45
[Download RAW message or body]

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/

["bttv-patch" (TEXT/PLAIN)]

--- 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));

["bttvtest.c" (TEXT/PLAIN)]

#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;
}



-- 
         To unsubscribe: mail video4linux-list-request@redhat.com with 
                       "unsubscribe" as the Subject.


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic