kern/121073: Patch to run chroot as an unprivileged user

Jille Timmermans jille at quis.cx
Mon Feb 25 09:50:03 UTC 2008


>Number:         121073
>Category:       kern
>Synopsis:       Patch to run chroot as an unprivileged user
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 25 09:50:03 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Jille Timmermans
>Release:        FreeBSD 8.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD stagemachine 8.0-CURRENT FreeBSD 8.0-CURRENT #0: Mon Feb 25 09:24:13 CET 2008 ed at stagemachine:/usr/obj/store/home/ed/p4/mpsafetty/sys/STAGEMACHINE  i386



	
>Description:
	We (Ed and I) thought it should be possible to chroot as non-root,
	This should (hopefully) increase the security, because no setuid-root and privilege dropping after the chroot(2) call is longer needed.
	This is tested on 8.0-CURRENT, should work on 7.0-RC2 and I will backport it later to 6.3-RELEASE.

>How-To-Repeat:
	sysctl kern.chroot_allow_unprivileged=1
	su nobody
	chroot / sh
	ping 127.0.0.1 # Should fail

>Fix:
--- lib/libc/sys/chroot.2
+++ lib/libc/sys/chroot.2
@@ -61,7 +61,13 @@
 .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 .
 .Pp
 Depending on the setting of the
 .Ql kern.chroot_allow_open_directories
@@ -140,3 +146,8 @@
 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.
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -560,7 +560,7 @@
 
 	if (credential_changing &&
 	    (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 &&
-	    (p->p_flag & P_TRACED) == 0) {
+	    (p->p_flag & (P_NOSUGID|P_TRACED)) == 0) {
 		/*
 		 * Turn off syscall tracing for set-id programs, except for
 		 * root.  Record any set-id flags first to make sure that
--- sys/kern/kern_fork.c
+++ sys/kern/kern_fork.c
@@ -584,7 +584,7 @@
 	 * Preserve some more flags in subprocess.  P_PROFIL has already
 	 * been preserved.
 	 */
-	p2->p_flag |= p1->p_flag & P_SUGID;
+	p2->p_flag |= p1->p_flag & P_INHERITED;
 	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)
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -860,9 +860,12 @@
  */
 
 static int chroot_allow_open_directories = 1;
+static int chroot_allow_unprivileged = 0;
 
 SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
      &chroot_allow_open_directories, 0, "");
+SYSCTL_INT(_kern, OID_AUTO, chroot_allow_unprivileged, CTLFLAG_RW,
+     &chroot_allow_unprivileged, 0, "");
 
 /*
  * Change notion of root (``/'') directory.
@@ -880,12 +883,27 @@
 	} */ *uap;
 {
 	int error;
+	struct proc *p;
 	struct nameidata nd;
 	int vfslocked;
 
 	error = priv_check(td, PRIV_VFS_CHROOT);
-	if (error)
-		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_flag |= P_NOSUGID;
+		PROC_UNLOCK(p);
+	}
+
 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
 	    UIO_USERSPACE, uap->path, td);
 	error = namei(&nd);
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -643,7 +643,9 @@
 #define	P_INMEM		0x10000000 /* Loaded into memory. */
 #define	P_SWAPPINGOUT	0x20000000 /* Process is being swapped out. */
 #define	P_SWAPPINGIN	0x40000000 /* Process is being swapped in. */
+#define	P_NOSUGID	0x80000000 /* Ignore set[ug]id on exec. */
 
+#define	P_INHERITED	(P_SUGID|P_NOSUGID)
 #define	P_STOPPED	(P_STOPPED_SIG|P_STOPPED_SINGLE|P_STOPPED_TRACE)
 #define	P_SHOULDSTOP(p)	((p)->p_flag & P_STOPPED)
 
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list