[libvirt] [PATCH RFC 6/7] qemu: Spawn qemu under mount namespace

Michal Privoznik mprivozn at redhat.com
Mon Nov 14 16:43:30 UTC 2016


Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/qemu/qemu_domain.c  | 233 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_domain.h  |   8 ++
 src/qemu/qemu_process.c |  13 +++
 3 files changed, 254 insertions(+)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 8cba755..3a0170c 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -55,6 +55,7 @@
 
 #include <sys/time.h>
 #include <fcntl.h>
+#include <sys/mount.h>
 
 #include <libxml/xpathInternals.h>
 
@@ -86,6 +87,21 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob, QEMU_ASYNC_JOB_LAST,
               "start",
 );
 
+#define QEMU_DEV_MAJ_MEMORY  1
+#define QEMU_DEV_MAJ_TTY     5
+#define QEMU_DEV_MAJ_KVM     10
+#define QEMU_DEV_MAJ_PTY     136
+
+#define QEMU_DEV_MIN_CONSOLE 1
+#define QEMU_DEV_MIN_FULL    7
+#define QEMU_DEV_MIN_FUSE    229
+#define QEMU_DEV_MIN_KVM     232
+#define QEMU_DEV_MIN_NULL    3
+#define QEMU_DEV_MIN_PTMX    2
+#define QEMU_DEV_MIN_RANDOM  8
+#define QEMU_DEV_MIN_TTY     0
+#define QEMU_DEV_MIN_URANDOM 9
+#define QEMU_DEV_MIN_ZERO    5
 
 struct _qemuDomainLogContext {
     int refs;
@@ -6658,3 +6674,220 @@ qemuDomainSupportsVideoVga(virDomainVideoDefPtr video,
 
     return true;
 }
+
+
+static int
+qemuDomainPopulateDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
+                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
+                          const char *path)
+{
+    int ret = -1;
+    virFileDevices devs[] = {
+        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_NULL, 0666, "/null" },
+        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_ZERO, 0666, "/zero" },
+        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_FULL, 0666, "/full" },
+        { QEMU_DEV_MAJ_KVM,  QEMU_DEV_MIN_KVM, 0660, "/kvm"},
+        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_RANDOM, 0666, "/random" },
+        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_URANDOM, 0666, "/urandom" },
+        { QEMU_DEV_MAJ_TTY, QEMU_DEV_MIN_TTY, 0666, "/tty" },
+        { 0, 0, 0, NULL},
+    };
+
+    if (virFilePopulateDevices(path, devs) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+
+static int
+qemuDomainSetupDev(virQEMUDriverPtr driver,
+                   virDomainObjPtr vm,
+                   const char *path)
+{
+    char *mount_options = NULL;
+    char *opts = NULL;
+    int ret = -1;
+
+    VIR_DEBUG("Setting up /dev/ for domain %s", vm->def->name);
+
+    mount_options = virSecurityManagerGetMountOptions(driver->securityManager,
+                                                      vm->def);
+
+    if (!mount_options &&
+        VIR_STRDUP(mount_options, "") < 0)
+        goto cleanup;
+
+    /*
+     * tmpfs is limited to 64kb, since we only have device nodes in there
+     * and don't want to DOS the entire OS RAM usage
+     */
+    if (virAsprintf(&opts,
+                    "mode=755,size=65536%s", mount_options) < 0)
+        goto cleanup;
+
+    if (virFileSetupDev(path, opts) < 0)
+        goto cleanup;
+
+    if (qemuDomainPopulateDevices(driver, vm, path) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(opts);
+    VIR_FREE(mount_options);
+    return ret;
+}
+
+
+static int
+qemuDomainSetupDevPTS(virQEMUDriverPtr driver,
+                      virDomainObjPtr vm,
+                      const char *path)
+{
+    char *mount_options = NULL;
+    char *opts = NULL;
+    int ret = -1;
+    const gid_t ptsgid = 5;
+
+    mount_options = virSecurityManagerGetMountOptions(driver->securityManager,
+                                                      vm->def);
+
+    if (!mount_options &&
+        VIR_STRDUP(mount_options, "") < 0)
+        goto cleanup;
+
+    if (virAsprintf(&opts, "newinstance,ptmxmode=0666,mode=0620,gid=%u%s",
+                    ptsgid, (mount_options ? mount_options : "")) < 0)
+        goto cleanup;
+
+    if (virFileSetupDevPTS(path, opts, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(opts);
+    VIR_FREE(mount_options);
+    return ret;
+}
+
+
+int
+qemuDomainBuildNamespace(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    const unsigned long mount_flags = MS_MOVE;
+    char *devPath = NULL;
+    char *devptsPath = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&devPath, "%s/%s.dev",
+                    cfg->stateDir, vm->def->name) < 0 ||
+        virAsprintf(&devptsPath, "%s/%s.devpts",
+                    cfg->stateDir, vm->def->name) < 0)
+        goto cleanup;
+
+    if (qemuDomainSetupDev(driver, vm, devPath) < 0)
+        goto cleanup;
+
+    if (mount(devPath, "/dev", NULL, mount_flags, NULL) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to mount %s on /dev"),
+                             devPath);
+        goto cleanup;
+    }
+
+    if (qemuDomainSetupDevPTS(driver, vm, devptsPath) < 0)
+        goto cleanup;
+
+    if (virFileMakePath("/dev/pts") < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Cannot create /dev/pts"));
+        goto cleanup;
+    }
+
+    if (mount(devptsPath, "/dev/pts", NULL, mount_flags, NULL) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to mount %s on /dev/pts"),
+                             devptsPath);
+        goto cleanup;
+    }
+
+    if (virFileBindMountDevice("/dev/pts/ptmx", "/dev/ptmx") < 0)
+        goto cleanup;
+
+    VIR_DEBUG("blaaah: %d", system("ls -l /dev > /tmp/blaaah"));
+    VIR_DEBUG("blaaah: %d", system("ls -l /dev/pts >> /tmp/blaaah"));
+    VIR_DEBUG("blaaah: %d", system("mount >> /tmp/blaaah"));
+    ret = 0;
+ cleanup:
+    VIR_FREE(devPath);
+    return ret;
+}
+
+
+int
+qemuDomainCreateNamespace(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    int ret = -1;
+    char *path = NULL;
+
+    if (virAsprintf(&path, "%s/%s.dev",
+                    cfg->stateDir, vm->def->name) < 0)
+        goto cleanup;
+
+    if (virFileMakePath(path) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to create %s"),
+                             path);
+        goto cleanup;
+    }
+
+    VIR_FREE(path);
+    if (virAsprintf(&path, "%s/%s.devpts",
+                    cfg->stateDir, vm->def->name) < 0)
+        goto cleanup;
+
+    if (virFileMakePath(path) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to create %s"),
+                             path);
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(path);
+    virObjectUnref(cfg);
+    return ret;
+}
+
+
+void
+qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    char *path;
+
+    if (virAsprintf(&path, "%s/%s.dev",
+                    cfg->stateDir, vm->def->name) < 0)
+        goto cleanup;
+
+    virFileDeleteTree(path);
+
+    VIR_FREE(path);
+    if (virAsprintf(&path, "%s/%s.devpts",
+                    cfg->stateDir, vm->def->name) < 0)
+        goto cleanup;
+
+    virFileDeleteTree(path);
+ cleanup:
+    virObjectUnref(cfg);
+    VIR_FREE(path);
+}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 0c1689b..8e6d199 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -784,4 +784,12 @@ int qemuDomainCheckMonitor(virQEMUDriverPtr driver,
 bool qemuDomainSupportsVideoVga(virDomainVideoDefPtr video,
                                 virQEMUCapsPtr qemuCaps);
 
+int qemuDomainBuildNamespace(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm);
+
+int qemuDomainCreateNamespace(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm);
+
+void qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm);
 #endif /* __QEMU_DOMAIN_H__ */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 09b2a72..522ac19 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2664,6 +2664,12 @@ static int qemuProcessHook(void *data)
     if (virSecurityManagerClearSocketLabel(h->driver->securityManager, h->vm->def) < 0)
         goto cleanup;
 
+    if (virProcessSetupPrivateNS() < 0)
+        goto cleanup;
+
+    if (qemuDomainBuildNamespace(h->driver, h->vm) < 0)
+        goto cleanup;
+
     if (virDomainNumatuneGetMode(h->vm->def->numa, -1, &mode) == 0) {
         if (mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT &&
             h->cfg->cgroupControllers & (1 << VIR_CGROUP_CONTROLLER_CPUSET) &&
@@ -5431,6 +5437,11 @@ qemuProcessLaunch(virConnectPtr conn,
 
     qemuDomainLogContextMarkPosition(logCtxt);
 
+    VIR_DEBUG("Building mount namespace");
+
+    if (qemuDomainCreateNamespace(driver, vm) < 0)
+        goto cleanup;
+
     VIR_DEBUG("Clear emulator capabilities: %d",
               cfg->clearEmulatorCapabilities);
     if (cfg->clearEmulatorCapabilities)
@@ -6200,6 +6211,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
         }
     }
 
+    qemuDomainDeleteNamespace(driver, vm);
+
     vm->taint = 0;
     vm->pid = -1;
     virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
-- 
2.8.4




More information about the libvir-list mailing list