FD's 0..2 and suid/sgid procs (Was: Crash a redhat 5.1 linux box)

From: Joe Zbiciak (j-zbiciak1at_private)
Date: Wed Jul 29 1998 - 17:02:33 PDT

  • Next message: Peter Jeremy: "Re: A way to prevent buffer overflow exploits?"

    'Zachary Amsden' said previously:
    |
    | Bug description:  the dumpreg utility included
    | with redhat 5.1 can cause kernel crashes.  The
    | reasons is that it opens /dev/mem with O_RDWR
    | access and blindly prints its output to fd 1.
    
    It's worth noting that the fdalloc patch for OpenBSD that Theo de Raadt
    briefly mentioned addresses this issue by forcing suid/sgid programs to
    have open files (specifically /dev/null) on fd's 0..2 so that things
    like printf() and fprintf(stderr,...) don't cause the sort of problem
    you're highlighting.  (see http://www.openbsd.org/security.html and
    click on "Jul 2, 1998: setuid and setgid processes should not be
    executed with fd slots 0, 1, or 2 free. (patch included).")
    
    Alan Cox actually is the first person who highlighted this sort of
    vulnerability to me.  Does anyone know if the OpenBSD approach is
    sufficient for avoiding these sorts of attacks (eg. feeding an
    suid/sgid program bogus stdin/stdout/stderr)?  Also, is a similar patch
    in the works for Linux?  (I ask, because I'm a Linux user myself.)
    And, is there any overwhelming reason why you wouldn't make the same
    guarantee that fd's 0..2 are open for all processes, rather than just
    suid/sgid processes?
    
    
    On an alternate note, what are the security implications of opening
    "/dev/null" exactly by name?  (I can't profess to be an expert in
    reading OpenBSD kernel source-code, but that appears to be what the
    patch does for fd's 0..2 that aren't yet open.)  Pertinent bit of the
    patch:
    
                   /*
                    * XXX For setuid processes, attempt to ensure that
                    * stdin, stdout, and stderr are already allocated.
                    * We do not want userland to accidentally allocate
                    * descriptors in this range which has implied meaning
                    * to libc.
                    */
                   for (i = 0; i < 3; i++) {
                           extern struct fileops vnops;
                           struct nameidata nd;
                           struct file *fp;
                           int indx;
    
                           if (p->p_fd->fd_ofiles[i] == NULL) {
                                   if ((error = falloc(p, &fp, &indx)) != 0)
                                           continue;
                                   NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE,
                                       "/dev/null", p);
                                   if ((error = vn_open(&nd, FREAD, 0)) != 0) {
                                           ffree(fp);
                                           p->p_fd->fd_ofiles[indx] = NULL;
                                           break;
                                   }
                                   fp->f_flag = FREAD;
                                   fp->f_type = DTYPE_VNODE;
                                   fp->f_ops = &vnops;
                                   fp->f_data = (caddr_t)nd.ni_vp;
                                   VOP_UNLOCK(nd.ni_vp, 0, p);
                           }
                   }
    
    
    
    
    
    Regards,
    
    --Joe
    
    --
      +------- Joseph Zbiciak ------+
      |- - - j+zbiciak1at_private - - -|  "The truth of a proposition has nothing
      | -Texas Instruments, Dallas- |   to do with its credibility.
      |- - #include <disclaim.h> - -|   And vice versa."       -- Lazarus Long
      +-----------------------------+
    
      (change + to - in email -- I avoiding Spam!)
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:10:34 PDT