From d520929586ee2063d48359aaaef8f28807604cae Mon Sep 17 00:00:00 2001 From: Pádraig Brady Date: Wed, 15 Oct 2014 18:08:42 +0100 Subject: 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 --- src/chroot.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'src/chroot.c') 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")); -- cgit v1.2.3-54-g00ecf