diff options
author | Colin Walters <walters@verbum.org> | 2013-02-24 08:33:31 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2013-02-24 10:55:37 -0500 |
commit | 04028db1d9f7909f4c86d9b4d4a8640e65fd11f1 (patch) | |
tree | 6e2b5ffaa4a5813b150c5f8d54a79e0e782e4560 | |
parent | c4388a624de392a72a5826b0d61c2aa21f283ede (diff) | |
download | linux-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.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 / */ |