Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Jan 2003 11:19:31 +0100 (CET)
From:      Oliver Fromme <olli@secnetix.de>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        Oliver Fromme <olli@secnetix.de>
Subject:   kern/47585: [PATCH] 
Message-ID:  <200301281019.h0SAJVwd056861@lurza.secnetix.de>

next in thread | raw e-mail | index | archive | help

>Number:         47585
>Category:       kern
>Synopsis:       [PATCH]
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jan 28 02:20:02 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Oliver Fromme <olli@secnetix.de>
>Release:        FreeBSD 4.7-RELEASE i386
>Organization:
secnetix GmbH Co KG, http://www.secnetix.de/
>Environment:
System: FreeBSD 4.7-RELEASE
The patch presented in this PR affects systems using
jail(2) environments.

>Description:

   Currently, the jail(2) feature of FreeBSD has a bug:
   jailed processes can see all mounts.  This can be a
   serious information leak and has been of critical
   concern to several ISPs that I've spoken to.  A jailed
   user can type "mount" or "df" to see all mounts, which
   typically gives a good indication of who the other
   customers are.
   
   The patch presented is an improved variant of the patch
   in PR kern/26740:  First, it scales much better, and
   second, it introduces a sysctl variable to control the
   behaviour.
   
   The sysctl MIB entry is named "jail.statfs_restricted".
   For backward compatibility (and POLA-preservation), the
   default value is 0, which disables the patch and causes
   the old behaviour.
   
   When set to 1, jailed processes will only see a single
   faked root mount.
   
   When set to 2, no mounts will be visible at all.  This
   means, however, that certain programs (e.g. ls) will
   refuse to work.  This setting might be useful for jails
   running server processes, but not user shells.
   
   The patch is for 4.7-RELEASE.
   It modifies statfs(), fstatfs() and getfsstat().
   
   If the patch is accepted, I'm willing to write a short
   addition for the jail(8) manpage describing the new
   sysctl MIB entry.

>How-To-Repeat:

   Set up a machine with several jails and observe that all
   jailed users can see all other users' mounts.

>Fix:

--- src/sys/sys/jail.h.orig	Wed Nov  1 18:58:06 2000
+++ src/sys/sys/jail.h	Mon Jan 27 16:07:54 2003
@@ -49,6 +49,7 @@
 extern int	jail_set_hostname_allowed;
 extern int	jail_socket_unixiproute_only;
 extern int	jail_sysvipc_allowed;
+extern int	jail_statfs_restricted;
 
 #endif /* !_KERNEL */
 #endif /* !_SYS_JAIL_H_ */
--- src/sys/kern/kern_jail.c.orig	Fri Aug 17 03:00:26 2001
+++ src/sys/kern/kern_jail.c	Mon Jan 27 16:07:31 2003
@@ -44,6 +44,11 @@
     &jail_sysvipc_allowed, 0,
     "Processes in jail can use System V IPC primitives");
 
+int	jail_statfs_restricted = 0;
+SYSCTL_INT(_jail, OID_AUTO, statfs_restricted, CTLFLAG_RW,
+    &jail_statfs_restricted, 0,
+    "Processes in jail are not allowed to see all mounts");
+
 int
 jail(p, uap)
         struct proc *p;
--- src/sys/kern/vfs_syscalls.c.orig	Fri Apr 26 02:46:04 2002
+++ src/sys/kern/vfs_syscalls.c	Mon Jan 27 18:21:11 2003
@@ -61,6 +61,7 @@
 #include <sys/proc.h>
 #include <sys/dirent.h>
 #include <sys/extattr.h>
+#include <sys/jail.h>
 
 #include <machine/limits.h>
 #include <miscfs/union/union.h>
@@ -660,6 +661,8 @@
 	register struct mount *mp;
 	register struct statfs *sp;
 	int error;
+	int non_su;
+	int fake_root;
 	struct nameidata nd;
 	struct statfs sb;
 
@@ -670,13 +673,23 @@
 	sp = &mp->mnt_stat;
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vrele(nd.ni_vp);
+	if ((fake_root = (p->p_prison && jail_statfs_restricted)))
+		if (jail_statfs_restricted >= 2)
+			return (ENOENT);
 	error = VFS_STATFS(mp, sp, p);
 	if (error)
 		return (error);
 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-	if (suser_xxx(p->p_ucred, 0, 0)) {
+	non_su = suser_xxx(p->p_ucred, 0, 0);
+	if (non_su || fake_root) {
 		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
-		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
+		if (non_su)
+			sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
+		if (fake_root) {
+			strcpy(sb.f_mntfromname, "jail");
+			sb.f_mntonname[0] = '/';
+			sb.f_mntonname[1] = '\0';
+		}
 		sp = &sb;
 	}
 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
@@ -704,6 +717,8 @@
 	struct mount *mp;
 	register struct statfs *sp;
 	int error;
+	int non_su;
+	int fake_root;
 	struct statfs sb;
 
 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
@@ -712,13 +727,23 @@
 	if (mp == NULL)
 		return (EBADF);
 	sp = &mp->mnt_stat;
+	if ((fake_root = (p->p_prison && jail_statfs_restricted)))
+		if (jail_statfs_restricted >= 2)
+			return (ENOENT);
 	error = VFS_STATFS(mp, sp, p);
 	if (error)
 		return (error);
 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-	if (suser_xxx(p->p_ucred, 0, 0)) {
+	non_su = suser_xxx(p->p_ucred, 0, 0);
+	if (non_su || fake_root) {
 		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
-		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
+		if (non_su)
+			sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
+		if (fake_root) {
+			strcpy(sb.f_mntfromname, "jail");
+			sb.f_mntonname[0] = '/';
+			sb.f_mntonname[1] = '\0';
+		}
 		sp = &sb;
 	}
 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
@@ -747,12 +772,22 @@
 	register struct statfs *sp;
 	caddr_t sfsp;
 	long count, maxcount, error;
+	int fake_root;
+	struct statfs sb;
 
 	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
 	sfsp = (caddr_t)SCARG(uap, buf);
 	count = 0;
+	fake_root = (p->p_prison && jail_statfs_restricted);
 	simple_lock(&mountlist_slock);
 	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
+		if (fake_root) {
+			if (jail_statfs_restricted > 1 ||
+			    strcmp(mp->mnt_stat.f_mntonname, "/") != 0) {
+				nmp = TAILQ_NEXT(mp, mnt_list);
+				continue;
+			}
+		}
 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
 			nmp = TAILQ_NEXT(mp, mnt_list);
 			continue;
@@ -773,6 +808,13 @@
 				continue;
 			}
 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+			if (fake_root) {
+				bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
+				strcpy(sb.f_mntfromname, "jail");
+				sb.f_mntonname[0] = '/';
+				sb.f_mntonname[1] = '\0';
+				sp = &sb;
+			}
 			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
 			if (error) {
 				vfs_unbusy(mp, p);
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200301281019.h0SAJVwd056861>