From owner-freebsd-arch@FreeBSD.ORG Sat Aug 16 11:18:26 2008 Return-Path: Delivered-To: freebsd-arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id ACF1F106567A for ; Sat, 16 Aug 2008 11:18:26 +0000 (UTC) (envelope-from ed@hoeg.nl) Received: from palm.hoeg.nl (mx0.hoeg.nl [IPv6:2001:610:652::211]) by mx1.freebsd.org (Postfix) with ESMTP id 519398FC14 for ; Sat, 16 Aug 2008 11:18:26 +0000 (UTC) (envelope-from ed@hoeg.nl) Received: by palm.hoeg.nl (Postfix, from userid 1000) id F1C511CDC3; Sat, 16 Aug 2008 13:18:24 +0200 (CEST) Date: Sat, 16 Aug 2008 13:18:24 +0200 From: Ed Schouten To: FreeBSD Arch Message-ID: <20080816111824.GL99951@hoeg.nl> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="0DcgAuOrObJpcAxl" Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) Cc: Jille Timmermans Subject: [Reviews requested] kern/121073: chroot for non-root users X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 16 Aug 2008 11:18:26 -0000 --0DcgAuOrObJpcAxl Content-Type: multipart/mixed; boundary="3MtLaQwm2ZGHj8IC" Content-Disposition: inline --3MtLaQwm2ZGHj8IC Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hello everyone, When I visited FOSDEM back in February, I was talking with Jille Timmermans about the chroot() call. After discussing that the problem with chroot() is that it cannot be safely be executed by non-root users w.r.t. setuid binaries*, we wrote this patchset for the kernel to add something similar to `MNT_NOSUID' to the process flags. The result being: http://bugs.FreeBSD.org/121073 The patch even adds a small security improvement to the system. Say, you'd change the typical chroot() + setuid() order the other way around, you're guaranteed the chrooted process will never change users afterwards, because it won't honour set[ug]id binaries anymore. Our security officer was wise enough to add the following to the PR: +----------------------------------------------------------+ |UNDER NO CONDITIONS SHOULD THIS PATCH BE COMMITTED WITHOUT| |EXPLICIT APPROVAL FROM THE FREEBSD SECURITY OFFICER. | +----------------------------------------------------------+ After having a discussion with Colin on IRC, there are a couple of questions we would like to be answered (or discussed) before getting this in the tree: - Are there any comments on the patch itself? - Colin was concerned if turned on, would it be possible for the user to do things which it normally couldn't and shouldn't? It would be great to get many reviews on this before we'd land it in the source tree. I've attached the patch to this email as well. Thanks! --=20 Ed Schouten WWW: http://80386.nl/ * Hardlink a setuid binary to a directory containing a fake C library and executing it. --3MtLaQwm2ZGHj8IC Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="chroot.diff" Content-Transfer-Encoding: quoted-printable --- 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 @@ -633,7 +633,7 @@ =20 if (credential_changing && (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) =3D=3D 0 && - (p->p_flag & P_TRACED) =3D=3D 0) { + (p->p_flag & (P_NOSUGID|P_TRACED)) =3D=3D 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 @@ -595,7 +595,7 @@ * Preserve some more flags in subprocess. P_PROFIL has already * been preserved. */ - p2->p_flag |=3D p1->p_flag & P_SUGID; + p2->p_flag |=3D p1->p_flag & P_INHERITED; td2->td_pflags |=3D td->td_pflags & TDP_ALTSTACK; SESS_LOCK(p1->p_session); if (p1->p_session->s_ttyvp !=3D NULL && p1->p_flag & P_CONTROLT) --- sys/kern/vfs_syscalls.c +++ sys/kern/vfs_syscalls.c @@ -860,9 +860,12 @@ */ =20 static int chroot_allow_open_directories =3D 1; +static int chroot_allow_unprivileged =3D 0; =20 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, ""); =20 /* * Change notion of root (``/'') directory. @@ -880,12 +883,27 @@ } */ *uap; { int error; + struct proc *p; struct nameidata nd; int vfslocked; =20 error =3D 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 =3D td->td_proc; + PROC_LOCK(p); + p->p_flag |=3D P_NOSUGID; + PROC_UNLOCK(p); + } + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, UIO_USERSPACE, uap->path, td); error =3D namei(&nd); --- sys/sys/proc.h +++ sys/sys/proc.h @@ -575,7 +575,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. */ =20 +#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) =20 --3MtLaQwm2ZGHj8IC-- --0DcgAuOrObJpcAxl Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (FreeBSD) iEYEARECAAYFAkimt4AACgkQ52SDGA2eCwV9uQCfWMRPwbvuyvLsCphhfFMKUxEL 9UgAnixkKdX13A6U77mFgHL47RIJ/0GY =z37V -----END PGP SIGNATURE----- --0DcgAuOrObJpcAxl--