[libvirt] [PATCH] remote: Prevent race when closing a connection
Eric Blake
eblake at redhat.com
Thu Mar 14 23:28:05 UTC 2013
On 03/14/2013 06:26 AM, Viktor Mihajlovski wrote:
> A race condition can occur when virConnectClose is called parallel
> to the execution of the connection close callback in remoteClientCloseFunc.
>
> The race happens if the connection object is destroyed (including
> the mutex) while remoteClientCloseFunc is waiting for the connection
> mutex. After the destruction of the (non error checking) mutex
> remoteClientCloseFunc starts to process the callbacks. However the
> operations can occur against a freed (or even worse, reallocated)
> object. Another issue is that the closeFreeCallback is invoked
> even if it's NULL (this is the case for virsh).
>
> The solution is to clean out the callback pointers in virConnectDispose
> before destroying the mutex. This way remoteClientCloseFunc will
> return immediately after passing virMutexLock, thus avoiding potential
> data corruption. There's still the slight chance that the concluding
> virMutexUnlock could do harm on the freed connection object.
See my question below...
> This could be fixed using an error checking mutex which however has a
> much broader scope and impact.
I'd like Dan to weigh in on this one, because he probably has a better
insight into the proper way to break the race. But here are some
smaller comments:
>
> Signed-off-by: Viktor Mihajlovski <mihajlov at linux.vnet.ibm.com>
> ---
> src/datatypes.c | 8 +++++++-
> src/remote/remote_driver.c | 3 ++-
> 2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/src/datatypes.c b/src/datatypes.c
> index b04e100..2358bdf 100644
> --- a/src/datatypes.c
> +++ b/src/datatypes.c
> @@ -146,8 +146,14 @@ virConnectDispose(void *obj)
>
> virMutexLock(&conn->lock);
>
> - if (conn->closeFreeCallback)
> + if (conn->closeCallback)
> + conn->closeCallback = NULL;
The if is pointless. Just blindly set conn->closeCallback to NULL.
> +
> + if (conn->closeFreeCallback) {
> conn->closeFreeCallback(conn->closeOpaque);
> + conn->closeFreeCallback = NULL;
> + conn->closeOpaque = NULL;
Clearing conn->closeOpaque is pointless; it is only ever used depending
on conn->closeFreeCallback, and leaving it non-NULL doesn't hurt.
> + }
>
> virResetError(&conn->err);
>
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index 3721af9..885120e 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -358,7 +358,8 @@ static void remoteClientCloseFunc(virNetClientPtr client ATTRIBUTE_UNUSED,
> closeCallback(conn, reason, closeOpaque);
> virMutexLock(&conn->lock);
> conn->closeDispatch = false;
> - if (conn->closeUnregisterCount != closeUnregisterCount)
> + if (conn->closeUnregisterCount != closeUnregisterCount &&
> + closeFreeCallback)
> closeFreeCallback(closeOpaque);
> }
> virMutexUnlock(&conn->lock);
...Wouldn't it be better to stash a copy of the callback pointer while
the mutex is held, but avoid calling the callback until after the mutex
is unlocked? Something like:
<TYPE> cb = NULL;
void* opaque;
virMutexLock(&conn->lock);
conn->closeDispatch = false;
if (conn->closeUnregisterCount != closeUnregisterCount) {
cb = closeFreeCallback;
opaque = closeOpaque;
}
virMutexUnlock(&conn->lock);
if (cb)
cb(opaque);
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 621 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20130314/da41d1f8/attachment-0001.sig>
More information about the libvir-list
mailing list