GNU bug report logs -
#18736
chroot regression - chroot avoids the chroot() call too eagerly.
Previous Next
Reported by: Rogier <rogier777 <at> gmail.com>
Date: Wed, 15 Oct 2014 15:44:04 UTC
Severity: normal
Done: Pádraig Brady <P <at> draigBrady.com>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 18736 in the body.
You can then email your comments to 18736 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Wed, 15 Oct 2014 15:44:04 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Rogier <rogier777 <at> gmail.com>
:
New bug report received and forwarded. Copy sent to
bug-coreutils <at> gnu.org
.
(Wed, 15 Oct 2014 15:44:05 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Hi,
Since a few months, it seems that chroot has started avoiding the
chroot call if it can be determined to be idempotent.
It looks like the new check is based on inode comparison - if the
inode is the same, the chroot() call is considered idempotent, and not
performed.
However, while two directories being in the same file system and having
the same inode number implies that they are the same directory, it
does not necessarily imply that they have same file system path (i.e.
use the same mountpoint), so there is no guarantee that the entire
directory trees rooted at the two directories are also identical even
though the directories are.This means that chroot will fail to
chroot() in cases when the call would in fact not be idempotent.
On my system (debian testing), I have / bind-mounted elsewhere, with a
slightly different directory tree mounted beneath it, as is mounted
beneath /. In my case, I need this so that I can make partial backups
of the system - including some file systems but leaving out others.
Undoubtly, there are other use-cases as well - I wouldn't be surprised
if users of libpam-chroot can be affected by this, depending on exactly
how they configure their chroot environments.
The new chroot behavior no longer allows chrooting into such alternate
trees. In my case, that means that my backup fails.
Kind regards,
Rogier.
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Wed, 15 Oct 2014 17:18:01 GMT)
Full text and
rfc822 format available.
Message #8 received at 18736 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 10/15/2014 10:40 AM, Rogier wrote:
> Hi,
>
> Since a few months, it seems that chroot has started avoiding the
> chroot call if it can be determined to be idempotent.
> It looks like the new check is based on inode comparison - if the
> inode is the same, the chroot() call is considered idempotent, and not
> performed.
>
> However, while two directories being in the same file system and having
> the same inode number implies that they are the same directory, it
> does not necessarily imply that they have same file system path (i.e.
> use the same mountpoint), so there is no guarantee that the entire
> directory trees rooted at the two directories are also identical even
> though the directories are.This means that chroot will fail to
> chroot() in cases when the call would in fact not be idempotent.
>
> On my system (debian testing), I have / bind-mounted elsewhere, with a
> slightly different directory tree mounted beneath it, as is mounted
> beneath /. In my case, I need this so that I can make partial backups
> of the system - including some file systems but leaving out others.
> Undoubtly, there are other use-cases as well - I wouldn't be surprised
> if users of libpam-chroot can be affected by this, depending on exactly
> how they configure their chroot environments.
>
> The new chroot behavior no longer allows chrooting into such alternate
> trees. In my case, that means that my backup fails.
I didn't consider this unusual case when avoiding the chroot() call,
for efficiency (especially in the --userspec case), and to add
consistency between platforms in the handling of `chroot / true`
for non root users.
I agree with your analysis and that we should revert
to the previous behavior here, which is done in
the attached patch.
thanks!
Pádraig.
[chroot-always.patch (text/x-patch, attachment)]
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Wed, 15 Oct 2014 21:56:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 18736 <at> debbugs.gnu.org (full text, mbox):
On 10/15/2014 07:17 PM, Pádraig Brady wrote:
> I agree with your analysis and that we should revert
> to the previous behavior here, which is done in
> the attached patch.
Hi Padraig,
I also agree that chroot(1) should chroot(2) in such a case, but wouldn't
be the obvious fix to STREQ() the canonicalized DIR against "/" rather
than reverting the whole change - something like the following?
Have a nice day,
Berny
diff --git a/src/chroot.c b/src/chroot.c
index 171ced9..7f60106 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -175,7 +175,13 @@ is_root (const char* dir)
error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
quote (dir));
- return SAME_INODE (root_ino, arg_st);
+ if (! SAME_INODE (root_ino, arg_st))
+ return false;
+
+ char *resolved = canonicalize_file_name (dir);
+ bool is_res_root = resolved && STREQ ("/", resolved);
+ free (resolved);
+ return is_res_root;
}
void
--
1.8.4.5
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Wed, 15 Oct 2014 23:15:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 18736 <at> debbugs.gnu.org (full text, mbox):
On 10/15/2014 10:55 PM, Bernhard Voelker wrote:
> On 10/15/2014 07:17 PM, Pádraig Brady wrote:
>> I agree with your analysis and that we should revert
>> to the previous behavior here, which is done in
>> the attached patch.
>
> Hi Padraig,
>
> I also agree that chroot(1) should chroot(2) in such a case, but wouldn't
> be the obvious fix to STREQ() the canonicalized DIR against "/" rather
> than reverting the whole change - something like the following?
>
> Have a nice day,
> Berny
>
> diff --git a/src/chroot.c b/src/chroot.c
> index 171ced9..7f60106 100644
> --- a/src/chroot.c
> +++ b/src/chroot.c
> @@ -175,7 +175,13 @@ is_root (const char* dir)
> error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
> quote (dir));
>
> - return SAME_INODE (root_ino, arg_st);
> + if (! SAME_INODE (root_ino, arg_st))
> + return false;
> +
> + char *resolved = canonicalize_file_name (dir);
> + bool is_res_root = resolved && STREQ ("/", resolved);
> + free (resolved);
> + return is_res_root;
> }
Yes I considered that and it should work for this case.
BTW the inode check would then be moot right?
Doing that would give better performance for --userspec=... --skip-chdir
and provide consistency for non root `chroot /` across platforms.
I'm worried though there are other edge cases we've not considered,
and the benefits above are not worth the risk?
Pádraig.
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Thu, 16 Oct 2014 00:06:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 18736 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 10/16/2014 12:14 AM, Pádraig Brady wrote:
> On 10/15/2014 10:55 PM, Bernhard Voelker wrote:
>> On 10/15/2014 07:17 PM, Pádraig Brady wrote:
>>> I agree with your analysis and that we should revert
>>> to the previous behavior here, which is done in
>>> the attached patch.
>>
>> Hi Padraig,
>>
>> I also agree that chroot(1) should chroot(2) in such a case, but wouldn't
>> be the obvious fix to STREQ() the canonicalized DIR against "/" rather
>> than reverting the whole change - something like the following?
>>
>> Have a nice day,
>> Berny
>>
>> diff --git a/src/chroot.c b/src/chroot.c
>> index 171ced9..7f60106 100644
>> --- a/src/chroot.c
>> +++ b/src/chroot.c
>> @@ -175,7 +175,13 @@ is_root (const char* dir)
>> error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
>> quote (dir));
>>
>> - return SAME_INODE (root_ino, arg_st);
>> + if (! SAME_INODE (root_ino, arg_st))
>> + return false;
>> +
>> + char *resolved = canonicalize_file_name (dir);
>> + bool is_res_root = resolved && STREQ ("/", resolved);
>> + free (resolved);
>> + return is_res_root;
>> }
>
> Yes I considered that and it should work for this case.
> BTW the inode check would then be moot right?
>
> Doing that would give better performance for --userspec=... --skip-chdir
> and provide consistency for non root `chroot /` across platforms.
> I'm worried though there are other edge cases we've not considered,
> and the benefits above are not worth the risk?
I suppose a compromise is to keep most of the better performance for:
chroot --userspec=... --skip-chdir /
but do the chroot(2) unconditionally.
Updated patch is attached.
thanks,
Pádraig.
[chroot-always.patch (text/x-patch, attachment)]
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Thu, 16 Oct 2014 07:39:02 GMT)
Full text and
rfc822 format available.
Message #20 received at 18736 <at> debbugs.gnu.org (full text, mbox):
Hi Padraig,
On 10/16/2014 02:05 AM, Pádraig Brady wrote:
> From d520929586ee2063d48359aaaef8f28807604cae Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?P=C3=A1draig=20Brady?=<P <at> draigBrady.com>
> Date: Wed, 15 Oct 2014 18:08:42 +0100
> Subject: [PATCH] chroot: call chroot() unconditionally to handle bind mounted
> "/"
>
> * src/chroot.c (is_root): Adjust to compare canonicalized paths
> rather than inodes, to handle (return false in) the case where
> we have a tree that is constructed by first bind mounting "/"
> (thus having the same inode).
> (main): Unconditionally call chroot() because it's safer
> and of minimal performance benefit to avoid in this case.
> This will cause inconsistency with some platforms
> not allowing `chroot / true` for non root users.
I'm not sure that introducing the inconsistency again is the right
way to go, although I don't have a strong preference (40:60):
I'd probably go with the smaller change in is_root() and wait for
other edge cases to come (which I think is improbable).
> diff --git a/tests/misc/chroot-fail.sh b/tests/misc/chroot-fail.sh
> index 82ae23c..75f724a 100755
> --- a/tests/misc/chroot-fail.sh
> +++ b/tests/misc/chroot-fail.sh
> @@ -29,14 +29,18 @@ test $? = 125 || fail=1
> chroot --- / true # unknown option
> test $? = 125 || fail=1
>
> -# Note chroot("/") succeeds for non-root users on some systems, but not all,
> -# however we avoid the chroot() with "/" to have common behavior.
> -chroot / sh -c 'exit 2' # exit status propagation
> -test $? = 2 || fail=1
> -chroot / . # invalid command
> -test $? = 126 || fail=1
> -chroot / no_such # no such command
> -test $? = 127 || fail=1
> +# chroot("/") succeeds for non-root users on some systems, but not all.
> +if chroot / true ; then
> + can_chroot_root=1
> + chroot / sh -c 'exit 2' # exit status propagation
> + test $? = 2 || fail=1
> + chroot / . # invalid command
> + test $? = 126 || fail=1
> + chroot / no_such # no such command
> + test $? = 127 || fail=1
> +else
> + test $? = 125 || fail=1
> +fi
>
> # Ensure that --skip-chdir fails with a non-"/" argument.
> cat <<\EOF > exp || framework_failure_
> @@ -47,17 +51,19 @@ chroot --skip-chdir . env pwd >out 2>err && fail=1
> compare /dev/null out || fail=1
> compare exp err || fail=1
>
> -# Ensure we don't chroot("/") when NEWROOT is old "/".
> -ln -s / isroot || framework_failure_
> -for dir in '/' '/.' '/../' isroot; do
> - # Verify that chroot(1) succeeds and performs chdir("/")
> - # (chroot(1) of coreutils-8.23 failed to run the latter).
> - curdir=$(chroot "$dir" env pwd) || fail=1
> - test "$curdir" = '/' || fail=1
> -
> - # Test the "--skip-chdir" option.
> - curdir=$(chroot --skip-chdir "$dir" env pwd) || fail=1
> - test "$curdir" = '/' && fail=1
> -done
> +# Ensure we chdir("/") appropriately when NEWROOT is old "/".
> +if test "$can_chroot_root"; then
> + ln -s / isroot || framework_failure_
> + for dir in '/' '/.' '/../' isroot; do
> + # Verify that chroot(1) succeeds and performs chdir("/")
> + # (chroot(1) of coreutils-8.23 failed to run the latter).
> + curdir=$(chroot "$dir" env pwd) || fail=1
> + test "$curdir" = '/' || fail=1
> +
> + # Test the "--skip-chdir" option.
> + curdir=$(chroot --skip-chdir "$dir" env pwd) || fail=1
> + test "$curdir" = '/' && fail=1
> + done
> +fi
>
> Exit $fail
> -- 1.7.7.6
Minor nit: it's better to initialize 'can_chroot_root' here.
Thanks & have a nice day,
Berny
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Thu, 16 Oct 2014 10:03:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 18736 <at> debbugs.gnu.org (full text, mbox):
On 10/16/2014 08:38 AM, Bernhard Voelker wrote:
> Hi Padraig,
>
> On 10/16/2014 02:05 AM, Pádraig Brady wrote:
>> From d520929586ee2063d48359aaaef8f28807604cae Mon Sep 17 00:00:00 2001
>> From: =?UTF-8?q?P=C3=A1draig=20Brady?=<P <at> draigBrady.com>
>> Date: Wed, 15 Oct 2014 18:08:42 +0100
>> Subject: [PATCH] chroot: call chroot() unconditionally to handle bind mounted
>> "/"
>>
>> * src/chroot.c (is_root): Adjust to compare canonicalized paths
>> rather than inodes, to handle (return false in) the case where
>> we have a tree that is constructed by first bind mounting "/"
>> (thus having the same inode).
>> (main): Unconditionally call chroot() because it's safer
>> and of minimal performance benefit to avoid in this case.
>> This will cause inconsistency with some platforms
>> not allowing `chroot / true` for non root users.
>
> I'm not sure that introducing the inconsistency again is the right
> way to go, although I don't have a strong preference (40:60):
> I'd probably go with the smaller change in is_root() and wait for
> other edge cases to come (which I think is improbable).
I don't have a strong preference either but would be (60:40) the other way.
In my mind they comes under the "it's better to ask forgiveness than permission" idea.
I.E. it's better to invoke lower layer logic where possible, rather than
adding higher level logic. Given it's more risky to avoid the chroot()
I'd be inclined to wait until there were complaints about the inconsistent
behavior rather than the other way around.
>> diff --git a/tests/misc/chroot-fail.sh b/tests/misc/chroot-fail.sh
> Minor nit: it's better to initialize 'can_chroot_root' here.
Good point. Done.
thanks,
Pádraig.
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18736
; Package
coreutils
.
(Thu, 16 Oct 2014 10:31:01 GMT)
Full text and
rfc822 format available.
Message #26 received at 18736 <at> debbugs.gnu.org (full text, mbox):
On 10/16/2014 12:02 PM, Pádraig Brady wrote:
> I don't have a strong preference either but would be (60:40) the other way.
> In my mind they comes under the "it's better to ask forgiveness than permission" idea.
> I.E. it's better to invoke lower layer logic where possible, rather than
> adding higher level logic. Given it's more risky to avoid the chroot()
> I'd be inclined to wait until there were complaints about the inconsistent
> behavior rather than the other way around.
Another possibility would be to suppress issuing an error diagnostic
for a chroot() failure when DIR is "/" ...
Have a nice day,
Berny
bug closed, send any further explanations to
18736 <at> debbugs.gnu.org and Rogier <rogier777 <at> gmail.com>
Request was from
Pádraig Brady <P <at> draigBrady.com>
to
control <at> debbugs.gnu.org
.
(Fri, 17 Oct 2014 00:41:03 GMT)
Full text and
rfc822 format available.
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Fri, 14 Nov 2014 12:24:04 GMT)
Full text and
rfc822 format available.
This bug report was last modified 10 years and 226 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.