From newton@atdot.dotat.org Wed Dec 23 23:05:05 1998 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 Subject: enhancing the security provided by chroot(2) X-Send-Pr-Version: 3.2 >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: newton >State: closed >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Dec 23 23:10:01 PST 1998 >Closed-Date: Thu Jun 1 15:17:33 PDT 2000 >Last-Modified: Thu Jun 01 15:18:37 PDT 2000 >Originator: Mark Newton >Release: FreeBSD 3.0-RELEASE i386 >Organization: >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. >Release-Note: >Audit-Trail: Responsible-Changed-From-To: freebsd-bugs->newton Responsible-Changed-By: newton Responsible-Changed-When: Thu Dec 24 15:28:41 PST 1998 Responsible-Changed-Why: I submitted the patch; I'll do the worrying about whether it's worthwhile during the discussion about whether it should be included. See discussion on freebsd-security. State-Changed-From-To: open->closed State-Changed-By: phk State-Changed-When: Thu Jun 1 15:17:33 PDT 2000 State-Changed-Why: This patch has been overtaken by events: jail reinforcements have closed these holes. http://www.freebsd.org/cgi/query-pr.cgi?pr=9183 >Unformatted: