Index: sys/sys/filedesc.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/filedesc.h,v
retrieving revision 1.19.2.3
diff -u -r1.19.2.3 filedesc.h
--- sys/sys/filedesc.h	2000/11/26 02:30:08	1.19.2.3
+++ sys/sys/filedesc.h	2002/04/19 14:25:39
@@ -142,6 +142,7 @@
 void	fdfree __P((struct proc *p));
 int	closef __P((struct file *fp,struct proc *p));
 void	fdcloseexec __P((struct proc *p));
+int	fdcheckstd __P((struct proc *p));
 struct	file *holdfp __P((struct filedesc* fdp, int fd, int flag));
 int	getvnode __P((struct filedesc *fdp, int fd, struct file **fpp));
 int	fdissequential __P((struct file *));
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.107.2.13
diff -u -r1.107.2.13 kern_exec.c
--- sys/kern/kern_exec.c	2002/01/22 17:22:59	1.107.2.13
+++ sys/kern/kern_exec.c	2002/04/19 14:25:39
@@ -328,6 +328,10 @@
 				vrele(vtmp);
 			}
 		}
+		/* Make sure file descriptors 0..2 are in use. */
+		error = fdcheckstd(p);
+		if (error != 0)
+			goto exec_fail_dealloc;
 		/*
 		 * Set the new credentials.
 		 */
Index: sys/kern/kern_descrip.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.81.2.10
diff -u -r1.81.2.10 kern_descrip.c
--- sys/kern/kern_descrip.c	2002/02/16 09:23:37	1.81.2.10
+++ sys/kern/kern_descrip.c	2002/04/19 14:25:39
@@ -50,6 +50,7 @@
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 #include <sys/proc.h>
+#include <sys/namei.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/filio.h>
@@ -1181,6 +1182,63 @@
 	}
 	while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
 		fdp->fd_lastfile--;
+}
+
+/*
+ * It is unsafe for set[ug]id processes to be started with file
+ * descriptors 0..2 closed, as these descriptors are given implicit
+ * significance in the Standard C library.  fdcheckstd() will create a
+ * descriptor referencing /dev/null for each of stdin, stdout, and
+ * stderr that is not already open.
+ */
+int
+fdcheckstd(p)
+       struct proc *p;
+{
+       struct nameidata nd;
+       struct filedesc *fdp;
+       struct file *fp;
+       register_t retval;
+       int fd, i, error, flags, devnull;
+
+       fdp = p->p_fd;
+       if (fdp == NULL)
+               return (0);
+       devnull = -1;
+       error = 0;
+       for (i = 0; i < 3; i++) {
+               if (fdp->fd_ofiles[i] != NULL)
+                       continue;
+               if (devnull < 0) {
+                       error = falloc(p, &fp, &fd);
+                       if (error != 0)
+                               break;
+                       NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "/dev/null",
+                           p);
+                       flags = FREAD | FWRITE;
+                       error = vn_open(&nd, flags, 0);
+                       if (error != 0) {
+                               fdp->fd_ofiles[i] = NULL;
+                               fdrop(fp, p);
+                               break;
+                       }
+                       NDFREE(&nd, NDF_ONLY_PNBUF);
+                       fp->f_data = (caddr_t)nd.ni_vp;
+                       fp->f_flag = flags;
+                       fp->f_ops = &vnops;
+                       fp->f_type = DTYPE_VNODE;
+                       VOP_UNLOCK(nd.ni_vp, 0, p);
+                       devnull = fd;
+               } else {
+                       error = fdalloc(p, 0, &fd);
+                       if (error != 0)
+                               break;
+                       error = do_dup(fdp, devnull, fd, &retval, p);
+                       if (error != 0)
+                               break;
+               }
+       }
+       return (error);
 }
 
 /*
