FreeBSD Bugzilla – Attachment 143547 Details for
Bug 121073
[kernel] [patch] run chroot as an unprivileged user
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Prevents escape from unprivileged chroot
chroot.diff (text/plain), 6.35 KB, created by
Nathan Whitehorn
on 2014-06-08 22:47:23 UTC
(
hide
)
Description:
Prevents escape from unprivileged chroot
Filename:
MIME Type:
Creator:
Nathan Whitehorn
Created:
2014-06-08 22:47:23 UTC
Size:
6.35 KB
patch
obsolete
>Index: lib/libc/sys/chroot.2 >=================================================================== >--- lib/libc/sys/chroot.2 (revision 267243) >+++ lib/libc/sys/chroot.2 (working copy) >@@ -61,7 +61,17 @@ > .Fn chroot > has no effect on the process's current directory. > .Pp >-This call is restricted to the super-user. >+By default, this call is restricted to the super-user. If >+.Ql kern.chroot_allow_unprivileged >+is set to a non-zero value, all users are capable of performing the >+.Fn chroot >+call. When called by an unprivileged user, the process and its children >+won't honor the setuid and setgid bits when performing an >+.Xr execve 2 . >+To prevent escape from a chroot established by a privileged process, >+unprivileged processes also cannot execute >+.Fn chroot >+under any circumstances when already under a modified root. > .Pp > Depending on the setting of the > .Ql kern.chroot_allow_open_directories >@@ -141,6 +151,11 @@ > open directories, or a MAC check), it is possible that this system > call may return an error, with the working directory of the process > left changed. >+.Pp >+When a call to >+.Fn chroot >+fails when invoked by an unprivileged user, the process is not properly >+capable of executing setuid or setgid applications anymore. > .Sh SECURITY CONSIDERATIONS > The system have many hardcoded paths to files where it may load after > the process starts. >Index: sys/compat/svr4/svr4_misc.c >=================================================================== >--- sys/compat/svr4/svr4_misc.c (revision 267243) >+++ sys/compat/svr4/svr4_misc.c (working copy) >@@ -631,7 +631,7 @@ > goto fail; > #endif > VOP_UNLOCK(vp, 0); >- error = change_root(vp, td); >+ error = change_root(vp, td, 0); > vrele(vp); > return (error); > fail: >Index: sys/kern/kern_exec.c >=================================================================== >--- sys/kern/kern_exec.c (revision 267243) >+++ sys/kern/kern_exec.c (working copy) >@@ -695,7 +695,7 @@ > ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && > #endif > (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && >- (p->p_flag & P_TRACED) == 0) { >+ (p->p_flag & P_TRACED) == 0 && (p->p_flag2 & P2_NOSUGID) == 0) { > /* > * Turn off syscall tracing for set-id programs, except for > * root. Record any set-id flags first to make sure that >Index: sys/kern/kern_fork.c >=================================================================== >--- sys/kern/kern_fork.c (revision 267243) >+++ sys/kern/kern_fork.c (working copy) >@@ -571,6 +571,7 @@ > * been preserved. > */ > p2->p_flag |= p1->p_flag & P_SUGID; >+ p2->p_flag2 |= p1->p_flag2 & P2_NOSUGID; > td2->td_pflags |= td->td_pflags & TDP_ALTSTACK; > SESS_LOCK(p1->p_session); > if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) >Index: sys/kern/kern_jail.c >=================================================================== >--- sys/kern/kern_jail.c (revision 267243) >+++ sys/kern/kern_jail.c (working copy) >@@ -2372,7 +2372,7 @@ > goto e_unlock; > #endif > VOP_UNLOCK(pr->pr_root, 0); >- if ((error = change_root(pr->pr_root, td))) >+ if ((error = change_root(pr->pr_root, td, 0))) > goto e_revert_osd; > > newcred = crget(); >Index: sys/kern/vfs_syscalls.c >=================================================================== >--- sys/kern/vfs_syscalls.c (revision 267243) >+++ sys/kern/vfs_syscalls.c (working copy) >@@ -855,6 +855,11 @@ > &chroot_allow_open_directories, 0, > "Allow a process to chroot(2) if it has a directory open"); > >+/* This one allows unprivileged users to run chroot */ >+static int chroot_allow_unprivileged = 0; >+SYSCTL_INT(_kern, OID_AUTO, chroot_allow_unprivileged, CTLFLAG_RW, >+ &chroot_allow_unprivileged, 0, ""); >+ > /* > * Change notion of root (``/'') directory. > */ >@@ -871,11 +876,35 @@ > } */ *uap; > { > struct nameidata nd; >+ struct proc *p; >+ int disallow_nesting; > int error; > >+ disallow_nesting = 0; > error = priv_check(td, PRIV_VFS_CHROOT); >- if (error != 0) >- return (error); >+ if (error) { >+ if (!chroot_allow_unprivileged) >+ return (error); >+ >+ /* >+ * Disallow this process and its children to use setuid >+ * bits. Users could hardlink setuid applications into a >+ * chroot which contains a fake C library to obtain >+ * super-user privileges. >+ */ >+ p = td->td_proc; >+ PROC_LOCK(p); >+ p->p_flag2 |= P2_NOSUGID; >+ PROC_UNLOCK(p); >+ >+ /* >+ * Don't allow unprivileged code to chroot more than once. >+ * This prevents escaping from a chroot after dropped >+ * privileges. >+ */ >+ disallow_nesting = 1; >+ } >+ > NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, > UIO_USERSPACE, uap->path, td); > error = namei(&nd); >@@ -890,7 +919,7 @@ > goto e_vunlock; > #endif > VOP_UNLOCK(nd.ni_vp, 0); >- error = change_root(nd.ni_vp, td); >+ error = change_root(nd.ni_vp, td, disallow_nesting); > vrele(nd.ni_vp); > NDFREE(&nd, NDF_ONLY_PNBUF); > return (error); >@@ -931,9 +960,10 @@ > * authorize this operation. > */ > int >-change_root(vp, td) >+change_root(vp, td, disallow_nesting) > struct vnode *vp; > struct thread *td; >+ int disallow_nesting; > { > struct filedesc *fdp; > struct vnode *oldvp; >@@ -941,6 +971,10 @@ > > fdp = td->td_proc->p_fd; > FILEDESC_XLOCK(fdp); >+ if (disallow_nesting && fdp->fd_rdir != rootvnode) { >+ FILEDESC_XUNLOCK(fdp); >+ return (EPERM); >+ } > if (chroot_allow_open_directories == 0 || > (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { > error = chroot_refuse_vdir_fds(fdp); >Index: sys/sys/proc.h >=================================================================== >--- sys/sys/proc.h (revision 267243) >+++ sys/sys/proc.h (working copy) >@@ -646,6 +646,7 @@ > > /* These flags are kept in p_flag2. */ > #define P2_INHERIT_PROTECTED 0x00000001 /* New children get P_PROTECTED. */ >+#define P2_NOSUGID 0x00000002 /* Ignore set[ug]id on exec. */ > > /* > * These were process status values (p_stat), now they are only used in >Index: sys/sys/vnode.h >=================================================================== >--- sys/sys/vnode.h (revision 267243) >+++ sys/sys/vnode.h (working copy) >@@ -605,7 +605,7 @@ > 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); >+int change_root(struct vnode *vp, struct thread *td, int disallow_nesting); > 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,
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 121073
:
84994
| 143547