Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Feb 2021 01:40:22 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: bc0d9b9b84ec - releng/11.4 - MFC jail: Change both root and working directories in jail_attach(2)
Message-ID:  <202102240140.11O1eMk1050844@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch releng/11.4 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=bc0d9b9b84ec5f8c463488c46721dd71fc803ceb

commit bc0d9b9b84ec5f8c463488c46721dd71fc803ceb
Author:     Jamie Gritton <jamie@FreeBSD.org>
AuthorDate: 2021-02-19 22:13:35 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-02-24 01:34:48 +0000

    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 d4380c0cdd0517dc038403dd5c99242ce78bdeb5)
    (cherry picked from commit 570121808a76b85b2709502fb15618dd1e5296f1)
---
 lib/libc/sys/jail.2     |  5 ++++-
 sys/kern/kern_descrip.c | 40 ++++++++++++++++++++++++++++++++++++----
 sys/kern/kern_jail.c    |  2 +-
 sys/sys/filedesc.h      |  1 +
 4 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/lib/libc/sys/jail.2 b/lib/libc/sys/jail.2
index 2e13a6c3a381..82c2e97d4a7b 100644
--- a/lib/libc/sys/jail.2
+++ b/lib/libc/sys/jail.2
@@ -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
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 26b059c0a4b6..17f773d2b7de 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -3052,10 +3052,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)
 {
@@ -3101,6 +3100,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.
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 0bb9c76a25c9..836bc4e4f8b7 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -2418,7 +2418,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();
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index b9ad9fe363e9..5bbc5a3e6fa8 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -239,6 +239,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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102240140.11O1eMk1050844>