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:
parent
70915d1289
commit
f0725a8e1e
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user