From: l00425170 <liujunji...@huawei.com>

When libvirt client registers callback function,
remoteDispatchConnectDomainEventCallbackRegisterAny is called, then 
virInsertElementsN
will be called to add new callback for struct daemonClientPrivate *priv.

But at the same time, if the corresponding socket is closed (one way is to kill 
the
client process), the close callback remoteClientCloseFunc is called, then
remoteFreePrivCallbacks(priv) is called to free priv. So there exists data race 
to
cause libvirtd coredump.

More details, in add callback, when memset for ptrptr (that is priv) is done in
virExpandN at the process of virInsertElementsN. At this time point, priv can be
free to be 0x0 when close client.

So when the procedure goes to memcpy in virInsertElementsN, the libvirtd will 
coredump.

And the stack are as follows:
Thread 1 (Thread 0x7feadf7fe700 (LWP 8978)):
    #0  0x00007feb7b77f314 in __memcpy_ssse3_back() from /usr/lib64/libc.so.6
    #1  0x00007feb7e769a82 in memcpy
        (__len=8, __src=0x7feadf7fdb58, __dest=<optimized out>)
        at /usr/include/bits/string3.h:51
    #2  virInsertElementsN
        (ptrptr=ptrptr@entry=0x558e9c36fae8, size=size@entry=8,
        at=<optimized out>, at@entry=18446744073709551615,
        countptr=countptr@entry=0x558e9c36faf0, add=add@entry=1,
        newelems=newelems@entry=0x7feadf7fdb58, 
clearOriginal=clearOriginal@entry=true,
        inPlace=inPlace@entry=false, report=report@entry=true,
        domcode=domcode@entry=7, filename=filename@entry=0x558e9af16107 
"remote.c",
        funcname=funcname@entry=0x558e9af24600 <__FUNCTION__.48097>
        "remoteDispatchConnectDomainEventCallbackRegisterAny", 
linenr=linenr@entry=4424)
        at util/viralloc.c:454
    #3  0x0000558e9aed7001 in 
remoteDispatchConnectDomainEventCallbackRegisterAny
        (server=<optimized out>, msg=<optimized out>, ret=0x7feab805e6f0,
        args=0x7feab806aa40, rerr=0x7feadf7fdc90, client=<optimized out>)
        at remote.c:4422
    #4  remoteDispatchConnectDomainEventCallbackRegisterAnyHelper
        (server=<optimized out>, client=<optimized out>, msg=<optimized out>,
        rerr=0x7feadf7fdc90, args=0x7feab806aa40, ret=0x7feab805e6f0)
        at remote_dispatch.h:424
    #5  0x0000558e9af0ca48 in virNetServerProgramDispatchCall
        (msg=0x558e9c3925c0, client=0x558e9c36f970, server=0x558e9c351570,
        prog=0x558e9c367d50)
        at rpc/virnetserverprogram.c:474
    #6  virNetServerProgramDispatch
        (prog=0x558e9c367d50, server=server@entry=0x558e9c351570, 
client=0x558e9c36f970,
        msg=0x558e9c3925c0)
        at rpc/virnetserverprogram.c:311
    #7  0x0000558e9af085ed in virNetServerProcessMsg
        (msg=<optimized out>, prog=<optimized out>, client=<optimized out>,
        srv=0x558e9c351570)
        at rpc/virnetserver.c:148
    #8  virNetServerHandleJob
        (jobOpaque=<optimized out>, opaque=0x558e9c351570)
        at rpc/virnetserver.c:169
    #9  0x00007feb7e7f1861 in virThreadPoolWorker
        (opaque=opaque@entry=0x558e9c36b5f0)
        at util/virthreadpool.c:167
    #10 0x00007feb7e7f0b78 in virThreadHelper
        (data=<optimized out>)
        at util/virthread.c:219
    #11 0x00007feb7b9fcdc5 in start_thread () from /usr/lib64/libpthread.so.0
    #12 0x00007feb7b72b75d in clone () from /usr/lib64/libc.so.6

Signed-off-by: l00425170 <liujunji...@huawei.com>
---
 src/remote/remote_daemon.h          |  2 ++
 src/remote/remote_daemon_dispatch.c | 46 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/remote/remote_daemon.h b/src/remote/remote_daemon.h
index 4467f71..8accafc 100644
--- a/src/remote/remote_daemon.h
+++ b/src/remote/remote_daemon.h
@@ -76,6 +76,8 @@ struct daemonClientPrivate {
     virConnectPtr conn;
 
     daemonClientStreamPtr streams;
+
+    bool clientClosed;
 };
 
 
diff --git a/src/remote/remote_daemon_dispatch.c 
b/src/remote/remote_daemon_dispatch.c
index fdb0a36..59e69e6 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -1752,8 +1752,12 @@ static void remoteClientCloseFunc(virNetServerClientPtr 
client)
     daemonRemoveAllClientStreams(priv->streams);
 
     /* Deregister event delivery callback */
-    if (priv->conn)
+    if (priv->conn) {
+        virMutexLock(&priv->lock);
         remoteClientFreePrivateCallbacks(priv);
+        priv->clientClosed = true;
+        virMutexUnlock(&priv->lock);
+    }
 }
 
 
@@ -3889,6 +3893,11 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr 
server ATTRIBUTE_UNUSED
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     /* If we call register first, we could append a complete callback
      * to our array, but on OOM append failure, we'd have to then hope
      * deregister works to undo our register.  So instead we append an
@@ -4116,6 +4125,11 @@ 
remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNU
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
      * new domain events added after this point should only use the
      * modern callback style of RPC.  */
@@ -4192,6 +4206,11 @@ 
remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRI
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->dom &&
         !(dom = get_nonnull_domain(priv->conn, *args->dom)))
         goto cleanup;
@@ -5702,6 +5721,11 @@ 
remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UN
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->net &&
         !(net = get_nonnull_network(priv->conn, *args->net)))
         goto cleanup;
@@ -5824,6 +5848,11 @@ 
remoteDispatchConnectStoragePoolEventRegisterAny(virNetServerPtr server ATTRIBUT
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->pool &&
         !(pool = get_nonnull_storage_pool(priv->conn, *args->pool)))
         goto cleanup;
@@ -5945,6 +5974,11 @@ 
remoteDispatchConnectNodeDeviceEventRegisterAny(virNetServerPtr server ATTRIBUTE
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->dev &&
         !(dev = get_nonnull_node_device(priv->conn, *args->dev)))
         goto cleanup;
@@ -6066,6 +6100,11 @@ 
remoteDispatchConnectSecretEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNU
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->secret &&
         !(secret = get_nonnull_secret(priv->conn, *args->secret)))
         goto cleanup;
@@ -6188,6 +6227,11 @@ 
qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_U
 
     virMutexLock(&priv->lock);
 
+    if (priv->clientClosed) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection want 
close"));
+        goto cleanup;
+    }
+
     if (args->dom &&
         !(dom = get_nonnull_domain(priv->conn, *args->dom)))
         goto cleanup;
-- 
2.13.3.windows.1


--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to