[libvirt] [PATCH] util: Fix domain object leaks on closecallbacks

Michal Privoznik mprivozn at redhat.com
Tue Jan 31 15:52:16 UTC 2017


On 01/25/2017 05:37 PM, John Ferlan wrote:
> Originally/discovered proposed by "Wang King <king.wang at huawei.com>"
> 
> When the virCloseCallbacksSet is first called, it increments the refcnt
> on the domain object to ensure it doesn't get deleted before the callback
> is called. The refcnt would be decremented in virCloseCallbacksUnset once
> the entry is removed from the closeCallbacks has table.
> 
> When (mostly) normal shutdown occurs, the qemuProcessStop will end up
> calling qemuProcessAutoDestroyRemove and will remove the callback from
> the list and hash table normally and decrement the refcnt.
> 
> However, when qemuConnectClose calls virCloseCallbacksRun, it will scan
> the (locked) closeCallbacks list for matching domain and callback function.
> If an entry is found, it will be removed from the closeCallbacks list and
> placed into a lookaside list to be processed when the closeCallbacks lock
> is dropped. The callback function (e.g. qemuProcessAutoDestroy) is called
> and will run qemuProcessStop. That code will fail to find the callback
> in the list when qemuProcessAutoDestroyRemove is called and thus not decrement
> the domain refcnt. Instead since the entry isn't found the code will just
> return (mostly) harmlessly.
> 
> This patch will resolve the issue by taking another ref during the
> search UUID process during virCloseCallackRun, decrementing the refcnt
> taken by virCloseCallbacksSet, calling the callback routine and returning
> overwriting the vm (since it could return NULL). Finally, it will call the
> virDomainObjEndAPI to lower the refcnt and remove the lock taken during
> the search UUID processing. This may cause the vm to be destroyed.
> 
> Signed-off-by: John Ferlan <jferlan at redhat.com>
> ---
>  src/util/virclosecallbacks.c | 17 ++++++++++++-----
>  1 file changed, 12 insertions(+), 5 deletions(-)
> 
> diff --git a/src/util/virclosecallbacks.c b/src/util/virclosecallbacks.c
> index 2f430cf..4db50e8 100644
> --- a/src/util/virclosecallbacks.c
> +++ b/src/util/virclosecallbacks.c
> @@ -346,17 +346,24 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
>      for (i = 0; i < list->nentries; i++) {
>          virDomainObjPtr vm;
>  
> -        if (!(vm = virDomainObjListFindByUUID(domains,
> -                                              list->entries[i].uuid))) {
> +        /* Grab a ref and lock to the vm */
> +        if (!(vm = virDomainObjListFindByUUIDRef(domains,
> +                                                 list->entries[i].uuid))) {
>              char uuidstr[VIR_UUID_STRING_BUFLEN];
>              virUUIDFormat(list->entries[i].uuid, uuidstr);
>              VIR_DEBUG("No domain object with UUID %s", uuidstr);
>              continue;
>          }
>  
> -        vm = list->entries[i].callback(vm, conn, opaque);
> -        if (vm)
> -            virObjectUnlock(vm);
> +        /* Remove the ref taken out during virCloseCallbacksSet since
> +         * we're about to call the callback function and we have another
> +         * ref anyway (so it cannot be deleted).
> +         *
> +         * Call the callback function, ignoring the return since it might be
> +         * NULL. Once we're done with the object, then end the API usage. */
> +        virObjectUnref(vm);
> +        ignore_value(list->entries[i].callback(vm, conn, opaque));
> +        virDomainObjEndAPI(&vm);
>      }
>      VIR_FREE(list->entries);
>      VIR_FREE(list);
> 

Looks very hacky, but I am unable to come up with a better fix.

ACK

Michal




More information about the libvir-list mailing list