[linux-user-chroot] [SECURITY] Use fsuid to lookup bind mount paths and chroot target



commit 04028db1d9f7909f4c86d9b4d4a8640e65fd11f1
Author: Colin Walters <walters verbum org>
Date:   Sun Feb 24 08:33:31 2013 -0500

    [SECURITY] Use fsuid to lookup bind mount paths and chroot target
    
    Otherise, the user can access otherwise inaccessible directories like
    this:
    
    $ linux-user-chroot --mount-bind /root/.virsh ~/mnt / /bin/sh
    
    Also, we should check the accessibility of the chroot target; this is
    much harder to exploit because you'd need an executable inside the
    chroot that can be run.
    
    Reported-by: Marc Deslauriers <marc deslauriers canonical com>
    Reported-by: Ryan Lortie <desrt desrt ca>
    Reviewed-by: Marc Deslauriers <marc deslauriers canonical com>
    Signed-off-by: Colin Walters <walters verbum org>

 src/linux-user-chroot.c |   31 ++++++++++++++++++++++++++++---
 1 files changed, 28 insertions(+), 3 deletions(-)
---
diff --git a/src/linux-user-chroot.c b/src/linux-user-chroot.c
index ac542ad..6cac578 100644
--- a/src/linux-user-chroot.c
+++ b/src/linux-user-chroot.c
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/prctl.h>
+#include <sys/fsuid.h>
 #include <sys/mount.h>
 #include <sys/syscall.h>
 #include <sys/wait.h>
@@ -110,6 +111,28 @@ reverse_mount_list (MountSpec *mount)
   return prev;
 }
 
+/**
+ * fsuid_chdir:
+ * @uid: User id we should use
+ * @path: Path string
+ *
+ * Like chdir() except we use the filesystem privileges of @uid.
+ */
+static int
+fsuid_chdir (uid_t       uid,
+             const char *path)
+{
+  int errsv;
+  int ret;
+  /* Note we don't check errors here because we can't, basically */
+  (void) setfsuid (uid);
+  ret = chdir (path);
+  errsv = errno;
+  (void) setfsuid (0);
+  errno = errsv;
+  return ret;
+}
+
 int
 main (int      argc,
       char   **argv)
@@ -330,7 +353,9 @@ main (int      argc,
             }
           else if (bind_mount_iter->type == MOUNT_SPEC_BIND)
             {
-              if (mount (bind_mount_iter->source, dest,
+              if (fsuid_chdir (ruid, bind_mount_iter->source) < 0)
+                fatal ("Couldn't chdir to bind mount source");
+              if (mount (".", dest,
                          NULL, MS_BIND | MS_PRIVATE, NULL) < 0)
                 fatal_errno ("mount (MS_BIND)");
             }
@@ -345,10 +370,10 @@ main (int      argc,
           free (dest);
         }
 
-      if (chdir (chroot_dir) < 0)
+      if (fsuid_chdir (ruid, chroot_dir) < 0)
         fatal_errno ("chdir");
 
-      if (mount (chroot_dir, chroot_dir, NULL, MS_BIND | MS_PRIVATE, NULL) < 0)
+      if (mount (".", ".", NULL, MS_BIND | MS_PRIVATE, NULL) < 0)
         fatal_errno ("mount (MS_BIND)");
 
       /* Only move if we're not actually just using / */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]