On 03/02/2017 03:02 AM, Caoxinhua wrote:
From 6b42792cfee124a742999e698e348e99b382ba16 Mon Sep 17 00:00:00
2001
From: c00207022 <caoxinhua(a)huawei.com>
I cannot 'git am -3' this patch - please follow the guidelines :
http://libvirt.org/hacking.html
and use git send-email rather than attaching some patch
Also we prefer to have a "real name" associated with patches not just an
email address.
Finally when you're posting followup patches - it's considered good
etiquette to include a link to previous patches either in a cover letter
or under the --- after your signoff so the reviewer can check the
history. The prior patch I see on this is:
http://www.redhat.com/archives/libvir-list/2017-February/msg00452.html
Thanks -
John
Date: Thu, 2 Mar 2017 12:07:27 +0800
Subject: [PATCH] libvirt-remote:fix use-after-free when sending event
message
[Changelog]:If there is a process with a client which registers event
callbacks,
and it calls libvirt's API which uses the same virConnectPtr in that
callback function. When this process exit abnormally lead to client
disconnect, there is a possibility that the libvirtd's main thread is use
virServerClient to send event just after the virServerClient been freed
by job
thread.
Following is backtrace:
#0 0x00007fda223d66d8 in virClassIsDerivedFrom (klass=0xdeadbeef,
parent=0x7fda24c81b40) at util/virobject.c:169
#1 0x00007fda223d6a1e in virObjectIsClass
(anyobj=anyobj@entry=0x7fd9e575b400, klass=<optimized out>) at
util/virobject.c:365
#2 0x00007fda223d6a44 in virObjectLock (anyobj=0x7fd9e575b400) at
util/virobject.c:317
#3 0x00007fda22507f71 in virNetServerClientSendMessage
(client=client@entry=0x7fd9e575b400, msg=msg@entry=0x7fd9ec30de90)
at rpc/virnetserverclient.c:1422
#4 0x00007fda230d714d in remoteDispatchObjectEventSend
(client=0x7fd9e575b400, program=0x7fda24c844e0, procnr=348,
proc=0x7fda2310e5e0 <xdr_remote_domain_event_callback_tunable_msg>,
data=0x7ffc3857fdb0) at remote.c:3803
#5 0x00007fda230dd71b in remoteRelayDomainEventTunable (conn=<optimized
out>, dom=0x7fda27cd7660, params=0x7fda27f3aae0, nparams=1,
opaque=0x7fd9e6c99e00) at remote.c:1033
#6 0x00007fda224484cb in virDomainEventDispatchDefaultFunc
(conn=0x7fda27cd0120, event=0x7fda2736ea00,
cb=0x7fda230dd610 <remoteRelayDomainEventTunable>,
cbopaque=0x7fd9e6c99e00) at conf/domain_event.c:1910
#7 0x00007fda22446871 in virObjectEventStateDispatchCallbacks
(callbacks=<optimized out>, callbacks=<optimized out>, event=0x7fda2736ea00,
state=0x7fda24ca3960) at conf/object_event.c:722
#8 virObjectEventStateQueueDispatch (callbacks=0x7fda24c65800,
queue=0x7ffc3857fe90, state=0x7fda24ca3960) at conf/object_event.c:736
#9 virObjectEventStateFlush (state=0x7fda24ca3960) at
conf/object_event.c:814
#10 virObjectEventTimer (timer=<optimized out>, opaque=0x7fda24ca3960)
at conf/object_event.c:560
#11 0x00007fda223ae8b9 in virEventPollDispatchTimeouts () at
util/vireventpoll.c:458
#12 virEventPollRunOnce () at util/vireventpoll.c:654
#13 0x00007fda223ad1d2 in virEventRunDefaultImpl () at util/virevent.c:314
#14 0x00007fda225046cd in virNetDaemonRun (dmn=0x7fda24c775c0) at
rpc/virnetdaemon.c:818
#15 0x00007fda230d6351 in main (argc=<optimized out>, argv=<optimized
out>) at libvirtd.c:1623
Let's clean all event callback when client close.
Signed-off-by: Caoxinhua <caoxinhua(a)huawei.com>
---
daemon/remote.c | 76
+++++++++++++++++++++------------------------------------
1 file changed, 28 insertions(+), 48 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 23c9de4..fb7cd50 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -101,6 +101,7 @@ static void
make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNod
static void make_nonnull_secret(remote_nonnull_secret *secret_dst,
virSecretPtr secret_src);
static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst,
virNWFilterPtr nwfilter_src);
static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot
*snapshot_dst, virDomainSnapshotPtr snapshot_src);
+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate
*priv);
static int
remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
@@ -1483,24 +1484,15 @@ void
remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int r
&msg);
}
-/*
- * You must hold lock for at least the client
- * We don't free stuff here, merely disconnect the client's
- * network socket & resources.
- * We keep the libvirt connection open until any async
- * jobs have finished, then clean it up elsewhere
- */
-void remoteClientFreeFunc(void *data)
+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate
*priv)
{
- struct daemonClientPrivate *priv = data;
-
/* Deregister event delivery callback */
- if (priv->conn) {
- virIdentityPtr sysident = virIdentityGetSystem();
+ if (priv && priv->conn) {
size_t i;
-
+ virIdentityPtr sysident = virIdentityGetSystem();
virIdentitySetCurrent(sysident);
+ virMutexLock(&priv->lock);
for (i = 0; i < priv->ndomainEventCallbacks; i++) {
int callbackID = priv->domainEventCallbacks[i]->callbackID;
if (callbackID < 0) {
@@ -1514,6 +1506,7 @@ void remoteClientFreeFunc(void *data)
VIR_WARN("unexpected domain event deregister failure");
}
VIR_FREE(priv->domainEventCallbacks);
+ priv->ndomainEventCallbacks = 0;
for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
int callbackID = priv->networkEventCallbacks[i]->callbackID;
@@ -1529,36 +1522,7 @@ void remoteClientFreeFunc(void *data)
VIR_WARN("unexpected network event deregister failure");
}
VIR_FREE(priv->networkEventCallbacks);
-
- for (i = 0; i < priv->nstorageEventCallbacks; i++) {
- int callbackID = priv->storageEventCallbacks[i]->callbackID;
- if (callbackID < 0) {
- VIR_WARN("unexpected incomplete storage pool callback
%zu", i);
- continue;
- }
- VIR_DEBUG("Deregistering remote storage pool event relay %d",
- callbackID);
- priv->storageEventCallbacks[i]->callbackID = -1;
- if (virConnectStoragePoolEventDeregisterAny(priv->conn,
- callbackID) < 0)
- VIR_WARN("unexpected storage pool event deregister
failure");
- }
- VIR_FREE(priv->storageEventCallbacks);
-
- for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {
- int callbackID = priv->nodeDeviceEventCallbacks[i]->callbackID;
- if (callbackID < 0) {
- VIR_WARN("unexpected incomplete node device callback
%zu", i);
- continue;
- }
- VIR_DEBUG("Deregistering remote node device event relay %d",
- callbackID);
- priv->nodeDeviceEventCallbacks[i]->callbackID = -1;
- if (virConnectNodeDeviceEventDeregisterAny(priv->conn,
- callbackID) < 0)
- VIR_WARN("unexpected node device event deregister
failure");
- }
- VIR_FREE(priv->nodeDeviceEventCallbacks);
+ priv->nnetworkEventCallbacks = 0;
for (i = 0; i < priv->nqemuEventCallbacks; i++) {
int callbackID = priv->qemuEventCallbacks[i]->callbackID;
@@ -1574,31 +1538,47 @@ void remoteClientFreeFunc(void *data)
VIR_WARN("unexpected qemu monitor event deregister
failure");
}
VIR_FREE(priv->qemuEventCallbacks);
+ priv->nqemuEventCallbacks = 0;
if (priv->closeRegistered) {
if (virConnectUnregisterCloseCallback(priv->conn,
remoteRelayConnectionClosedEvent) < 0)
VIR_WARN("unexpected close callback event deregister
failure");
}
-
- virConnectClose(priv->conn);
-
+ virMutexUnlock(&priv->lock);
virIdentitySetCurrent(NULL);
virObjectUnref(sysident);
}
+}
+
+
+/*
+ * You must hold lock for at least the client
+ * We don't free stuff here, merely disconnect the client's
+ * network socket & resources.
+ * We keep the libvirt connection open until any async
+ * jobs have finished, then clean it up elsewhere
+ */
+void remoteClientFreeFunc(void *data)
+{
+ struct daemonClientPrivate *priv = data;
+ if (!priv || !priv->conn)
+ return;
+
+ remoteClientCleanEventCallbacks(priv);
+ virConnectClose(priv->conn);
VIR_FREE(priv);
}
-
static void remoteClientCloseFunc(virNetServerClientPtr client)
{
struct daemonClientPrivate *priv =
virNetServerClientGetPrivateData(client);
daemonRemoveAllClientStreams(priv->streams);
+ remoteClientCleanEventCallbacks(priv);
}
-
void *remoteClientInitHook(virNetServerClientPtr client,
void *opaque ATTRIBUTE_UNUSED)
{
--
1.8.3.1