902636
From c7ae38df696e4be432fd418c670dcea892b910a7 Mon Sep 17 00:00:00 2001
902636
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
902636
Date: Mon, 27 Jan 2020 19:01:27 +0100
902636
Subject: [PATCH 056/116] virtiofsd: sandbox mount namespace
902636
MIME-Version: 1.0
902636
Content-Type: text/plain; charset=UTF-8
902636
Content-Transfer-Encoding: 8bit
902636
902636
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
902636
Message-id: <20200127190227.40942-53-dgilbert@redhat.com>
902636
Patchwork-id: 93504
902636
O-Subject: [RHEL-AV-8.2 qemu-kvm PATCH 052/112] virtiofsd: sandbox mount namespace
902636
Bugzilla: 1694164
902636
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
902636
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
902636
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
902636
902636
From: Stefan Hajnoczi <stefanha@redhat.com>
902636
902636
Use a mount namespace with the shared directory tree mounted at "/" and
902636
no other mounts.
902636
902636
This prevents symlink escape attacks because symlink targets are
902636
resolved only against the shared directory and cannot go outside it.
902636
902636
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
902636
Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
902636
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
902636
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
902636
(cherry picked from commit 5baa3b8e95064c2434bd9e2f312edd5e9ae275dc)
902636
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
902636
---
902636
 tools/virtiofsd/passthrough_ll.c | 89 ++++++++++++++++++++++++++++++++++++++++
902636
 1 file changed, 89 insertions(+)
902636
902636
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
902636
index e2e2211..0570453 100644
902636
--- a/tools/virtiofsd/passthrough_ll.c
902636
+++ b/tools/virtiofsd/passthrough_ll.c
902636
@@ -50,6 +50,7 @@
902636
 #include <stdlib.h>
902636
 #include <string.h>
902636
 #include <sys/file.h>
902636
+#include <sys/mount.h>
902636
 #include <sys/syscall.h>
902636
 #include <sys/xattr.h>
902636
 #include <unistd.h>
902636
@@ -1943,6 +1944,58 @@ static void print_capabilities(void)
902636
     printf("}\n");
902636
 }
902636
 
902636
+/* This magic is based on lxc's lxc_pivot_root() */
902636
+static void setup_pivot_root(const char *source)
902636
+{
902636
+    int oldroot;
902636
+    int newroot;
902636
+
902636
+    oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
902636
+    if (oldroot < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "open(/): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    newroot = open(source, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
902636
+    if (newroot < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "open(%s): %m\n", source);
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (fchdir(newroot) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (syscall(__NR_pivot_root, ".", ".") < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "pivot_root(., .): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (fchdir(oldroot) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "fchdir(oldroot): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (mount("", ".", "", MS_SLAVE | MS_REC, NULL) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "mount(., MS_SLAVE | MS_REC): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (umount2(".", MNT_DETACH) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "umount2(., MNT_DETACH): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (fchdir(newroot) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    close(newroot);
902636
+    close(oldroot);
902636
+}
902636
+
902636
 static void setup_proc_self_fd(struct lo_data *lo)
902636
 {
902636
     lo->proc_self_fd = open("/proc/self/fd", O_PATH);
902636
@@ -1952,6 +2005,39 @@ static void setup_proc_self_fd(struct lo_data *lo)
902636
     }
902636
 }
902636
 
902636
+/*
902636
+ * Make the source directory our root so symlinks cannot escape and no other
902636
+ * files are accessible.
902636
+ */
902636
+static void setup_mount_namespace(const char *source)
902636
+{
902636
+    if (unshare(CLONE_NEWNS) != 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWNS): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "mount(/, MS_REC|MS_PRIVATE): %m\n");
902636
+        exit(1);
902636
+    }
902636
+
902636
+    if (mount(source, source, NULL, MS_BIND, NULL) < 0) {
902636
+        fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source);
902636
+        exit(1);
902636
+    }
902636
+
902636
+    setup_pivot_root(source);
902636
+}
902636
+
902636
+/*
902636
+ * Lock down this process to prevent access to other processes or files outside
902636
+ * source directory.  This reduces the impact of arbitrary code execution bugs.
902636
+ */
902636
+static void setup_sandbox(struct lo_data *lo)
902636
+{
902636
+    setup_mount_namespace(lo->source);
902636
+}
902636
+
902636
 int main(int argc, char *argv[])
902636
 {
902636
     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
902636
@@ -2052,6 +2138,7 @@ int main(int argc, char *argv[])
902636
     }
902636
 
902636
     lo.root.fd = open(lo.source, O_PATH);
902636
+
902636
     if (lo.root.fd == -1) {
902636
         fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
902636
         exit(1);
902636
@@ -2075,6 +2162,8 @@ int main(int argc, char *argv[])
902636
     /* Must be after daemonize to get the right /proc/self/fd */
902636
     setup_proc_self_fd(&lo);
902636
 
902636
+    setup_sandbox(&lo);
902636
+
902636
     /* Block until ctrl+c or fusermount -u */
902636
     ret = virtio_loop(se);
902636
 
902636
-- 
902636
1.8.3.1
902636