]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
chroot: make changing root check more robust
authorPádraig Brady <P@draigBrady.com>
Sun, 18 May 2014 16:20:06 +0000 (17:20 +0100)
committerPádraig Brady <P@draigBrady.com>
Wed, 21 May 2014 10:18:27 +0000 (11:18 +0100)
* src/chroot.c (is_root): A new helper function to
determine if the passed argument is the root directory
based on inode comparison.
(main): Use the new helper rather than comparing strings.
* tests/misc/chroot-fail.sh: Add cases for alternative root paths.

src/chroot.c
tests/misc/chroot-fail.sh

index 0ded25dec2a61b009f3c0dda42291b6113db30d7..a623f883a977abd4a9159695870426f01d6be9fb 100644 (file)
@@ -28,6 +28,7 @@
 #include "ignore-value.h"
 #include "mgetgroups.h"
 #include "quote.h"
+#include "root-dev-ino.h"
 #include "userspec.h"
 #include "xstrtol.h"
 
@@ -158,6 +159,22 @@ parse_additional_groups (char const *groups, GETGROUPS_T **pgids,
   return ret;
 }
 
+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);
+}
+
 void
 usage (int status)
 {
@@ -253,7 +270,7 @@ main (int argc, char **argv)
 
   /* 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], "/"))
+  if (! is_root (argv[optind]))
     {
       /* We have to look up users and groups twice.
         - First, outside the chroot to load potentially necessary passwd/group
index 56be8e23164d45338fd0fb454a47606590e78792..b171ec40c760e708ba9349d729eb4b7cbb681e50 100755 (executable)
@@ -39,7 +39,9 @@ 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
+for dir in '/' '/.' '/../'; do
+  curdir=$(chroot "$dir" env pwd) || fail=1
+  test "$curdir" = '/' && fail=1
+done
 
 Exit $fail