[libvirt] [PATCH v2 2/2] remote: Fix possible use-after-free when sending event message
Michal Privoznik
mprivozn at redhat.com
Mon Apr 24 04:51:54 UTC 2017
On 03/27/2017 06:47 PM, John Ferlan wrote:
> Based upon an idea and some research by Wang King <king.wang at huawei.com>
> and xinhua.Cao <caoxinhua at huawei.com>.
>
> Since we're assigning the 'client' to our callback event lookaside list,
> it's imperative that we grab a reference to the object; otherwise, when
> the object is unref'd during virNetServerProcessClients when it's determined
> that the virNetServerClientIsClosed and the memory is free'd before perhaps
> the object event state callbacks are run. When a virObjectLock() is run,
> before sending the message the following trace occurs;
>
> #0 0x00007fda223d66d8 in virClassIsDerivedFrom
> (klass=0xdeadbeef, parent=0x7fda24c81b40)
> at util/virobject.c:169
> #1 0x00007fda223d6a1e in virObjectIsClass
> (anyobj=anyobj at 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 at entry=0x7fd9e575b400, msg=msg at 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
>
> Signed-off-by: John Ferlan <jferlan at redhat.com>
> ---
> daemon/remote.c | 38 +++++++++++++++++++++-----------------
> 1 file changed, 21 insertions(+), 17 deletions(-)
>
> diff --git a/daemon/remote.c b/daemon/remote.c
> index 5cdc53e..25a29cf 100644
> --- a/daemon/remote.c
> +++ b/daemon/remote.c
> @@ -124,7 +124,11 @@ remoteDispatchObjectEventSend(virNetServerClientPtr client,
> static void
> remoteEventCallbackFree(void *opaque)
> {
> - VIR_FREE(opaque);
> + daemonClientEventCallbackPtr callback = opaque;
> + if (!callback)
> + return;
> + virObjectUnref(callback->client);
> + VIR_FREE(callback);
> }
>
>
> @@ -3896,7 +3900,7 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED
> */
> if (VIR_ALLOC(callback) < 0)
> goto cleanup;
> - callback->client = client;
> + callback->client = virObjectRef(client);
> callback->eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
> callback->callbackID = -1;
> callback->legacy = true;
> @@ -3923,7 +3927,7 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED
> rv = 0;
>
> cleanup:
> - VIR_FREE(callback);
> + remoteEventCallbackFree(callback);
> if (rv < 0)
> virNetMessageSaveError(rerr);
> virMutexUnlock(&priv->lock);
I don't really see how this could work in the first place. I mean,
@callback is allocated in the chunk above. Cool. Then, in between these
two chunks it's passed (under code name @ref) to
virConnectDomainEventRegisterAny() ...
Aaand I get it now. Just realized that VIR_APPEND_ELEMENT() sets
@callback to NULL. So we are safe here. D'oh.
ACK
Michal
More information about the libvir-list
mailing list