From owner-freebsd-bugs Wed Dec 23 23:10:12 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id XAA22957 for freebsd-bugs-outgoing; Wed, 23 Dec 1998 23:10:12 -0800 (PST) (envelope-from owner-freebsd-bugs@FreeBSD.ORG) Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id XAA22952 for ; Wed, 23 Dec 1998 23:10:11 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.8.8/8.8.5) id XAA09481; Wed, 23 Dec 1998 23:10:01 -0800 (PST) Received: from atdot.dotat.org (atdot.dotat.org [203.23.150.35]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id XAA22103 for ; Wed, 23 Dec 1998 23:05:01 -0800 (PST) (envelope-from newton@atdot.dotat.org) Received: (from newton@localhost) by atdot.dotat.org (8.9.1/8.7) id RAA00744; Thu, 24 Dec 1998 17:34:02 +1030 (CST) Message-Id: <199812240704.RAA00744@atdot.dotat.org> Date: Thu, 24 Dec 1998 17:34:02 +1030 (CST) From: Mark Newton Reply-To: newton@atdot.dotat.org To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: kern/9183: enhancing the security provided by chroot(2) Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 9183 >Category: kern >Synopsis: chroot(2) can be broken by the superuser. this patch disables chroot() for processes which have already been chroot()'ed >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Dec 23 23:10:01 PST 1998 >Last-Modified: >Originator: Mark Newton >Organization: >Release: FreeBSD 3.0-RELEASE i386 >Environment: Any security-conscious site with a requirement to use chroot(). >Description: There are many techniques which can be used by a root user to break out of a "chroot()'ed" jail. Most of these techniques involve feeding a new directory into the chroot() call to set a process' root directory to something "outside" the jail, thereby allowing an attacker to access files outside the restricted area. Most of those techniques are rendered moot if the chroot() system call cannot be used by processes in the jail. This patch compares the root directory of processes which call chroot() against the root directory of PID 1. If they match, chroot() is permitted as per normal semantics. If they don't, chroot() will fail with EPERM. This breaks "traditional" chroot() semantics, so this patch implements the change under the control of a sysctl MIB variable called vfs.hard_chroot (to distinguish it from the normal "soft" chroot :-). If that variable is set to a non-zero value chroot will fail if it is used by "jailed" processes even if the caller is root. >How-To-Repeat: N/A >Fix: *** sys/kern/vfs_syscalls.c.981224 Thu Dec 24 17:01:07 1998 --- sys/kern/vfs_syscalls.c Thu Dec 24 17:08:24 1998 *************** *** 86,92 **** --- 86,99 ---- static int setutimes __P((struct proc *, struct vnode *, struct timeval *, int)); static int usermount = 0; /* if 1, non-root can mount fs. */ + /* + * hard_chroot - If 1, chroot() will fail with EPERM for any processes + * which are already chroot()ed. + */ + static int hard_chroot = 0; + SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, ""); + SYSCTL_INT(_vfs, OID_AUTO, hard_chroot, CTLFLAG_RW, &hard_chroot, 0, ""); /* * Virtual File System System Calls *************** *** 831,836 **** --- 838,850 ---- register struct filedesc *fdp = p->p_fd; int error; struct nameidata nd; + register struct proc *init; + + if (hard_chroot) { + init = pfind((pid_t)1); /* locate init's proc structure */ + if (fdp->fd_rdir != init->p_fd->fd_rdir) + return(EPERM); + } error = suser(p->p_ucred, &p->p_acflag); if (error) *** lib/libc/sys/chroot.2.981224 Thu Dec 24 17:16:30 1998 --- lib/libc/sys/chroot.2 Thu Dec 24 17:23:15 1998 *************** *** 60,65 **** --- 60,73 ---- has no effect on the process's current directory. .Pp This call is restricted to the super-user. + .Sh MIB VARIABLES + .Fn chroot + observes the value of vfs.hard_chroot. A non-zero value in this variable + indicates that + .Fn chroot + should fail if the caller is already under the influence of a prior + .Fn chroot + operation. .Sh RETURN VALUES Upon successful completion, a value of 0 is returned. Otherwise, a value of -1 is returned and *************** *** 72,78 **** .It Bq Er ENOTDIR A component of the path name is not a directory. .It Bq Er EPERM ! The effective user ID is not the super-user. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters. --- 80,89 ---- .It Bq Er ENOTDIR A component of the path name is not a directory. .It Bq Er EPERM ! The effective user ID is not the super-user or vfs.hard_chroot is non-zero ! and the caller's root directory has been set by a previous ! .Fn chroot ! operation. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters. >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message