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
This commit is contained in:
Mateusz Guzik 2015-07-11 16:19:11 +00:00
parent 70915d1289
commit f0725a8e1e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285390
7 changed files with 102 additions and 103 deletions

View File

@ -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:

View File

@ -2854,6 +2854,96 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode,
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");
/*
* 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.

View File

@ -2432,7 +2432,7 @@ do_jail_attach(struct thread *td, struct prison *pr)
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();

View File

@ -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,55 +800,10 @@ kern_chdir(struct thread *td, char *path, enum uio_seg pathseg)
}
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.
*/
@ -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)
{

View File

@ -205,6 +205,10 @@ fd_modified(struct filedesc *fdp, int fd, seq_t seq)
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_ */

View File

@ -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,

View File

@ -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: