[libvirt] [PATCH] rpc: avoid libvirtd crash on unexpected client close

Wen Congyang wency at cn.fujitsu.com
Tue Aug 2 01:19:20 UTC 2011


At 08/02/2011 03:53 AM, Eric Blake Write:
> Steps to reproduce this problem (vm1 is not running):
> for i in `seq 50`; do virsh managedsave vm1& done; killall virsh
> 
> Pre-patch, virNetServerClientClose could end up setting client->sock
> to NULL prior to other cleanup functions trying to use client->sock.
> This fixes things by checking for NULL in more places, and by deferring
> the cleanup until after all queued messages have been served.

With this patch, libvirtd does not crash.

> 
> * src/rpc/virnetserverclient.c (virNetServerClientRegisterEvent)
> (virNetServerClientGetFD, virNetServerClientIsSecure)
> (virNetServerClientLocalAddrString)
> (virNetServerClientRemoteAddrString): Check for closed socket.
> (virNetServerClientClose): Rearrange close sequence.
> Analysis from Wen Congyang.
> ---
> 
> This fixes the problem using the reproduction formula (that is,
> pre-patch I reproduced the failure; valgrind showed it at:
> ==29390== Thread 4:
> ==29390== Invalid read of size 4
> ==29390==    at 0x3D16608FA0: pthread_mutex_lock (pthread_mutex_lock.c:50)
> ==29390==    by 0x4E9FED2: virMutexLock (threads-pthread.c:85)
> ==29390==    by 0x45DA5E: virNetSocketGetLocalIdentity (virnetsocket.c:741)
> ==29390==    by 0x45554A: virNetServerClientGetLocalIdentity (virnetserverclient.c:401)
> ==29390==    by 0x4420E3: remoteDispatchAuthList (remote.c:1682)
> ==29390==    by 0x4224E4: remoteDispatchAuthListHelper (remote_dispatch.h:19)
> ==29390==    by 0x453EFD: virNetServerProgramDispatchCall (virnetserverprogram.c:375)
> ==29390==    by 0x4539FF: virNetServerProgramDispatch (virnetserverprogram.c:252)
> ==29390==    by 0x456B20: virNetServerHandleJob (virnetserver.c:155)
> ==29390==    by 0x4EA06A3: virThreadPoolWorker (threadpool.c:98)
> ==29390==    by 0x4EA01D6: virThreadHelper (threads-pthread.c:157)
> ==29390==    by 0x3D16606CCA: start_thread (pthread_create.c:301)
> ==29390==  Address 0x10 is not stack'd, malloc'd or (recently) free'd
> 
> 
> post-patch, libvirtd stays alive and valgrind no longer reports
> an invalid read).  But I'd really like danpb's opinion, if there
> is time to get that before 0.9.4.

I agree with this patch. But give the chance to danpb to give the final
ack before 0.9.4.

> 
> /me note to self 'git send-email --cc=...' uses cc as well as
> honoring .git/config --to to the list; but the list manager
> sometimes strips cc: lines.  Converserly, 'git send-email --to=...'
> overrides .git/config settings, leaving out the list.  I can't
> win; sorry for the private mails on my previous send attempt.
> 
>  src/rpc/virnetserverclient.c |   29 +++++++++++++++++++----------
>  1 files changed, 19 insertions(+), 10 deletions(-)
> 
> diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
> index 3c0dba8..2f6c040 100644
> --- a/src/rpc/virnetserverclient.c
> +++ b/src/rpc/virnetserverclient.c
> @@ -177,7 +177,8 @@ static int virNetServerClientRegisterEvent(virNetServerClientPtr client)
> 
>      client->refs++;
>      VIR_DEBUG("Registering client event callback %d", mode);
> -    if (virNetSocketAddIOCallback(client->sock,
> +    if (!client->sock ||
> +        virNetSocketAddIOCallback(client->sock,
>                                    mode,
>                                    virNetServerClientDispatchEvent,
>                                    client,
> @@ -386,9 +387,10 @@ int virNetServerClientGetTLSKeySize(virNetServerClientPtr client)
> 
>  int virNetServerClientGetFD(virNetServerClientPtr client)
>  {
> -    int fd = 0;
> +    int fd = -1;
>      virNetServerClientLock(client);
> -    fd = virNetSocketGetFD(client->sock);
> +    if (client->sock)
> +        fd = virNetSocketGetFD(client->sock);
>      virNetServerClientUnlock(client);
>      return fd;
>  }
> @@ -396,9 +398,10 @@ int virNetServerClientGetFD(virNetServerClientPtr client)
>  int virNetServerClientGetLocalIdentity(virNetServerClientPtr client,
>                                         uid_t *uid, pid_t *pid)
>  {
> -    int ret;
> +    int ret = -1;
>      virNetServerClientLock(client);
> -    ret = virNetSocketGetLocalIdentity(client->sock, uid, pid);
> +    if (client->sock)
> +        ret = virNetSocketGetLocalIdentity(client->sock, uid, pid);
>      virNetServerClientUnlock(client);
>      return ret;
>  }
> @@ -413,7 +416,7 @@ bool virNetServerClientIsSecure(virNetServerClientPtr client)
>      if (client->sasl)
>          secure = true;
>  #endif
> -    if (virNetSocketIsLocal(client->sock))
> +    if (client->sock && virNetSocketIsLocal(client->sock))
>          secure = true;
>      virNetServerClientUnlock(client);
>      return secure;
> @@ -502,12 +505,16 @@ void virNetServerClientSetDispatcher(virNetServerClientPtr client,
> 
>  const char *virNetServerClientLocalAddrString(virNetServerClientPtr client)
>  {
> +    if (!client->sock)
> +        return NULL;
>      return virNetSocketLocalAddrString(client->sock);
>  }
> 
> 
>  const char *virNetServerClientRemoteAddrString(virNetServerClientPtr client)
>  {
> +    if (!client->sock)
> +        return NULL;
>      return virNetSocketRemoteAddrString(client->sock);
>  }
> 
> @@ -570,10 +577,7 @@ void virNetServerClientClose(virNetServerClientPtr client)
>          virNetTLSSessionFree(client->tls);
>          client->tls = NULL;
>      }
> -    if (client->sock) {
> -        virNetSocketFree(client->sock);
> -        client->sock = NULL;
> -    }
> +    client->wantClose = true;
> 
>      while (client->rx) {
>          virNetMessagePtr msg
> @@ -586,6 +590,11 @@ void virNetServerClientClose(virNetServerClientPtr client)
>          virNetMessageFree(msg);
>      }
> 
> +    if (client->sock) {
> +        virNetSocketFree(client->sock);
> +        client->sock = NULL;
> +    }
> +
>      virNetServerClientUnlock(client);
>  }
> 




More information about the libvir-list mailing list