diff options
author | Jiri Denemark <jdenemar@redhat.com> | 2014-01-09 22:26:40 +0100 |
---|---|---|
committer | Eric Blake <eblake@redhat.com> | 2014-01-15 11:01:59 -0700 |
commit | 21fb70f0484fb02c66dfad27e638ca9fa34fd362 (patch) | |
tree | c20e5b58242af129137fa41204b2b14c31e97ee9 | |
parent | c51986ba820dde30e48b4f1694862c3cf4d8b7ec (diff) | |
download | libvirt-21fb70f0484fb02c66dfad27e638ca9fa34fd362.tar.gz |
Don't crash if a connection closes early
https://bugzilla.redhat.com/show_bug.cgi?id=1047577
When a client closes its connection to libvirtd early during
virConnectOpen, more specifically just after making
REMOTE_PROC_CONNECT_SUPPORTS_FEATURE call to check if
VIR_DRV_FEATURE_PROGRAM_KEEPALIVE is supported without even waiting for
the result, libvirtd may crash due to a race in keep-alive
initialization. Once receiving the REMOTE_PROC_CONNECT_SUPPORTS_FEATURE
call, the daemon's event loop delegates it to a worker thread. In case
the event loop detects EOF on the connection and calls
virNetServerClientClose before the worker thread starts to handle
REMOTE_PROC_CONNECT_SUPPORTS_FEATURE call, client->keepalive will be
disposed by the time virNetServerClientStartKeepAlive gets called from
remoteDispatchConnectSupportsFeature. Because the flow is common for
both authenticated and read-only connections, even unprivileged clients
may cause the daemon to crash.
To avoid the crash, virNetServerClientStartKeepAlive needs to check if
the connection is still open before starting keep-alive protocol.
Every libvirt release since 0.9.8 is affected by this bug.
(cherry picked from commit 173c2914734eb5c32df6d35a82bf503e12261bcf)
-rw-r--r-- | src/rpc/virnetserverclient.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 8fec7e6758..147511ee90 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -1372,9 +1372,22 @@ cleanup: int virNetServerClientStartKeepAlive(virNetServerClientPtr client) { - int ret; + int ret = -1; + virObjectLock(client); + + /* The connection might have been closed before we got here and thus the + * keepalive object could have been removed too. + */ + if (!client->sock) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("connection not open")); + goto cleanup; + } + ret = virKeepAliveStart(client->keepalive, 0, 0); + +cleanup: virObjectUnlock(client); return ret; } |