Bugtraq mailing list archives

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


From: j-zbiciak1 () ti com (Joe Zbiciak)
Date: Wed, 29 Jul 1998 19:02:33 -0500


'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+zbiciak1 () ti com - - -|  "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!)



Current thread: