diff options
author | Pádraig Brady <P@draigBrady.com> | 2014-10-15 18:08:42 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2014-10-16 00:45:32 +0100 |
commit | d520929586ee2063d48359aaaef8f28807604cae (patch) | |
tree | 3922530539173d01e62ae04aedd252d61c3d7ecd /src | |
parent | 84616da89dbfc81e22f8c2fd077f1d61d788522c (diff) | |
download | coreutils-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.c | 29 |
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")); |