[libvirt] [PATCH] Introduce virConnectCrashDaemon API

Ján Tomko jtomko at redhat.com
Tue Apr 1 07:34:45 UTC 2014


This reduces the affect of an unexpected DoS vulnerablity in libvirtd.
---
 include/libvirt/libvirt.h.in | 13 +++++++++++++
 src/driver.h                 |  5 +++++
 src/libvirt.c                | 32 +++++++++++++++++++++++++++++++
 src/libvirt_private.syms     |  1 +
 src/libvirt_public.syms      |  4 ++++
 src/qemu/qemu_driver.c       | 16 ++++++++++++++++
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 15 ++++++++++++++-
 src/util/virutil.c           | 23 ++++++++++++++++++++++
 src/util/virutil.h           |  1 +
 tools/virsh-host.c           | 45 ++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 930b7e8..d0db483 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1540,6 +1540,19 @@ char *                  virConnectGetURI        (virConnectPtr conn);
 char *                  virConnectGetSysinfo    (virConnectPtr conn,
                                                  unsigned int flags);
 
+typedef enum {
+    VIR_CONNECT_CRASH_RANDOM      = 0, /* Randomly choose one crash method */
+    VIR_CONNECT_CRASH_NULL_PTR    = 1, /* Null pointer access */
+    VIR_CONNECT_CRASH_DOUBLE_FREE = 2, /* Double free */
+
+# ifdef VIR_ENUM_SENTINELS
+    VIR_CONNECT_CRASH_LAST
+# endif
+} virConnectCrashFlags;
+
+int                     virConnectCrashDaemon   (virConnectPtr conn,
+                                                 unsigned int flags);
+
 int virConnectSetKeepAlive(virConnectPtr conn,
                            int interval,
                            unsigned int count);
diff --git a/src/driver.h b/src/driver.h
index e66fc7a..b899a4f 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1149,6 +1149,10 @@ typedef int
                                      unsigned int flags,
                                      int cancelled);
 
+typedef int
+(*virDrvConnectCrashDaemon)(virConnectPtr conn,
+                            unsigned int flags);
+
 typedef struct _virDriver virDriver;
 typedef virDriver *virDriverPtr;
 
@@ -1363,6 +1367,7 @@ struct _virDriver {
     virDrvDomainMigrateFinish3Params domainMigrateFinish3Params;
     virDrvDomainMigrateConfirm3Params domainMigrateConfirm3Params;
     virDrvConnectGetCPUModelNames connectGetCPUModelNames;
+    virDrvConnectCrashDaemon connectCrashDaemon;
 };
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 4454829..739c747 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -1717,6 +1717,38 @@ virConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
 
 
 /**
+ * virConnectCrashDaemon:
+ * @conn: pointer to a hypervisor connection
+ * @flags: one of virConnectCrashDaemonFlags
+ *
+ * Crashes the daemon by the method selected via @flags.
+ *
+ * Returns -1 on error or doesn't return at all in case of success.
+ */
+int
+virConnectCrashDaemon(virConnectPtr conn, unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, flags=%x", conn, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+
+    if (conn->driver->connectCrashDaemon) {
+        if (conn->driver->connectCrashDaemon(conn, flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
  * virConnectGetMaxVcpus:
  * @conn: pointer to the hypervisor connection
  * @type: value of the 'type' attribute in the <domain> element
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 38fbf63..18f91b2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1983,6 +1983,7 @@ virUSBDeviceSetUsedBy;
 
 # util/virutil.h
 virCompareLimitUlong;
+virCrashDaemon;
 virDoubleToStr;
 virEnumFromString;
 virEnumToString;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 9ab0c92..378d256 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -650,5 +650,9 @@ LIBVIRT_1.2.3 {
         virDomainCoreDumpWithFormat;
 } LIBVIRT_1.2.1;
 
+LIBVIRT_1.2.4 {
+    global:
+        virConnectCrashDaemon;
+} LIBVIRT_1.2.3;
 
 # .... define new API here using predicted next version number ....
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b032441..cd258b7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16661,6 +16661,21 @@ qemuConnectGetCPUModelNames(virConnectPtr conn,
 }
 
 
+static int
+qemuConnectCrashDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
+                       unsigned int flags)
+{
+    if (flags >= VIR_CONNECT_CRASH_LAST) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("Unsupported crash method %u"),
+                       flags);
+        return -1;
+    }
+
+    return virCrashDaemon(flags);
+}
+
+
 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
     .name = QEMU_DRIVER_NAME,
@@ -16851,6 +16866,7 @@ static virDriver qemuDriver = {
     .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */
     .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */
     .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
+    .connectCrashDaemon = qemuConnectCrashDaemon, /* 1.2.4 */
 };
 
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index ed7dde6..b01dd5b 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -7800,6 +7800,7 @@ static virDriver remote_driver = {
     .domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */
     .domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */
     .connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.3 */
+    .connectCrashDaemon = remoteConnectCrashDaemon, /* 1.2.4 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 6c445cc..7eb7f83 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -442,6 +442,13 @@ struct remote_connect_get_sysinfo_ret {
     remote_nonnull_string sysinfo;
 };
 
+struct remote_connect_crash_daemon_args {
+    unsigned int flags;
+};
+
+struct remote_connect_crash_daemon_ret {
+    int retval;
+};
 struct remote_connect_get_uri_ret {
     remote_nonnull_string uri;
 };
@@ -5275,5 +5282,11 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:core_dump
      */
-    REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT = 334
+    REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT = 334,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_CONNECT_CRASH_DAEMON = 335
 };
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 9be1590..97215d0 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -78,6 +78,7 @@
 #include "vircommand.h"
 #include "nonblocking.h"
 #include "virprocess.h"
+#include "virrandom.h"
 #include "virstring.h"
 #include "virutil.h"
 
@@ -2204,3 +2205,25 @@ void virUpdateSelfLastChanged(const char *path)
         selfLastChanged = sb.st_ctime;
     }
 }
