From owner-freebsd-security Mon Jan 11 02:42:26 1999 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id CAA13128 for freebsd-security-outgoing; Mon, 11 Jan 1999 02:42:26 -0800 (PST) (envelope-from owner-freebsd-security@FreeBSD.ORG) Received: from gatekeeper.tsc.tdk.com (gatekeeper.tsc.tdk.com [207.113.159.21]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id CAA13123 for ; Mon, 11 Jan 1999 02:42:25 -0800 (PST) (envelope-from gdonl@tsc.tdk.com) Received: from sunrise.gv.tsc.tdk.com (root@sunrise.gv.tsc.tdk.com [192.168.241.191]) by gatekeeper.tsc.tdk.com (8.8.8/8.8.8) with ESMTP id CAA19371; Mon, 11 Jan 1999 02:35:19 -0800 (PST) (envelope-from gdonl@tsc.tdk.com) Received: from salsa.gv.tsc.tdk.com (salsa.gv.tsc.tdk.com [192.168.241.194]) by sunrise.gv.tsc.tdk.com (8.8.5/8.8.5) with ESMTP id CAA28654; Mon, 11 Jan 1999 02:35:18 -0800 (PST) Received: (from gdonl@localhost) by salsa.gv.tsc.tdk.com (8.8.5/8.8.5) id CAA15251; Mon, 11 Jan 1999 02:35:16 -0800 (PST) From: Don Lewis Message-Id: <199901111035.CAA15251@salsa.gv.tsc.tdk.com> Date: Mon, 11 Jan 1999 02:35:16 -0800 In-Reply-To: Mark Newton "Re: About chroot" (Jan 11, 3:04pm) X-Mailer: Mail User's Shell (7.2.6 alpha(3) 7/19/95) To: Mark Newton , Don.Lewis@tsc.tdk.com (Don Lewis) Subject: Re: About chroot Cc: robert+freebsd@cyrus.watson.org, newton@camtech.com.au, eivind@yes.no, casper@acc.am, freebsd-security@FreeBSD.ORG Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org On Jan 11, 3:04pm, Mark Newton wrote: } Subject: Re: About chroot } Don Lewis wrote: } } > } > > kern/9183 } > } > } > } > It seems like a neat idea. However, enabling vfs.hard_chroot may break } > } > security in certain environments--in particular, environments where a } > } > chroot is used as part of the system bootup, and where existing } > } > services will try to use chroot to create sandboxes. } > } } > } Agreed. I figured those cases would make up a minority. } > } > There's at least one place where I need two levels of chroot(). The hack } > that I'm currently using added another rdir-like entry to struct filedesc. } > I'm currently in the process of reimplementing this as a stack. The main } > main problem I'm having is a lack of time to work on the code. } > One tricky thing is that once you allow more than one level of chroot(), } > you create the possibility of breaking out of the jail. I've got some } > ideas on how to protect against this. } } Care to share? I'm hoping that I can post a patch in the next week or so. The problem is that I've been hoping the same thing for quite a while :-( } Although multiple recursive levels of chroot() are one of those things } that would be "nice to have", do you think the implementational } complexity of an in-kernel root directory stack are worth it considering } that people have been able to work around chroot() limitations for the } last 20 years or so? It's worthwhile for me. The implementation isn't too bad. Unfortunately it requires some tweaks to fstat, lsof, etc. } } [ ooooh, I'm gonna get it in the neck for that question... ] } } > } Of course -- But that's relatively easy: The same check for } > } p_rdir that's used to work out whether chroot() should fail can also } > } be placed into mknod(2) and mount(2). I wouldn't even need to } > } unstaticize hard_chroot to make those changes happen. } > } > I did something like this a couple years ago (don't forget about umount()). } > My current preference would be to set a flag in struct proc that disables } > access to these. The process that puts the suspect process in jail would } > do the chroot() and set the flag. } } I've modified my initial patch to vfs_syscalls.c; It now affects the } syscalls described below if the caller's root directory is not the } same as init's root directory AND vfs.hard_chroot != 0 AND if an additional } supplementary condition evaluates to true, regardless of the uid of } the caller: } } system call supplementary condition } ------------------------------------------------------------------ } mount true (:-) } umount true } chroot true } mknod true (only affects mknod(2); FIFOs are still } allowed) } chmod mode & S_ISUID } lchmod mode & S_ISUID } fchmod mode & S_ISUID } } The last three are to prevent a chroot'ed user from making setuid } binaries of any kind regardless of who owns them. Good idea. I didn't need to do this because all the writeable areas of my sandboxes are mounted noexec. This could relax this to nosuid if necessary. } The vfs.hard_chroot test is performed by means of a macro called } FAIL_HARD_CHROOT() defined in the same place as the hard_chroot sysctl. } It takes one parameter, which is the supplementary conditional used } to fail the syscall. FHC_ALWAYS is defined to 1 for the cases marked } as "true" in the table above. } } > Even better would be finer grained access control. It's too bad that POSIX } > wasn't able to standardize something. } } IRIX, HP-UX and Solaris have ACLs. I wasn't thinking of file ACLs, which would also be nice to have, but rather a flag that controls whether or not you can mount(), etc. What would be really cool is phk's sandbox stuff. } > } We'd probably also want to restrict a user's ability to access LKM/KLD } > } interfaces, assuming they're in the kernel in the first place. reboot(2) } > } should also be restricted. Are there any others? (deny bind()ing to } > } privileged ports? nah, that'd break ftpd, which is part of the } > } intended audience of the patch, with very few security benefits). } > } > I disabled access to lkms, blocked access to processes outside the } > jail by kill() and ptrace(). } } On further reflection, the lkm (or kld) and ptrace cases are already } covered by kern.securelevel. You can't ptrace the init process when securelevel > 0, but I think everything else is wide open. } The kill case could be covered by unstaticizing hard_chroot, putting } the FAIL_HARD_CHROOT() macro into a .h file, and putting something like } the following (untested code) at the front of kill()/killpg()/etc in } kern_sig.c: } } FAIL_HARD_CHROOT((pfind(uap->pid))->p_fd->fd_rdir != cp->p_fd->fd_rdir); } } i.e.: fail the kill() operation if the root directory of the target } is not the same as the root directory of the caller. This would } mean that processes in one jail couldn't kill processes in other } jails on the same system too. This is pretty much the same as what I implemented. To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message