Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Nov 1996 23:38:23 -0700 (MST)
From:      Marc Slemko <marcs@znep.com>
To:        Don Lewis <Don.Lewis@tsc.tdk.com>
Cc:        Dev Chanchani <dev@trifecta.com>, freebsd-security@freebsd.org
Subject:   Re: chroot() security
Message-ID:  <Pine.BSF.3.95.961101225850.22655K-100000@alive.ampr.ab.ca>
In-Reply-To: <199611020401.UAA07806@salsa.gv.ssi1.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 1 Nov 1996, Don Lewis wrote:

> You can add various checks to the kernel to keep chroot()ed processes
> from doing a lot of these things, but there is one deadly exploit that
> someone posted to this list back in September.  By the clever use of
> chroot() and chdir(), it is possible for a root process to waltz out
> of a chroot()ed environment.  I don't know of a clean way of plugging
> that hole.
> 
> BTW, thanks for mentioning ptrace().  I hadn't thought of that one.

Yup, you certainly can add checks and in theory you should be able to plug
all the holes IF you can find them.  My bet is that you won't be able to
find them, so you can't make it secure.

I assume the below message is the one you are referring to, so I'll
include a copy so people know what the issue is.  Heck, I may as well run
through what the code does.  I forgot about the obvious because well,
there are just so many ways to get out.  This one is quite clean though. 

When you do a chroot(2), the current working directory is not changed, the
only thing that is changed is what the kernel thinks the root directory is
for that process.  The chroot program that comes with FreeBSD does
something like: 
	if (chdir(path) || chroot(".")) print_error_and_die

where path is the directory you want to chroot to.  If either of the calls
fail, it exits.  This ensures that the current directory is inside the new
root directory so no access outside can be made.

Now, there is only one root directory per process (well, that isn't quite
true but the details get complicated).  Keeping this in mind, examine the
code below.  It does a chroot to a new directory inside the chrooted
environment; since there is only one root directory per process, this is
NOT a chrooted environment inside a chrooted environment, but is simply a
chrooted environment.  If you can break the new chrooted environment, you
have access to the whole filesystem, not just to the old chrooted
envionment.

Now, how can we go about breaking out of this new chrooted environment? 
Go back to how the chroot program does it; first it changes the directory,
then it does the chroot to be sure the current directory is inside the
chrooted tree.  This program doesn't do that.  After it does the chroot,
the current directory is still outside the new chrooted directory;  it is
inside what was the old one, but that doesn't matter any more.  From
there, it is a simple matter to back up until we get to the root, then
make the real root our new root with another chroot call.

A trivial solution would be to modify the kernel chroot routine to change
the current directory to something inside the chrooted directory, however
that solution is too trivial in that it would break some existing programs
and I'm not sure it would help anything because I would suggest that many
of the data structures involved could perhaps be manipulated using some
other method. 


Date:      Mon, 9 Sep 1996 16:09:46 -0500 (CDT)
From:      Zach Heilig <zach@blizzard.gaffaneys.com>
To:        rkw@dataplex.net (Richard Wackerbarth)
Cc:        freebsd-security@freebsd.org
Sender:    owner-security@freebsd.org
Subject:   Re: Question about chroot

In a previous message, Richard Wackerbarth wrote:

>In looking at some of the "make" problems, I ran up against a
>characteristic of "chroot" that puzzles me.

>In order to chroot, you must be root. Why?

Basically, all you have to do to become root in a chroot() environment
is to hard-link the appropriate setuid executables into a publicly
writable directory (usually /usr/tmp), and build your own minimal
filesystem to use while in that environment.  You need the
/etc/master.passwd file (you create it yourself), /etc/group (to put
yourself in the wheel group), /usr/sbin/vipw (to rebuild the other
passwd files), /usr/bin/su (to gain root), /bin/sh, and any other file
utilities that you find you need in the course of the attack (probably
hard links to each of the lib*.so.* libraries, and ld/ldd).  You
should probably put the binaries in /bin (relative to the chroot()
root directory).  Breaking out of the chroot() environment after you
become root is trivial.  I have source here that works for FreeBSD:

#include <stdio.h>
#include <unistd.h>

int
main(void)
{
    int i;

    mkdir("break-out", 0755);
    chroot("./break-out");
    chdir(".");
    for (i = 0; i < 30; ++i) chdir("..");
    chroot(".");
    execl("/bin/sh", "sh" , (char *) 0);
    puts("exec failed!");
    return 1;
}

You compile this before calling chroot for /usr/tmp/wherever.  At this
point, the attacker would clean up his mess in /usr/tmp, and possibly
put a setuid shell in an accessible spot.

>It appears to me than the only thing that chroot does is to restrict the
>"visable" tree. It does not ADD anything that is not already there.

But the user can BEFORE running chroot.

>If that is the case, why wouldn't it be good enough for chroot to be suid
>root and allow any user to execute it?

>Am I overlooking some security hole?

Yes.

This is one reason it is bad to have a world-writable directory on the
same filesystem as the /usr filesystem.

--
Zach Heilig (zach@blizzard.gaffaneys.com) | ALL unsolicited commercial email
Support bacteria -- it's the              | is unwelcome.  I avoid dealing
only culture some people have!            | with companies that email ads.




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.95.961101225850.22655K-100000>