From: Miloslav Semler <majkls@prepere.com>
To: Kyle Moffett <mrmacman_g4@mac.com>
Cc: David Newall <david@davidnewall.com>,
Adrian Bunk <bunk@kernel.org>,
Alan Cox <alan@lxorguk.ukuu.org.uk>,
"Serge E. Hallyn" <serge@hallyn.com>,
Bill Davidsen <davidsen@tmr.com>,
Philipp Marek <philipp@marek.priv.at>,
7eggert@gmx.de, bunk@fs.tum.de, linux-kernel@vger.kernel.org
Subject: Re: Chroot bug
Date: Wed, 26 Sep 2007 15:11:33 +0200 [thread overview]
Message-ID: <46FA5A85.20407@prepere.com> (raw)
In-Reply-To: <6BA6E9EE-B67B-4334-AC83-9B8E30527832@mac.com>
[-- Attachment #1: Type: text/plain, Size: 2407 bytes --]
Kyle Moffett napsal(a):
> On Sep 26, 2007, at 06:27:38, David Newall wrote:
>> Kyle Moffett wrote:
>>> David, please do tell myself and Adrian how "locking down" chroot()
>>> the way you want will avoid letting root break out through any of
>>> the above ways?
>>
>> As has been said, there are thousands of ways to break out of a
>> chroot. It's just that one of them should not be that chroot lets
>> you walk out. I can't explain it clearer than that. If you don't
>> see it now you probably never will.
>
> Let me put it this way: You *CANNOT* enforce chroot() the way you
> want to without a completely unacceptable performance penalty. Let's
> start with the simplest example of:
>
> fd = open("/", O_DIRECTORY);
> chroot("/foo");
> fchdir(fd);
> chroot(".");
>
> If you had ever actually looked at the Linux VFS, it is completely
> *impossible* to tell whether "fd" at the time of the chroot is inside
> or outside of "/foo" without tracking an enormous amount of extra state.
so there *is* solution. It is possible. I solved it. I have patch and it
is working. So if you find some way how to break it I woud glad if you
tell me it.
> Even then, any such determination may not be valid since an FD may be
> opened to an inode which is hardlinked at multiple locations in the
> directory tree. It could also be bind-mounted at multiple locations,
> or it may not even be mounted at all in this namespace (CDROM that was
> lazy-unmounted). That FD may be later passed over an open UNIX-domain
> socket from another process. Moreover, arbitrarily closing FDs would
> break a huge number of programs. Furthermore, since you can't fix the
> "trivial" case of 'fchdir()', then there's no point in even
> *attempting* to fix the "cwd is outside of chroot" problem, although
> that is basically equivalent in difficulty to fixing the "dir-fd is
> outside of chroot" problem.
>
> As for the nested-chroot() bit, the root user inside of a chroot is
> always allowed to chroot(). This is necessary for test-suites for
> various distro installers, chroot once to enter the installer playpen,
> installer chroots again to configure the test-installed-system. Once
> you allow a second chroot, you're back at the "can't reliably and
> efficiently track directory sub-tree members" problem.
>
> So if you think it can and should be fixed, then PROVIDE THE CODE.
Miloslav Semler
[-- Attachment #2: sys_chroot+sys_fchdir.patch --]
[-- Type: text/x-diff, Size: 3265 bytes --]
diff -Nrp linux-2.6.16.53/fs/namei.c linux-2.6.16.53-new/fs/namei.c
*** linux-2.6.16.53/fs/namei.c 2007-07-25 23:05:45.000000000 +0200
--- linux-2.6.16.53-new/fs/namei.c 2007-09-15 16:13:50.000000000 +0200
*************** static __always_inline void follow_dotdo
*** 728,733 ****
--- 728,772 ----
}
follow_mount(&nd->mnt, &nd->dentry);
}
+ long directory_is_out(struct vfsmount *wdmnt, struct dentry *wdentry,
+ struct vfsmount *rootmnt, struct dentry *root)
+ {
+ struct nameidata oldentry, newentry;
+ long ret = 1;
+
+ read_lock(¤t->fs->lock);
+ oldentry.dentry = dget(wdentry);
+ oldentry.mnt = mntget(wdmnt);
+ read_unlock(¤t->fs->lock);
+ newentry.dentry = oldentry.dentry;
+ newentry.mnt = oldentry.mnt;
+
+ follow_dotdot(&newentry);
+ /* check it */
+ if(newentry.dentry == root &&
+ newentry.mnt == rootmnt){
+ ret = 0;
+ goto out;
+ }
+
+ while(oldentry.mnt != newentry.mnt ||
+ oldentry.dentry != newentry.dentry){
+
+ memcpy(&oldentry, &newentry, sizeof(struct nameidata));
+ follow_dotdot(&newentry);
+
+ /* check it */
+ if(newentry.dentry == root &&
+ newentry.mnt == rootmnt){
+ ret = 0;
+ goto out;
+ }
+ }
+ out:
+ dput(newentry.dentry);
+ mntput(newentry.mnt);
+ return ret;
+ }
/*
* It's more convoluted than I'd like it to be, but... it's still fairly
diff -Nrp linux-2.6.16.53/fs/open.c linux-2.6.16.53-new/fs/open.c
*** linux-2.6.16.53/fs/open.c 2007-07-25 23:05:45.000000000 +0200
--- linux-2.6.16.53-new/fs/open.c 2007-09-15 16:14:52.000000000 +0200
*************** dput_and_out:
*** 560,565 ****
--- 560,567 ----
out:
return error;
}
+ long directory_is_out(struct vfsmount *, struct dentry*,
+ struct vfsmount *, struct dentry *);
asmlinkage long sys_fchdir(unsigned int fd)
{
*************** asmlinkage long sys_fchdir(unsigned int
*** 581,586 ****
--- 583,591 ----
error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
goto out_putf;
+ if (directory_is_out(mnt, dentry, current->fs->rootmnt,
+ current->fs->root))
+ goto out_putf;
error = file_permission(file, MAY_EXEC);
if (!error)
*************** out:
*** 594,600 ****
asmlinkage long sys_chroot(const char __user * filename)
{
struct nameidata nd;
! int error;
error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
if (error)
--- 599,605 ----
asmlinkage long sys_chroot(const char __user * filename)
{
struct nameidata nd;
! int error, set_wd = 0;
error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
if (error)
*************** asmlinkage long sys_chroot(const char __
*** 607,615 ****
--- 612,631 ----
error = -EPERM;
if (!capable(CAP_SYS_CHROOT))
goto dput_and_out;
+ error = -ENOTDIR;
+ /*
+ if (directory_is_out(nd.mnt, nd.dentry, current->fs->rootmnt,
+ current->fs->root))
+ goto dput_and_out;
+ */
+ set_wd = directory_is_out(current->fs->pwdmnt, current->fs->pwd,
+ nd.mnt, nd.dentry);
set_fs_root(current->fs, nd.mnt, nd.dentry);
set_fs_altroot();
+ /* if wd is out, reset it to . */
+ if(set_wd)
+ set_fs_pwd(current->fs, nd.mnt, nd.dentry);
error = 0;
dput_and_out:
path_release(&nd);
next prev parent reply other threads:[~2007-09-26 13:11 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <952DN-83o-31@gated-at.bofh.it>
[not found] ` <954cl-29C-3@gated-at.bofh.it>
[not found] ` <95ctn-74b-15@gated-at.bofh.it>
[not found] ` <95cMH-7um-19@gated-at.bofh.it>
[not found] ` <95gdA-4OZ-7@gated-at.bofh.it>
2007-09-20 11:13 ` sys_chroot+sys_fchdir Fix Bodo Eggert
2007-09-20 11:59 ` Philipp Marek
2007-09-20 12:52 ` majkls
2007-09-20 16:06 ` David Newall
2007-09-20 16:17 ` Philipp Marek
2007-09-20 18:02 ` David Newall
2007-09-20 20:53 ` Bill Davidsen
2007-09-21 8:29 ` David Newall
2007-09-24 21:32 ` Serge E. Hallyn
2007-09-24 22:04 ` David Newall
2007-09-24 23:00 ` Serge E. Hallyn
2007-09-25 7:45 ` David Newall
2007-09-25 11:49 ` Serge E. Hallyn
2007-09-25 13:58 ` David Newall
2007-09-25 15:10 ` Chroot bug (was: sys_chroot+sys_fchdir Fix) David Newall
2007-09-25 15:20 ` Jan Engelhardt
2007-09-25 15:39 ` Chroot bug Miloslav Semler
2007-09-25 15:41 ` David Newall
2007-09-25 15:48 ` Jan Engelhardt
2007-09-25 16:19 ` Miloslav Semler
2007-09-25 16:52 ` Jan Engelhardt
2007-09-25 17:00 ` Miloslav Semler
2007-09-25 17:05 ` Jan Engelhardt
2007-09-25 17:09 ` Miloslav Semler
2007-09-25 17:09 ` Al Viro
2007-09-25 17:19 ` Miloslav Semler
2007-09-25 16:53 ` Serge E. Hallyn
2007-09-25 20:51 ` David Newall
2007-09-25 15:30 ` Chroot bug (was: sys_chroot+sys_fchdir Fix) Alan Cox
2007-09-25 15:35 ` Chroot bug David Newall
2007-09-25 15:48 ` Alan Cox
2007-09-25 15:47 ` Jan Engelhardt
2007-09-25 23:50 ` David Newall
2007-09-26 0:18 ` Alan Cox
2007-09-26 10:24 ` David Newall
2007-09-26 10:47 ` Alan Cox
2007-09-26 11:06 ` David Newall
2007-09-26 11:20 ` Alan Cox
[not found] ` <46FA41B4.9040104@prepere.com>
[not found] ` <20070926123522.54ffd56f@the-village.bc.nu>
2007-09-26 11:34 ` Miloslav Semler
2007-09-26 14:09 ` Alan Cox
2007-09-26 13:13 ` Bongani Hlope
2007-09-26 0:55 ` Adrian Bunk
2007-09-26 5:21 ` Kyle Moffett
2007-09-26 5:25 ` Willy Tarreau
2007-09-26 10:27 ` David Newall
2007-09-26 10:45 ` Olivier Galibert
2007-09-26 11:13 ` David Newall
2007-09-26 13:18 ` linux-os (Dick Johnson)
2007-09-26 15:02 ` Olivier Galibert
2007-09-26 12:54 ` Kyle Moffett
2007-09-26 13:11 ` Miloslav Semler [this message]
2007-09-26 13:42 ` Al Viro
2007-09-26 14:51 ` Miloslav Semler
2007-09-26 14:02 ` Kyle Moffett
2007-09-26 15:01 ` Miloslav Semler
2007-09-27 13:49 ` Jiri Kosina
2007-09-25 16:33 ` Arjan van de Ven
2007-09-25 15:32 ` Chroot bug (was: sys_chroot+sys_fchdir Fix) Adrian Bunk
2007-09-25 15:43 ` Chroot bug Miloslav Semler
2007-09-25 16:02 ` Adrian Bunk
2007-09-26 19:23 ` Chroot bug (was: sys_chroot+sys_fchdir Fix) Bodo Eggert
2007-09-24 23:02 ` sys_chroot+sys_fchdir Fix Serge E. Hallyn
[not found] ` <95UE2-1oR-19@gated-at.bofh.it>
[not found] ` <95V72-2ly-17@gated-at.bofh.it>
[not found] ` <97pG8-3B5-47@gated-at.bofh.it>
[not found] ` <97sX2-p1-3@gated-at.bofh.it>
2007-09-26 9:38 ` Nick Craig-Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46FA5A85.20407@prepere.com \
--to=majkls@prepere.com \
--cc=7eggert@gmx.de \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=bunk@fs.tum.de \
--cc=bunk@kernel.org \
--cc=david@davidnewall.com \
--cc=davidsen@tmr.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mrmacman_g4@mac.com \
--cc=philipp@marek.priv.at \
--cc=serge@hallyn.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.