Date: Mon, 25 Feb 2008 10:21:17 +0100 (CET) From: Jille Timmermans <jille@quis.cx> To: FreeBSD-gnats-submit@FreeBSD.org Cc: Ed Schouten <ed@FreeBSD.org> Subject: kern/121073: Patch to run chroot as an unprivileged user Message-ID: <20080225092117.4DF633981F@istud.quis.cx> Resent-Message-ID: <200802250950.m1P9o3w4026348@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080225092117.4DF633981F>