diff options
author | jhb <jhb@FreeBSD.org> | 2002-07-13 04:07:12 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2002-07-13 04:07:12 +0000 |
commit | 11a8bfb92369446efa4603ca160d80657e9a4f67 (patch) | |
tree | 2e3f9a69f51eb683e7a7967b23ce4aa7ed122eef | |
parent | eefbe93dbbf7956d09b58f82fabed0c4c58864de (diff) | |
download | FreeBSD-src-11a8bfb92369446efa4603ca160d80657e9a4f67.zip FreeBSD-src-11a8bfb92369446efa4603ca160d80657e9a4f67.tar.gz |
- Change chroot_refuse_vdir_fds() to require that the passed in struct
filedesc is already locked rather than having chroot() unlock the
filedesc so chroot_refuse_vdir_fds() can immediately relock it.
- Reorder chroot() a bitso that we do the namei lookup before checking
the process's struct filedesc. This closes at least one potential race
and allows us to only acquire the filedsec lock once in chroot().
- Push down Giant slightly into chroot().
-rw-r--r-- | sys/kern/vfs_extattr.c | 34 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 34 |
2 files changed, 36 insertions, 32 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 17da270..69159e7 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -450,20 +450,17 @@ chroot_refuse_vdir_fds(fdp) struct file *fp; int fd; - FILEDESC_LOCK(fdp); + FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); for (fd = 0; fd < fdp->fd_nfiles ; fd++) { fp = fget_locked(fdp, fd); if (fp == NULL) continue; if (fp->f_type == DTYPE_VNODE) { vp = (struct vnode *)fp->f_data; - if (vp->v_type == VDIR) { - FILEDESC_UNLOCK(fdp); + if (vp->v_type == VDIR) return (EPERM); - } } } - FILEDESC_UNLOCK(fdp); return (0); } @@ -504,21 +501,18 @@ chroot(td, uap) error = suser_cred(td->td_ucred, PRISON_ROOT); if (error) return (error); - FILEDESC_LOCK(fdp); - if (chroot_allow_open_directories == 0 || - (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { - FILEDESC_UNLOCK(fdp); - error = chroot_refuse_vdir_fds(fdp); - } else - FILEDESC_UNLOCK(fdp); - if (error) - return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), td); + mtx_lock(&Giant); if ((error = change_dir(&nd, td)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); + goto error; FILEDESC_LOCK(fdp); + if (chroot_allow_open_directories == 0 || + (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { + error = chroot_refuse_vdir_fds(fdp); + if (error) + goto error_unlock; + } vp = fdp->fd_rdir; fdp->fd_rdir = nd.ni_vp; if (!fdp->fd_jdir) { @@ -526,8 +520,16 @@ chroot(td, uap) VREF(fdp->fd_jdir); } FILEDESC_UNLOCK(fdp); + NDFREE(&nd, NDF_ONLY_PNBUF); vrele(vp); + mtx_unlock(&Giant); return (0); +error_unlock: + FILEDESC_UNLOCK(fdp); +error: + mtx_unlock(&Giant); + NDFREE(&nd, 0); + return (error); } /* diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 17da270..69159e7 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -450,20 +450,17 @@ chroot_refuse_vdir_fds(fdp) struct file *fp; int fd; - FILEDESC_LOCK(fdp); + FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); for (fd = 0; fd < fdp->fd_nfiles ; fd++) { fp = fget_locked(fdp, fd); if (fp == NULL) continue; if (fp->f_type == DTYPE_VNODE) { vp = (struct vnode *)fp->f_data; - if (vp->v_type == VDIR) { - FILEDESC_UNLOCK(fdp); + if (vp->v_type == VDIR) return (EPERM); - } } } - FILEDESC_UNLOCK(fdp); return (0); } @@ -504,21 +501,18 @@ chroot(td, uap) error = suser_cred(td->td_ucred, PRISON_ROOT); if (error) return (error); - FILEDESC_LOCK(fdp); - if (chroot_allow_open_directories == 0 || - (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { - FILEDESC_UNLOCK(fdp); - error = chroot_refuse_vdir_fds(fdp); - } else - FILEDESC_UNLOCK(fdp); - if (error) - return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), td); + mtx_lock(&Giant); if ((error = change_dir(&nd, td)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); + goto error; FILEDESC_LOCK(fdp); + if (chroot_allow_open_directories == 0 || + (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { + error = chroot_refuse_vdir_fds(fdp); + if (error) + goto error_unlock; + } vp = fdp->fd_rdir; fdp->fd_rdir = nd.ni_vp; if (!fdp->fd_jdir) { @@ -526,8 +520,16 @@ chroot(td, uap) VREF(fdp->fd_jdir); } FILEDESC_UNLOCK(fdp); + NDFREE(&nd, NDF_ONLY_PNBUF); vrele(vp); + mtx_unlock(&Giant); return (0); +error_unlock: + FILEDESC_UNLOCK(fdp); +error: + mtx_unlock(&Giant); + NDFREE(&nd, 0); + return (error); } /* |