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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox