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