From owner-svn-src-all@freebsd.org Sat Jul 11 16:19:16 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 4259699916C; Sat, 11 Jul 2015 16:19:16 +0000 (UTC) (envelope-from mjg@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2454C1996; Sat, 11 Jul 2015 16:19:16 +0000 (UTC) (envelope-from mjg@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.14.9/8.14.9) with ESMTP id t6BGJFXd069799; Sat, 11 Jul 2015 16:19:15 GMT (envelope-from mjg@FreeBSD.org) Received: (from mjg@localhost) by repo.freebsd.org (8.14.9/8.14.9/Submit) id t6BGJCm4069792; Sat, 11 Jul 2015 16:19:12 GMT (envelope-from mjg@FreeBSD.org) Message-Id: <201507111619.t6BGJCm4069792@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mjg set sender to mjg@FreeBSD.org using -f From: Mateusz Guzik Date: Sat, 11 Jul 2015 16:19:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r285390 - in head/sys: compat/svr4 kern sys ufs/ffs X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 11 Jul 2015 16:19:16 -0000 Author: mjg Date: Sat Jul 11 16:19:11 2015 New Revision: 285390 URL: https://svnweb.freebsd.org/changeset/base/285390 Log: Move chdir/chroot-related fdp manipulation to kern_descrip.c Prefix exported functions with pwd_. Deduplicate some code by adding a helper for setting fd_cdir. Reviewed by: kib Modified: head/sys/compat/svr4/svr4_misc.c head/sys/kern/kern_descrip.c head/sys/kern/kern_jail.c head/sys/kern/vfs_syscalls.c head/sys/sys/filedesc.h head/sys/sys/vnode.h head/sys/ufs/ffs/ffs_alloc.c Modified: head/sys/compat/svr4/svr4_misc.c ============================================================================== --- head/sys/compat/svr4/svr4_misc.c Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/compat/svr4/svr4_misc.c Sat Jul 11 16:19:11 2015 (r285390) @@ -643,7 +643,7 @@ svr4_sys_fchroot(td, uap) goto fail; #endif VOP_UNLOCK(vp, 0); - error = change_root(vp, td); + error = pwd_chroot(td, vp); vrele(vp); return (error); fail: Modified: head/sys/kern/kern_descrip.c ============================================================================== --- head/sys/kern/kern_descrip.c Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/kern/kern_descrip.c Sat Jul 11 16:19:11 2015 (r285390) @@ -2855,6 +2855,96 @@ dupfdopen(struct thread *td, struct file } /* + * This sysctl determines if we will allow a process to chroot(2) if it + * has a directory open: + * 0: disallowed for all processes. + * 1: allowed for processes that were not already chroot(2)'ed. + * 2: allowed for all processes. + */ + +static int chroot_allow_open_directories = 1; + +SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, + &chroot_allow_open_directories, 0, + "Allow a process to chroot(2) if it has a directory open"); + +/* + * Helper function for raised chroot(2) security function: Refuse if + * any filedescriptors are open directories. + */ +static int +chroot_refuse_vdir_fds(struct filedesc *fdp) +{ + struct vnode *vp; + struct file *fp; + int fd; + + FILEDESC_LOCK_ASSERT(fdp); + + for (fd = 0; fd <= fdp->fd_lastfile; fd++) { + fp = fget_locked(fdp, fd); + if (fp == NULL) + continue; + if (fp->f_type == DTYPE_VNODE) { + vp = fp->f_vnode; + if (vp->v_type == VDIR) + return (EPERM); + } + } + return (0); +} + +/* + * Common routine for kern_chroot() and jail_attach(). The caller is + * responsible for invoking priv_check() and mac_vnode_check_chroot() to + * authorize this operation. + */ +int +pwd_chroot(struct thread *td, struct vnode *vp) +{ + struct filedesc *fdp; + struct vnode *oldvp; + int error; + + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + if (chroot_allow_open_directories == 0 || + (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { + error = chroot_refuse_vdir_fds(fdp); + if (error != 0) { + FILEDESC_XUNLOCK(fdp); + return (error); + } + } + oldvp = fdp->fd_rdir; + VREF(vp); + fdp->fd_rdir = vp; + if (fdp->fd_jdir == NULL) { + VREF(vp); + fdp->fd_jdir = vp; + } + FILEDESC_XUNLOCK(fdp); + vrele(oldvp); + return (0); +} + +void +pwd_chdir(struct thread *td, struct vnode *vp) +{ + struct filedesc *fdp; + struct vnode *oldvp; + + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + VNASSERT(vp->v_usecount > 0, vp, + ("chdir to a vnode with zero usecount")); + oldvp = fdp->fd_cdir; + fdp->fd_cdir = vp; + FILEDESC_XUNLOCK(fdp); + vrele(oldvp); +} + +/* * Scan all active processes and prisons to see if any of them have a current * or root directory of `olddp'. If so, replace them with the new mount point. */ Modified: head/sys/kern/kern_jail.c ============================================================================== --- head/sys/kern/kern_jail.c Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/kern/kern_jail.c Sat Jul 11 16:19:11 2015 (r285390) @@ -2432,7 +2432,7 @@ do_jail_attach(struct thread *td, struct goto e_unlock; #endif VOP_UNLOCK(pr->pr_root, 0); - if ((error = change_root(pr->pr_root, td))) + if ((error = pwd_chroot(td, pr->pr_root))) goto e_revert_osd; newcred = crget(); Modified: head/sys/kern/vfs_syscalls.c ============================================================================== --- head/sys/kern/vfs_syscalls.c Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/kern/vfs_syscalls.c Sat Jul 11 16:19:11 2015 (r285390) @@ -728,8 +728,7 @@ sys_fchdir(td, uap) int fd; } */ *uap; { - register struct filedesc *fdp = td->td_proc->p_fd; - struct vnode *vp, *tdp, *vpold; + struct vnode *vp, *tdp; struct mount *mp; struct file *fp; cap_rights_t rights; @@ -761,11 +760,7 @@ sys_fchdir(td, uap) return (error); } VOP_UNLOCK(vp, 0); - FILEDESC_XLOCK(fdp); - vpold = fdp->fd_cdir; - fdp->fd_cdir = vp; - FILEDESC_XUNLOCK(fdp); - vrele(vpold); + pwd_chdir(td, vp); return (0); } @@ -791,9 +786,7 @@ sys_chdir(td, uap) int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg) { - register struct filedesc *fdp = td->td_proc->p_fd; struct nameidata nd; - struct vnode *vp; int error; NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, @@ -807,56 +800,11 @@ kern_chdir(struct thread *td, char *path } VOP_UNLOCK(nd.ni_vp, 0); NDFREE(&nd, NDF_ONLY_PNBUF); - FILEDESC_XLOCK(fdp); - vp = fdp->fd_cdir; - fdp->fd_cdir = nd.ni_vp; - FILEDESC_XUNLOCK(fdp); - vrele(vp); + pwd_chdir(td, nd.ni_vp); return (0); } /* - * Helper function for raised chroot(2) security function: Refuse if - * any filedescriptors are open directories. - */ -static int -chroot_refuse_vdir_fds(fdp) - struct filedesc *fdp; -{ - struct vnode *vp; - struct file *fp; - int fd; - - FILEDESC_LOCK_ASSERT(fdp); - - for (fd = 0; fd <= fdp->fd_lastfile; fd++) { - fp = fget_locked(fdp, fd); - if (fp == NULL) - continue; - if (fp->f_type == DTYPE_VNODE) { - vp = fp->f_vnode; - if (vp->v_type == VDIR) - return (EPERM); - } - } - return (0); -} - -/* - * This sysctl determines if we will allow a process to chroot(2) if it - * has a directory open: - * 0: disallowed for all processes. - * 1: allowed for processes that were not already chroot(2)'ed. - * 2: allowed for all processes. - */ - -static int chroot_allow_open_directories = 1; - -SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, - &chroot_allow_open_directories, 0, - "Allow a process to chroot(2) if it has a directory open"); - -/* * Change notion of root (``/'') directory. */ #ifndef _SYS_SYSPROTO_H_ @@ -891,7 +839,7 @@ sys_chroot(td, uap) goto e_vunlock; #endif VOP_UNLOCK(nd.ni_vp, 0); - error = change_root(nd.ni_vp, td); + error = pwd_chroot(td, nd.ni_vp); vrele(nd.ni_vp); NDFREE(&nd, NDF_ONLY_PNBUF); return (error); @@ -926,42 +874,6 @@ change_dir(vp, td) return (VOP_ACCESS(vp, VEXEC, td->td_ucred, td)); } -/* - * Common routine for kern_chroot() and jail_attach(). The caller is - * responsible for invoking priv_check() and mac_vnode_check_chroot() to - * authorize this operation. - */ -int -change_root(vp, td) - struct vnode *vp; - struct thread *td; -{ - struct filedesc *fdp; - struct vnode *oldvp; - int error; - - fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); - if (chroot_allow_open_directories == 0 || - (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { - error = chroot_refuse_vdir_fds(fdp); - if (error != 0) { - FILEDESC_XUNLOCK(fdp); - return (error); - } - } - oldvp = fdp->fd_rdir; - fdp->fd_rdir = vp; - VREF(fdp->fd_rdir); - if (!fdp->fd_jdir) { - fdp->fd_jdir = vp; - VREF(fdp->fd_jdir); - } - FILEDESC_XUNLOCK(fdp); - vrele(oldvp); - return (0); -} - static __inline void flags_to_rights(int flags, cap_rights_t *rightsp) { Modified: head/sys/sys/filedesc.h ============================================================================== --- head/sys/sys/filedesc.h Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/sys/filedesc.h Sat Jul 11 16:19:11 2015 (r285390) @@ -205,6 +205,10 @@ fd_modified(struct filedesc *fdp, int fd return (!seq_consistent(fd_seq(fdp->fd_files, fd), seq)); } +/* cdir/rdir/jdir manipulation functions. */ +void pwd_chdir(struct thread *td, struct vnode *vp); +int pwd_chroot(struct thread *td, struct vnode *vp); + #endif /* _KERNEL */ #endif /* !_SYS_FILEDESC_H_ */ Modified: head/sys/sys/vnode.h ============================================================================== --- head/sys/sys/vnode.h Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/sys/vnode.h Sat Jul 11 16:19:11 2015 (r285390) @@ -616,7 +616,6 @@ void cache_purge(struct vnode *vp); void cache_purge_negative(struct vnode *vp); void cache_purgevfs(struct mount *mp); int change_dir(struct vnode *vp, struct thread *td); -int change_root(struct vnode *vp, struct thread *td); void cvtstat(struct stat *st, struct ostat *ost); void cvtnstat(struct stat *sb, struct nstat *nsb); int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, Modified: head/sys/ufs/ffs/ffs_alloc.c ============================================================================== --- head/sys/ufs/ffs/ffs_alloc.c Sat Jul 11 16:02:06 2015 (r285389) +++ head/sys/ufs/ffs/ffs_alloc.c Sat Jul 11 16:19:11 2015 (r285390) @@ -2748,13 +2748,12 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) struct thread *td = curthread; struct fsck_cmd cmd; struct ufsmount *ump; - struct vnode *vp, *vpold, *dvp, *fdvp; + struct vnode *vp, *dvp, *fdvp; struct inode *ip, *dp; struct mount *mp; struct fs *fs; ufs2_daddr_t blkno; long blkcnt, blksize; - struct filedesc *fdp; struct file *fp, *vfp; cap_rights_t rights; int filetype, error; @@ -2968,12 +2967,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) break; } VOP_UNLOCK(vp, 0); - fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); - vpold = fdp->fd_cdir; - fdp->fd_cdir = vp; - FILEDESC_XUNLOCK(fdp); - vrele(vpold); + pwd_chdir(td, vp); break; case FFS_SET_DOTDOT: