summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2014-10-15 18:08:42 +0100
committerPádraig Brady <P@draigBrady.com>2014-10-16 00:45:32 +0100
commitd520929586ee2063d48359aaaef8f28807604cae (patch)
tree3922530539173d01e62ae04aedd252d61c3d7ecd /src
parent84616da89dbfc81e22f8c2fd077f1d61d788522c (diff)
downloadcoreutils-d520929586ee2063d48359aaaef8f28807604cae.tar.xz
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
Diffstat (limited to 'src')
-rw-r--r--src/chroot.c29
1 files changed, 12 insertions, 17 deletions
diff --git a/src/chroot.c b/src/chroot.c
index 171ced98a..3aacafae8 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -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"));