+
+int virCrashDaemon(unsigned int flags)
+{
+    char **bla = NULL;
+    char **tmp;
+
+    if (flags == VIR_CONNECT_CRASH_RANDOM)
+        flags = virRandomInt(VIR_CONNECT_CRASH_LAST) + 1;
+
+    switch (flags) {
+    case VIR_CONNECT_CRASH_NULL_PTR:
+        bla[1] = bla[0];
+        /* fallthrough */
+    case VIR_CONNECT_CRASH_DOUBLE_FREE:
+        if (VIR_ALLOC_N(bla, 2) < 0)
+            return -1;
+        tmp = bla;
+        VIR_FREE(tmp);
+        VIR_FREE(bla);
+    }
+    return -1;
+}
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 1f2efd5..aaf1bef 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -202,4 +202,5 @@ bool virIsSUID(void);
 time_t virGetSelfLastChanged(void);
 void virUpdateSelfLastChanged(const char *path);
 
+int virCrashDaemon(unsigned int flags);
 #endif /* __VIR_UTIL_H__ */
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index cac6086..28e5e3b 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -939,6 +939,45 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd)
     goto cleanup;
 }
 
+/*
+ * "crash" command
+ */
+static const vshCmdInfo info_crash[] = {
+    {.name = "help",
+     .data = N_("crash the daemon")
+    },
+    {.name = "desc",
+     .data = N_("Crash the libvirt daemon using the selected method.")
+    },
+    {.name = NULL}
+};
+
+static const vshCmdOptDef opts_crash[] = {
+    {.name = "null",
+     .type = VSH_OT_BOOL,
+     .help = N_("Crash by null pointer access")
+    },
+    {.name = "doublefree",
+     .type = VSH_OT_BOOL,
+     .help = N_("Crash by double free")
+    },
+    {.name = NULL}
+};
+
+static bool
+cmdCrash(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+    unsigned int flags = VIR_CONNECT_CRASH_RANDOM;
+
+    if (vshCommandOptBool(cmd, "null"))
+        flags = VIR_CONNECT_CRASH_NULL_PTR;
+    if (vshCommandOptBool(cmd, "doublefree"))
+        flags = VIR_CONNECT_CRASH_DOUBLE_FREE;
+
+    virConnectCrashDaemon(ctl->conn, flags);
+    return true;
+}
+
 const vshCmdDef hostAndHypervisorCmds[] = {
     {.name = "capabilities",
      .handler = cmdCapabilities,
@@ -1024,5 +1063,11 @@ const vshCmdDef hostAndHypervisorCmds[] = {
      .info = info_version,
      .flags = 0
     },
+    {.name = "crash",
+     .handler = cmdCrash,
+     .opts = opts_crash,
+     .info = info_crash,
+     .flags = 0
+    },
     {.name = NULL}
 };
-- 
1.8.3.2




More information about the libvir-list mailing list