From fcc5ad0935b7186f4b02cdb9e21265c4b22f7bdc Mon Sep 17 00:00:00 2001 From: nectar Date: Fri, 19 Apr 2002 00:45:29 +0000 Subject: [PATCH] When exec'ing a set[ug]id program, make sure that the stdio file descriptors (0, 1, 2) are allocated by opening /dev/null for any which are not already open. Reviewed by: alfred, phk MFC after: 2 days --- sys/kern/kern_descrip.c | 65 +++++++++++++++++++++++++++++++++++++++++ sys/kern/kern_exec.c | 4 +++ sys/sys/filedesc.h | 1 + 3 files changed, 70 insertions(+) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 136bd61db2f2..04764939c67c 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -1497,6 +1498,70 @@ fdcloseexec(td) FILEDESC_UNLOCK(fdp); } +/* + * 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(td) + struct thread *td; +{ + struct nameidata nd; + struct filedesc *fdp; + struct file *fp; + register_t retval; + int fd, i, error, flags, devnull; + + fdp = td->td_proc->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) { + FILEDESC_LOCK(fdp); + error = falloc(td, &fp, &fd); + FILEDESC_UNLOCK(fdp); + if (error != 0) + break; + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "/dev/null", + td); + flags = FREAD | FWRITE; + error = vn_open(&nd, &flags, 0); + if (error != 0) { + FILEDESC_LOCK(fdp); + fdp->fd_ofiles[i] = NULL; + FILEDESC_UNLOCK(fdp); + fdrop(fp, td); + 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, td); + devnull = fd; + } else { + FILEDESC_LOCK(fdp); + error = fdalloc(td, 0, &fd); + if (error != 0) { + FILEDESC_UNLOCK(fdp); + break; + } + error = do_dup(fdp, devnull, fd, &retval, td); + if (error != 0) + break; + } + } + return (error); +} + /* * Internal form of close. * Decrement reference count on file structure. diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 1b32699722c9..af4edaed892a 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -368,6 +368,10 @@ execve(td, uap) vrele(vtmp); } } + /* Make sure file descriptors 0..2 are in use. */ + error = fdcheckstd(td); + if (error != 0) + goto exec_fail_dealloc; /* * Set the new credentials. */ diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 160bda2d039b..d2d108c74396 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -147,6 +147,7 @@ int falloc(struct thread *p, struct file **resultfp, int *resultfd); int fdalloc(struct thread *p, int want, int *result); int fdavail(struct thread *td, int n); void fdcloseexec(struct thread *td); +int fdcheckstd(struct thread *td); struct filedesc *fdcopy(struct thread *td); void fdfree(struct thread *td); struct filedesc *fdinit(struct thread *td);