--- sys/kern/kern_descrip.c Fri Dec 14 13:26:24 2001 +++ sys/kern/kern_descrip.c Mon Apr 22 16:38:20 2002 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1183,6 +1184,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); } /* diff --exclude=CVS -ruN sys/kern/kern_exec.c sys/kern/kern_exec.c --- sys/kern/kern_exec.c Tue Jan 22 11:22:59 2002 +++ sys/kern/kern_exec.c Mon Jul 29 22:21:49 2002 @@ -328,6 +328,12 @@ vrele(vtmp); } } + /* Close any file descriptors 0..2 that reference procfs */ + setugidsafety(p); + /* Make sure file descriptors 0..2 are in use. */ + error = fdcheckstd(p); + if (error != 0) + goto exec_fail_dealloc; /* * Set the new credentials. */ @@ -336,7 +342,6 @@ change_euid(p, attr.va_uid); if (attr.va_mode & VSGID) p->p_ucred->cr_gid = attr.va_gid; - setugidsafety(p); } else { if (p->p_ucred->cr_uid == p->p_cred->p_ruid && p->p_ucred->cr_gid == p->p_cred->p_rgid) diff --exclude=CVS -ruN sys/sys/filedesc.h sys/sys/filedesc.h --- sys/sys/filedesc.h Sat Nov 25 20:30:08 2000 +++ sys/sys/filedesc.h Sun Apr 21 08:08:57 2002 @@ -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 *));