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