1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-06-01 15:26:29 +02:00

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.
* tests/misc/chroot-fail.sh: Adjust appropriately.
* NEWS: Mention the bug fixes.
Fixes http://bugs.gnu.org/18736
This commit is contained in:
Pádraig Brady
2014-10-15 18:08:42 +01:00
parent 84616da89d
commit d520929586
3 changed files with 42 additions and 42 deletions
+5 -6
View File
@@ -7,6 +7,11 @@ GNU coreutils NEWS -*- outline -*-
dd supports more robust SIGINFO/SIGUSR1 handling for outputting statistics.
Previously those signals may have inadvertently terminated the process.
chroot again calls chroot(DIR) and chdir("/"), even if DIR is "/".
This handles separate bind mounted "/" trees, and environments
depending on the implicit chdir("/").
[bugs introduced in coreutils-8.23]
cp no longer issues an incorrect warning about directory hardlinks when a
source directory is specified multiple times. Now, consistent with other
file types, a warning is issued for source directories with duplicate names,
@@ -25,12 +30,6 @@ GNU coreutils NEWS -*- outline -*-
dd accepts a new status=progress level to print data transfer statistics
on stderr approximately every second.
** Changes in behavior
chroot changes the current directory to "/" in again - unless the above new
--skip-chdir option is specified.
[bug introduced in coreutils-8.23]
** Improvements
cp,install,mv will convert smaller runs of NULs in the input to holes,
+12 -17
View File
@@ -162,20 +162,17 @@ parse_additional_groups (char const *groups, GETGROUPS_T **pgids,
return ret;
}
/* Return whether the passed path is equivalent to "/".
Note we don't compare against get_root_dev_ino() as "/"
could be bind mounted to a separate location. */
static bool
is_root (const char* dir)
{
struct dev_ino root_ino;
if (! get_root_dev_ino (&root_ino))
error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
quote ("/"));
struct stat arg_st;
if (stat (dir, &arg_st) == -1)
error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
quote (dir));
return SAME_INODE (root_ino, arg_st);
char *resolved = canonicalize_file_name (dir);
bool is_res_root = resolved && STREQ ("/", resolved);
free (resolved);
return is_res_root;
}
void
@@ -291,8 +288,6 @@ main (int argc, char **argv)
usage (EXIT_CANCELED);
}
/* Only do chroot specific actions if actually changing root.
The main difference here is that we don't change working dir. */
if (! is_oldroot)
{
/* We have to look up users and groups twice.
@@ -328,12 +323,12 @@ main (int argc, char **argv)
n_gids = ngroups;
}
#endif
if (chroot (newroot) != 0)
error (EXIT_CANCELED, errno, _("cannot change root directory to %s"),
newroot);
}
if (chroot (newroot) != 0)
error (EXIT_CANCELED, errno, _("cannot change root directory to %s"),
newroot);
if (! skip_chdir && chdir ("/"))
error (EXIT_CANCELED, errno, _("cannot chdir to root directory"));
+25 -19
View File
@@ -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
# 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
# Test the "--skip-chdir" option.
curdir=$(chroot --skip-chdir "$dir" env pwd) || fail=1
test "$curdir" = '/' && fail=1
done
fi
Exit $fail