summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-02-24 08:33:31 -0500
committerColin Walters <walters@verbum.org>2013-02-24 10:55:37 -0500
commit04028db1d9f7909f4c86d9b4d4a8640e65fd11f1 (patch)
tree6e2b5ffaa4a5813b150c5f8d54a79e0e782e4560
parentc4388a624de392a72a5826b0d61c2aa21f283ede (diff)
downloadlinux-user-chroot-04028db1d9f7909f4c86d9b4d4a8640e65fd11f1.tar.gz
[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>
-rw-r--r--src/linux-user-chroot.c31
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 / */