[libvirt] [PATCH] EventRegister: Fix double deference error in libvirt_virConnectDomainEventRegisterAny

John Ferlan jferlan at redhat.com
Wed Jun 14 11:15:36 UTC 2017



On 06/01/2017 08:25 AM, fangying wrote:
> As descriped at https://www.spinics.net/linux/fedora/libvir/msg148562.html,
> even when virConnectDomainEventRegisterAny returns -1 there is still a
> scenario in which it will trigger the free callback. We fix the problem in the
> following way:
> (1) implement a function virObjectEventStateSetFreeCB to add freecallback.
> (2) call virObjectEventStateSetFreeCB only if the event is successfully added.
> 

Rather than putting a link to some page that may not exist some time in
the future, please describe the issue in the patch. Like you did in your
first version:

https://www.redhat.com/archives/libvir-list/2017-May/msg01089.html

> Signed-off-by: fangying <fangying1 at huawei.com>

If you look at other commits in libvirt you'll typically see a "first"
and "last" name... IOW: We prefer a more legal name as opposed to your
current login/email short name.

> ---

If you need to ever place a reference to some web page, when using git
send-email and you can "edit" your patch before sending, you can add
"reviewer comments" right after the "---". That helps see the history of
the patch.  If you have a multiple patch series, that type of
information can go in the cover letter.

>  src/conf/object_event.c    | 34 ++++++++++++++++++++++++++++++++++
>  src/conf/object_event.h    |  7 +++++++
>  src/libvirt_private.syms   |  2 +-
>  src/remote/remote_driver.c |  4 ++--
>  4 files changed, 44 insertions(+), 3 deletions(-)
> 

So this patch doesn't compile using top of tree, please see and follow
the guidelines at:

http://libvirt.org/hacking.html


> diff --git a/src/conf/object_event.c b/src/conf/object_event.c
> index e5f942f..a770978 100644
> --- a/src/conf/object_event.c
> +++ b/src/conf/object_event.c
> @@ -923,6 +923,40 @@ virObjectEventStateRegisterID(virConnectPtr conn,
>  
>  
>  /**
> + * virObjectEventStateSetFreeCB:
> + * @conn: connection to associate with callback
> + * @state: object event state
> + * @callbackID: ID of the function to remove from event
> + * @freecb: freecb to be added
> + *
> + * Add the callbalck function @freecb for @callbackID with connection @conn,
> + * from @state, for events.
> + */
> +void
> +virObjectEventStateSetFreeCB(virConnectPtr conn,
> +                             virObjectEventStatePtr state,
> +                             int callbackID,
> +                             virFreeCallback freecb)
> +{
> +    size_t i;
> +    virObjectEventCallbackListPtr cbList;
> +
> +    virObjectEventStateLock(state);

In particular, this *Lock function no longer exists. It was removed in
libvirt 2.4 by commit id '1827f2ac5d', you should have used
'virObjectLock(state);' instead.

> +    cbList = state->callbacks;
> +    for (i = 0; i < cbList->count; i++) {
> +        virObjectEventCallbackPtr cb = cbList->callbacks[i];
> +
> +        if (cb->callbackID == callbackID && cb->conn == conn) {
> +            cb->freecb = freecb;
> +            break;
> +        }
> +    }
> +
> +    virObjectEventStateUnlock(state);

Similarly virObjectUnlock(state);

> +}
> +
> +
> +/**
>   * virObjectEventStateDeregisterID:
>   * @conn: connection to associate with callback
>   * @state: object event state
> diff --git a/src/conf/object_event.h b/src/conf/object_event.h
> index 7a9995e..a7d29a0 100644
> --- a/src/conf/object_event.h
> +++ b/src/conf/object_event.h
> @@ -90,4 +90,11 @@ virObjectEventStateSetRemote(virConnectPtr conn,
>                               int remoteID)
>      ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
>  
> +void
> +virObjectEventStateSetFreeCB(virConnectPtr conn,
> +                             virObjectEventStatePtr state,
> +                             int callbackID,
> +                             virFreeCallback freecb)
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
> +
>  #endif
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 429b095..e9d9cb6 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -791,7 +791,7 @@ virObjectEventStateDeregisterID;
>  virObjectEventStateEventID;
>  virObjectEventStateNew;
>  virObjectEventStateQueue;
> -

Spurious deletion. Follow the model in the module.  Each .h file has a
sorted list of function names followed by 2 blank lines followed by the
next .h file.

> +virObjectEventStateSetFreeCB;
>  
>  # conf/secret_conf.h
>  virSecretDefFormat;
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index d27e96f..71177bd 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -5947,7 +5947,7 @@ remoteConnectDomainEventRegisterAny(virConnectPtr conn,
>  
>      if ((count = virDomainEventStateRegisterClient(conn, priv->eventState,
>                                                     dom, eventID, callback,
> -                                                   opaque, freecb, false,
> +                                                   opaque, NULL, false,
>                                                     &callbackID,
>                                                     priv->serverEventFilter)) < 0)
>          goto done;
> @@ -5993,7 +5993,7 @@ remoteConnectDomainEventRegisterAny(virConnectPtr conn,
>      }
>  
>      rv = callbackID;
> -
> +    virObjectEventStateSetFreeCB(conn, priv->eventState, callbackID, freecb);

After reading Daniel's response to your initial posting and doing just a
small amount of investigating - it would seem that perhaps this may fix
one instance, but there are multiple callers pass a @freecb to a
vir*EventStateRegisterClient API, make a remote "call" that could fail,
and then call virObjectEventStateDeregisterID which would conceivably
have the same problem.

So instead of adjusting each of those to have this type set the freecb,
I think altering virObjectEventStateDeregisterID to take a boolean that
would inhibit calling the cb->freecb function may be a better approach.
For callers to virObjectEventStateDeregisterID from some
remoteConnect*EventDeregister* function, the boolean would be false.

IOW: Change virObjectEventStateDeregisterID to add a 4th parameter "bool
inhibitFreeCb". It's "true" on *error* paths from the remote calls
because returning -1 to the caller indicates that the caller needs to
free their opaque data since the freecb wouldn't be run, while calls
from various removeConnect*EventDeregister* APIs the parameter would be
"false" and the logic prior to calling the cb->freecb function is
altered to be "if (!inhibitFreeCb && cb->freecb)", with perhaps a
comment before it indicating that inhibitFreeCb would be used on error
paths to ensure/avoid the double free problem.

HTH,

John



>   done:
>      remoteDriverUnlock(priv);
>      return rv;
> 




More information about the libvir-list mailing list