MFC jail: Change both root and working directories in jail_attach(2)
jail_attach(2) performs an internal chroot operation, leaving it up to
the calling process to assure the working directory is inside the jail.
Add a matching internal chdir operation to the jail's root. Also
ignore kern.chroot_allow_open_directories, and always disallow the
operation if there are any directory descriptors open.
Approved by: so
Security: CVE-2020-25582
Security: FreeBSD-SA-21:05.jail_chdir
Reported by: mjg
Approved by: markj, kib
(cherry picked from commit d4380c0cdd
)
(cherry picked from commit ca9ab8ea17748a1758701fde262cb272fb757989)
This commit is contained in:
parent
8549a1d34e
commit
672f84f97b
|
@ -25,7 +25,7 @@
|
|||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 8, 2012
|
||||
.Dd February 19, 2021
|
||||
.Dt JAIL 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -228,6 +228,9 @@ The
|
|||
system call attaches the current process to an existing jail,
|
||||
identified by
|
||||
.Fa jid .
|
||||
It changes the process's root and current directories to the jail's
|
||||
.Va path
|
||||
directory.
|
||||
.Pp
|
||||
The
|
||||
.Fn jail_remove
|
||||
|
|
|
@ -3169,10 +3169,9 @@ chroot_refuse_vdir_fds(struct filedesc *fdp)
|
|||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
* 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)
|
||||
{
|
||||
|
@ -3218,6 +3217,39 @@ pwd_chdir(struct thread *td, struct vnode *vp)
|
|||
vrele(oldvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* jail_attach(2) changes both root and working directories.
|
||||
*/
|
||||
int
|
||||
pwd_chroot_chdir(struct thread *td, struct vnode *vp)
|
||||
{
|
||||
struct filedesc *fdp;
|
||||
struct vnode *oldvrp, *oldvcp;
|
||||
int error;
|
||||
|
||||
fdp = td->td_proc->p_fd;
|
||||
FILEDESC_XLOCK(fdp);
|
||||
error = chroot_refuse_vdir_fds(fdp);
|
||||
if (error != 0) {
|
||||
FILEDESC_XUNLOCK(fdp);
|
||||
return (error);
|
||||
}
|
||||
oldvrp = fdp->fd_rdir;
|
||||
vrefact(vp);
|
||||
fdp->fd_rdir = vp;
|
||||
oldvcp = fdp->fd_cdir;
|
||||
vrefact(vp);
|
||||
fdp->fd_cdir = vp;
|
||||
if (fdp->fd_jdir == NULL) {
|
||||
vrefact(vp);
|
||||
fdp->fd_jdir = vp;
|
||||
}
|
||||
FILEDESC_XUNLOCK(fdp);
|
||||
vrele(oldvrp);
|
||||
vrele(oldvcp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
|
|
@ -2427,7 +2427,7 @@ do_jail_attach(struct thread *td, struct prison *pr)
|
|||
goto e_unlock;
|
||||
#endif
|
||||
VOP_UNLOCK(pr->pr_root, 0);
|
||||
if ((error = pwd_chroot(td, pr->pr_root)))
|
||||
if ((error = pwd_chroot_chdir(td, pr->pr_root)))
|
||||
goto e_revert_osd;
|
||||
|
||||
newcred = crget();
|
||||
|
|
|
@ -243,6 +243,7 @@ fd_modified(struct filedesc *fdp, int fd, seq_t seq)
|
|||
/* cdir/rdir/jdir manipulation functions. */
|
||||
void pwd_chdir(struct thread *td, struct vnode *vp);
|
||||
int pwd_chroot(struct thread *td, struct vnode *vp);
|
||||
int pwd_chroot_chdir(struct thread *td, struct vnode *vp);
|
||||
void pwd_ensure_dirs(void);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
|
Loading…
Reference in New Issue