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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list