Jacek Caban : rpcrt4: Fix a race when server grabs a connection from the list of active connections.

Alexandre Julliard julliard at winehq.org
Thu Jun 8 15:54:57 CDT 2017


Module: wine
Branch: master
Commit: e889b027efa99fdc783fcf48c59adfe119e0d65c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e889b027efa99fdc783fcf48c59adfe119e0d65c

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Thu Jun  8 14:16:50 2017 +0200

rpcrt4: Fix a race when server grabs a connection from the list of active connections.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/rpcrt4/rpc_transport.c | 58 ++++++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 0ae7125..909fec1 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -3373,40 +3373,50 @@ void rpcrt4_conn_release_and_wait(RpcConnection *connection)
     }
 }
 
-RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn )
+RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection)
 {
-    InterlockedIncrement( &conn->ref );
-    return conn;
+    LONG ref = InterlockedIncrement(&connection->ref);
+    TRACE("%p ref=%u\n", connection, ref);
+    return connection;
 }
 
-RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
+RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection *connection)
 {
-  if (InterlockedDecrement( &Connection->ref ) > 0) return RPC_S_OK;
+    LONG ref = InterlockedDecrement(&connection->ref);
 
-  TRACE("destroying connection %p\n", Connection);
+    if (!ref && connection->protseq)
+    {
+        /* protseq stores a list of active connections, but does not own references to them.
+         * It may need to grab a connection from the list, which could lead to a race if
+         * connection is being released, but not yet removed from the list. We handle that
+         * by synchronizing on CS here. */
+        EnterCriticalSection(&connection->protseq->cs);
+        ref = connection->ref;
+        if (!ref)
+            list_remove(&connection->protseq_entry);
+        LeaveCriticalSection(&connection->protseq->cs);
+    }
 
-  RPCRT4_CloseConnection(Connection);
-  RPCRT4_strfree(Connection->Endpoint);
-  RPCRT4_strfree(Connection->NetworkAddr);
-  HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
-  HeapFree(GetProcessHeap(), 0, Connection->CookieAuth);
-  if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
-  if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
+    TRACE("%p ref=%u\n", connection, ref);
 
-  /* server-only */
-  if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
+    if (!ref)
+    {
+        RPCRT4_CloseConnection(connection);
+        RPCRT4_strfree(connection->Endpoint);
+        RPCRT4_strfree(connection->NetworkAddr);
+        HeapFree(GetProcessHeap(), 0, connection->NetworkOptions);
+        HeapFree(GetProcessHeap(), 0, connection->CookieAuth);
+        if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo);
+        if (connection->QOS) RpcQualityOfService_Release(connection->QOS);
 
-  if (Connection->protseq)
-  {
-    EnterCriticalSection(&Connection->protseq->cs);
-    list_remove(&Connection->protseq_entry);
-    LeaveCriticalSection(&Connection->protseq->cs);
-  }
+        /* server-only */
+        if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding);
 
-  if (Connection->wait_release) SetEvent(Connection->wait_release);
+        if (connection->wait_release) SetEvent(connection->wait_release);
 
-  HeapFree(GetProcessHeap(), 0, Connection);
-  return RPC_S_OK;
+        HeapFree(GetProcessHeap(), 0, connection);
+    }
+    return RPC_S_OK;
 }
 
 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)




More information about the wine-cvs mailing list