Firewall Wizards mailing list archives

Re: chroot useful?


From: Anton J Aylward <anton () toronto com>
Date: Sat, 15 Nov 1997 08:38:10 -0500

At 01:55 PM 14/11/97 +1100, Darren Reed wrote:

>No. If it can write to /dev/kmem (especially), then all it needs to do
>is call the mknod(2) system call, create the right device for /dev/kmem,
>open it, search for the right place in memory to change and voila! No
>more chroot'd environment. Most of the buffer exploits for programs
>could be converted to do that or make it possible.

suppose I don't have a /dev/kmem - see LINUX
suppose I don't have a /dev in my chroot()'d environment
suppose I have a /dev/kmem in my chroot'd environment which is
actually /dev/null


Why oh why would you set up a chroot'd environment with
the ability to break out of it, by supplying things like a compiler,
syscall library.....

There is also a very simple kernel tweek you can make.
If the per process root inode is not the same as the system
inode (i.e. the process is running chroot()'d) then disallow
various system calls. I can claim originality for this....

It occurred in

From: "Marcus J. Ranum" <mjr () 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
Reply-To: mjr () iwi com
Organization: Information Warehouse! Inc, Baltimore, MD
URL: <A HREF="http://iwi.com/mjr/mjr-top.html">mjr's web page</A>
Phone: 410-889-8569
Coredump: Infocalypse Now!!!
Sender: firewalls-owner () GreatCircle COM

Where he said (sorry this is so long, I've cut some of the discussion out
to leave the meat).

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.

[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.

Hoever his really important point is that things have to be
set up properly or this is all redundant. Having /dev/kmem
in your chroot()'d are is NOT setting things up properly!

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.

Personally, as an old kernel hacker, I'd put the code earlier.
I'd have the check made right after entry to a syscall interrupt handler
and either have a second dispatch table or a column in the table saying
whether this can be executed when croot'd or not. This has the advantage of
localizing the changes and making them more visible. But then I'm also
partial to table driven code ;-) perhaps those flags would also indicate if
you need to be root to execute that system call. I can imagine a simple
piece of code that says if you're chroot()'d you can't do any privileged
calls.

My point is that the arguments about breaking out of chroot jail so far have
assumed it hasn't been set up properly. I don't want to play an infinite
regression of "yes....but" games, but saying you can break out if a certain
hole exists just means add for checking for that hole to you setup list.
And the holes presented so far are not impressive.

/anton





## Reply End ##
--------------------------------------------------------------------------
Anton J Aylward | "Quality refers to the extent to which
The Strahn & Strachan Group Inc | processes, products, services, and
Information Security Consultants | relationships are free from defects,
Voice: (416) 421-8182 | constraints and items which do not add
Fax: (416) 421-8183 | value." - Dr. Mildred G Pryor, 1995


Current thread: