summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--src/chroot.c36
-rwxr-xr-xtests/misc/chroot-fail.sh24
3 files changed, 37 insertions, 26 deletions
diff --git a/NEWS b/NEWS
index c204b680d..93e3a0980 100644
--- a/NEWS
+++ b/NEWS
@@ -82,6 +82,9 @@ GNU coreutils NEWS -*- outline -*-
** Changes in behavior
+ chroot with an argument of "/" no longer implicitly changes the current
+ directory to "/", allowing changing only user credentials for a command.
+
ls with none of LS_COLORS or COLORTERM environment variables set,
will now honor an empty or unknown TERM environment variable,
and not output colors even with --colors=always.
diff --git a/src/chroot.c b/src/chroot.c
index 8b08b84ea..a2debac1c 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -225,21 +225,27 @@ main (int argc, char **argv)
usage (EXIT_CANCELED);
}
- /* We have to look up users and groups twice.
- - First, outside the chroot to load potentially necessary passwd/group
- parsing plugins (e.g. NSS);
- - Second, inside chroot to redo the parsing in case IDs are different. */
- if (userspec)
- ignore_value (parse_user_spec (userspec, &uid, &gid, NULL, NULL));
- if (groups && *groups)
- ignore_value (parse_additional_groups (groups, &out_gids, &n_gids, false));
-
- if (chroot (argv[optind]) != 0)
- error (EXIT_CANCELED, errno, _("cannot change root directory to %s"),
- argv[optind]);
-
- if (chdir ("/"))
- error (EXIT_CANCELED, errno, _("cannot chdir to root directory"));
+ /* Only do chroot specific actions if actually changing root.
+ The main difference here is that we don't change working dir. */
+ if (! STREQ (argv[optind], "/"))
+ {
+ /* We have to look up users and groups twice.
+ - First, outside the chroot to load potentially necessary passwd/group
+ parsing plugins (e.g. NSS);
+ - Second, inside chroot to redo parsing in case IDs are different. */
+ if (userspec)
+ ignore_value (parse_user_spec (userspec, &uid, &gid, NULL, NULL));
+ if (groups && *groups)
+ ignore_value (parse_additional_groups (groups, &out_gids, &n_gids,
+ false));
+
+ if (chroot (argv[optind]) != 0)
+ error (EXIT_CANCELED, errno, _("cannot change root directory to %s"),
+ argv[optind]);
+
+ if (chdir ("/"))
+ error (EXIT_CANCELED, errno, _("cannot chdir to root directory"));
+ }
if (argc == optind + 1)
{
diff --git a/tests/misc/chroot-fail.sh b/tests/misc/chroot-fail.sh
index 11f03458c..56be8e231 100755
--- a/tests/misc/chroot-fail.sh
+++ b/tests/misc/chroot-fail.sh
@@ -28,16 +28,18 @@ test $? = 125 || fail=1
chroot --- / true # unknown option
test $? = 125 || fail=1
-# chroot("/") succeeds for non-root users on some systems, but not all.
-if chroot / true ; then
- 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
+# Note chroot("/") succeeds for non-root users on some systems, but not all,
+# however we avoid the chroot() with "/" to have common behvavior.
+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
+
+# Ensure we don't chdir("/") when not changing root
+# to allow only changing user ids for a command.
+curdir=$(chroot / env pwd) || fail=1
+test "$curdir" = '/' && fail=1
Exit $fail