From owner-freebsd-bugs Tue Jan 28 2:30:11 2003 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 5959A37B406 for ; Tue, 28 Jan 2003 02:30:04 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id BE34343F9B for ; Tue, 28 Jan 2003 02:30:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.6/8.12.6) with ESMTP id h0SAU1NS097010 for ; Tue, 28 Jan 2003 02:30:01 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.6/8.12.6/Submit) id h0SAU1T7097009; Tue, 28 Jan 2003 02:30:01 -0800 (PST) Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A49B737B401 for ; Tue, 28 Jan 2003 02:22:05 -0800 (PST) Received: from lurza.secnetix.de (lurza.secnetix.de [212.66.1.130]) by mx1.FreeBSD.org (Postfix) with ESMTP id D20F443E4A for ; Tue, 28 Jan 2003 02:22:04 -0800 (PST) (envelope-from olli@lurza.secnetix.de) Received: from lurza.secnetix.de (localhost [IPv6:::1]) by lurza.secnetix.de (8.12.6/8.12.5) with ESMTP id h0SAM3dK057050; Tue, 28 Jan 2003 11:22:03 +0100 (CET) (envelope-from oliver.fromme@secnetix.de) Received: (from olli@localhost) by lurza.secnetix.de (8.12.6/8.12.5/Submit) id h0SAM3aP057049; Tue, 28 Jan 2003 11:22:03 +0100 (CET) Message-Id: <200301281022.h0SAM3aP057049@lurza.secnetix.de> Date: Tue, 28 Jan 2003 11:22:03 +0100 (CET) From: Oliver Fromme Reply-To: Oliver Fromme To: FreeBSD-gnats-submit@FreeBSD.org Cc: Oliver Fromme X-Send-Pr-Version: 3.113 Subject: kern/47586: [PATCH] fix information-leak (mounts) in jail(2) Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 47586 >Category: kern >Synopsis: [PATCH] fix information-leak (mounts) in jail(2) >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:30:01 PST 2003 >Closed-Date: >Last-Modified: >Originator: Oliver Fromme >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 #include #include +#include #include #include @@ -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