[libvirt] Double deference error in libvirt_virConnectDomainEventRegisterAny

Daniel P. Berrange berrange at redhat.com
Fri May 26 13:30:20 UTC 2017


On Fri, May 26, 2017 at 04:39:17PM +0800, fangying wrote:
> Hi,
>     We'd like to report a double dereference error of 'pyobj_cbData' in libvirt_virConnectDomainEventRegisterAny.
>     The bug can be triggered in the situation where 'domainEventRegisterAny' (the python interface of libvirt_virConnectDomainEventRegisterAny)
> is invoked and network connection is coincidently lost (likely libvirtd restarted) at same time.
> 
>     We get the following stacktrace when the bug is hit.
>     Program terminated with signal 6, Aborted.
>     #0  0x00007fc45cba15d7 in raise () from /usr/lib64/libc.so.6
>     #1  0x00007fc45cba2cc8 in abort () from /usr/lib64/libc.so.6
>     #2  0x00007fc45cbe12f7 in __libc_message () from /usr/lib64/libc.so.6
>     #3  0x00007fc45cbe86d3 in _int_free () from /usr/lib64/libc.so.6
>     #4  0x00007fc45d8d292c in PyDict_Fini () from /usr/lib64/libpython2.7.so.1.0
>     #5  0x00007fc45d94f46a in Py_Finalize () from /usr/lib64/libpython2.7.so.1.0
>     #6  0x00007fc45d960735 in Py_Main () from /usr/lib64/libpython2.7.so.1.0
>     #7  0x00007fc45cb8daf5 in __libc_start_main () from /usr/lib64/libc.so.6
>     #8  0x0000000000400721 in _start ()
> 
>     The double dereference of 'pyobj_cbData' is triggered in the following way:
>     (1) libvirt_virConnectDomainEventRegisterAny is invoked.
>     (2) the event is successfully added to the event callback list (virDomainEventStateRegisterClient in
>         remoteConnectDomainEventRegisterAny returns 1 which means ok).
>     (3) when function remoteConnectDomainEventRegisterAny is hit, network connection disconnected coincidently
>         (or libvirtd is restarted) in the context of function 'call' then the connection is lost and the
>         function 'call' failed, the branch virObjectEventStateDeregisterID is therefore taken.
>     (4) 'pyobj_conn' is dereferenced the 1st time in libvirt_virConnectDomainEventFreeFunc.
>     (5) 'pyobj_cbData' (refered to pyobj_conn) is dereferenced the 2nd time in libvirt_virConnectDomainEventRegisterAny.
>     (6) the double free error is triggered.

IOW,  even when virConnectDomainEventRegisterAny returns -1 there is still
a scenario in which it will trigger the free callback.

This is a bug in the libvirt C impl of virConnectDomainEventRegisterAny,
not the python bindings. If this API returns -1, it *must* guarantee
that the callbacks are never called.


>     static void
>     libvirt_virConnectDomainEventFreeFunc(void *opaque)
>     {
>         PyObject *pyobj_conn = (PyObject*)opaque;
>         LIBVIRT_ENSURE_THREAD_STATE;
>         Py_DECREF(pyobj_conn);          /* 1st dereference comes here */
>         LIBVIRT_RELEASE_THREAD_STATE;
>     }
> 
>     static PyObject *
>     libvirt_virConnectDomainEventRegisterAny(PyObject *self ATTRIBUTE_UNUSED,
>                                              PyObject *args) {
>         ...
>         Py_INCREF(pyobj_cbData);
> 
>         LIBVIRT_BEGIN_ALLOW_THREADS;
>         ret = virConnectDomainEventRegisterAny(conn, dom, eventID,
>                                                cb, pyobj_cbData,
>                                                libvirt_virConnectDomainEventFreeFunc);
> 
>         if (ret < 0) {
>             Py_DECREF(pyobj_cbData);   /* 2nd dereference comes here */
>         }
>     }
> 
>     Currently we cannot find a good solution to fix this problem,
> could anyone guide us to fix it ?

You need to look at the  libvirt code to fix it, rather than python
code. The python code expectations are correct in assuming that
when ret == -1, it must free the data.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the libvir-list mailing list