From: Martin Josefsson (gandalf_at_wlug.westbo.se)
Date: Thu 24 Jan 2002 - 12:03:27 GMT
On Thu, 24 Jan 2002, Jacques Gelinas wrote:
> > I tested the same code on OpenBSD and there it doesn't work. I believe the
> > reason for this is that OpenBSD sets cwd = fsroot when chroot() is called.
> > If I change the code to this:
>
> Someone told me the forcing the chdir right in the chroot system call
> was breaking posix compatibility and it was bad. There is apparently
> a big thread on linux kernel mailing list about this. I have not seen it
> but I was told that the end argument was that fixing chroot was a big
> can of worm...
Yes Al Viro said that. so OpenBSD breaks POSIX and SuS :)
> > chroot("/tmp");
> > chdir("/");
> >
> > mkdir("blabber", 0755);
> > chroot("blabber");
> > chdir("/");
> > chdir("../bin");
> >
> > n = scandir("./", &blah, NULL, 0);
> >
> > Which is the same thing OpenBSD does then I can't list the contents of
> > /bin on Linux either.
>
> Yes this simple fix in the kernel would plug one attack.
Yup but break POSIX and SuS.
> > This manages to break out of the chroot on both Linux and OpenBSD but not
> > on FreeBSD. (on FreeBSD I'm still in /tmp after the chdir("../bin"))
>
> I really would like to see how it is done in freebsd. I have tought of various
> ways to make chrooted environment reliable.
>
> Invalidating open directory handle ?
>
> and all my ideas were either complex to implement or would slow the
> kernel.
http://www.FreeBSD.org/cgi/man.cgi?query=chroot&sektion=2&apropos=0&manpath=FreeBSD+4.0-RELEASE
FreeBSD doesn't force cwd = fsroot on a chroot so if you leave the
chdir("/") out then the chroot has no real effect as on Linux.
According to the manpage the thing that FreeBSD does is to abort
chroot() if the calling process has any open directory handles and
chroot() was called inside a chroot.
> > But it doesn't work when run in an vserver, I havn't looked at the code
> > yet but I assume that CAP_SYS_ADMIN or something similar is needed to be
> > able to really execute a chroot() call.
>
> chroot is controlled by CAP_CHROOT. A little modified escaperoot does work
> in a vserver (as of kernel ctx-5).
hmm how does that work?
> Here is the trick
>
> chmod 000 /vservers
>
> A directory with permission 000 is not usable by anyone. Well, anyone except
> root. root has the CAP_DAC_OVERIDE capability. It means that root can do
> whatever it wants and the permissions and ownership bit are irrelevant.
>
> A directory with permission bit 000 is not common. Even for root, it is weird.
> So I am using this to create the dead zone. In the file /usr/src/linux/fs/namei.c
> I have changed the function vfs_permission like this
>
> int vfs_permission(struct inode * inode, int mask)
> {
> umode_t mode = inode->i_mode;
>
> /*
> A dir with permission bit all 0s is a dead zone for
> process running in a vserver. By doing
> chmod 000 /vservers
> you fix the "escape from chroot" bug.
> */
> if ((mode & 0777) == 0 && current->s_context != 0) return -EACCES;
>
> I just put a if. So if the permissions bit are 000 and you are not in
> security context 0, you can't access. Root or not.
>
> Using this simple fix, a vserver can't be escaped.
>
> I like this solution because it is very very simple. Should not impact
> performance either.
Yes it's not a bad idea.
> I don't like this solution because you have to do something to get it right.
> I mean, you have to do the "chmod 000 vservers". No big deal at first. I can
> change the /usr/sbin/vserver script to fix the directory on the fly. So far
> so good. But people may start to move vservers around because they
> need some disk sapce. They will do
>
> ln -s /drive2/dir1/xx /vservers/xx
>
> Now /drive2/dir1 has to be turned into a dead zone. No big deal again, instead
> of doing
>
> chmod 000 /vservers
>
> when I start a vserver, I can do
>
> chmod 000 /vservers/xx/..
Or you could check the permissions and bail out if they are wrong, I don't
like the 'chmod 000 /vservers/xx/..', if it's a symlink we could be
changing permissions of a directory that shouldn't be changed. Complain
and let the admin work it out.
/Martin
Never argue with an idiot. They drag you down to their level, then beat you with experience.