Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Nov 1995 12:01:31 +0200 (EET)
From:      "Andrew V. Stesin" <stesin@elvisti.kiev.ua>
To:        security@freebsd.org
Subject:   Re: chroot/setuid vs type enforcement (fwd)
Message-ID:  <199511291001.MAA15889@office.elvisti.kiev.ua>

next in thread | raw e-mail | index | archive | help
Here are interesting thoughts about hardening security of chrooted
environment...

Forwarded message:
# From: "Marcus J. Ranum" <mjr@iwi.com>
# Message-Id: <199511290431.XAA20148@switchblade.iwi.com>
# Subject: Re: chroot/setuid vs type enforcement
# To: jeromie@garrison.com
# Date: Tue, 28 Nov 1995 23:31:00 -0500 (EST)
# Cc: firewalls@GreatCircle.COM, mjr@iwi.com
# Organization: Information Warehouse! Inc, Baltimore, MD
# Phone: 410-889-8569
# Coredump: Infocalypse Now!!!
# 
# jeromie@garrison.com writes:
# >	As far as being able to remove system calls from accessibility, I would
# >like to hear about if any firewalls have done this. Removing the system calls
# >from accessibility would limit potential vulerabilities.
# 
# 	It's not hard to do; you simply comment them out of the kernel
# or appropriately modify the kernel. I staunchly refuse to accept that
# these things are rocket science, or even very difficult; the kernel
# is just a program and if you are smart enough to use a system you can
# get source for then it's easy to fix.
# 
# 	Let's examine one possiblity. Suppose I am using chroot() to
# protect my firewall. And the argument I want to make is that I want
# to be sure, for sure, that nobody can tweak a buffer overrun and
# call a socket from inside the chrooted area.
# 
# [This is all from BSDI/NetBSD.]
# 	uipc_syscalls.c, at around line 79, has the source code
# for the socket() system call. vfs_syscalls.c, at around line 613
# has the source code for the chroot() system call.
# 
# 	You'll notice, in chroot() that the proc struct (the process
# table slot) for each process has the vnode of the process' root
# file system in it. That's hung off the p->p_fd, which is the
# process' file descriptor table - which in turn stores the
# root vnode as p->p_fd->fd_rdir. With me so far? :)
# 
# 	Now, there's a vnode that's stashed away (see vfs_lookup
# and the system init code in init_main.c) and it's called "rootvnode."
# Given it's name, you won't be shocked to discover that it's the
# root filesystem's "top" vnode.
# 
# 	So - we can assume that if a process' root vnode is not
# the same as the system's root vnode, then it's been chrooted. TA-DA!
# It actually may be simpler than that, since line 127 of vfs_lookup.c
# implies that processes which have NOT been chrooted have a root
# vnode of NULL:
# 
#        if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
#                 ndp->ni_rootdir = rootvnode;
# 
# 	Let's assume that's correct. Now we "harden" our kernel
# by altering the socket() system call thusly:
# 
# uipc_syscalls.c line 78:
# 
#         if(p->fdp->fr_rdir != NULL)
#                 return(EPERM);
# 
# 	WHOAH! It took me 24 lines to explain it, and 2 to code it!
# What this means is that a chrooted process that does a socket() will
# get a permission denied. Maybe that's a bit too brute force. We
# might want to put the code into connect() instead and only let the
# process connect to localhost - or whatever. You get the idea. This
# is trivial code that takes minutes to implement.
# 
# 	The *TRICK* is implementing the RIGHT code in the RIGHT
# place. For this example, if I put it in socket() - what about other
# forms of IPC? See - I'd need to be darn careful to cover all the
# angles. That's nothing to do with the formal properties of my
# protection model; that's a simple matter of Getting The Code Right
# and Damn The Formal Handwaving.
# 
# >In summary, the strongest feature touted by sctc is that chroot() is vulerable
# >to buffer overflows.  In my eyes, this means that if a proxy were to get 
# >subverted, it would not take much to subvert the chroot() setuid() calls and
# >gain full access over the firewall.  I would like to hear if anyone has
# >comments on this issue..??
# 
# 	Chroot() is not "vulnerable to buffer overflows" -- processes
# that have chrooted are potentially vulnerable to buffer overflows.
# 
# 	Subverting a chroot() that has been correctly combined with
# a setuid() is *HARD* - if the chroot() area is set up correctly and
# the kernel is implemented correctly, and your system doesn't
# automatically trust connections from itself, then you are not going
# to be able to do a lot of damage. But, as I've shown above, there
# are lots of ways to address that kind of thing. You can make it
# impossible to break out of a chroot simply by setuid()ing to a non
# root user - then you are no longer permitted to chroot again. If
# there's no way in the chroot area to get privs, then there's no
# way out other than via a socket - and you can nail that dead with
# 2 lines of code.
# 
# 	The easiest way, however, is to be REAL careful about not
# having buffer overruns in your code. :)
# 
# 	This whole game is about being REAL careful about your code.
# Whether it's code in the kernel or code in user space, it's just
# code. Because someone's waved the orange-book over the hacks they
# made to the kernel doesn't make them any fancier than the kind of
# hackery I described above (but for sure they're better documented!)
# 
# mjr.
# 


-- 

	With best regards -- Andrew Stesin.

	+380 (44) 2760188	+380 (44) 2713457	+380 (44) 2713560

	An undocumented feature is a coding error.



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