core: fix endless loops waiting for activation
authorNorbert Federa <norbert.federa@thincast.com>
Thu, 20 Feb 2020 16:26:27 +0000 (17:26 +0100)
committerNorbert Federa <norbert.federa@thincast.com>
Thu, 20 Feb 2020 16:51:20 +0000 (17:51 +0100)
There are two loops polling the transport pdu receiver in non-blocking mode
when waiting for reaching CONNECTION_STATE_ACTIVE rdp state.

In case of an invalid pdu size in the tpkt header this leaded to an endless
loop, utilizing 100% of a cpu core.

Added a sleep and limited the max loop time to the tcp ack timout value.

libfreerdp/core/activation.c
libfreerdp/core/connection.c

index 98381e2..51d95da 100644 (file)
@@ -24,6 +24,8 @@
 #include "activation.h"
 #include "display.h"
 
+#define TAG FREERDP_TAG("core.activation")
+
 /*
 static const char* const CTRLACTION_STRINGS[] =
 {
@@ -255,6 +257,7 @@ BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp)
 BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
 {
        UINT16 lengthSourceDescriptor;
+       UINT32 timeout;
 
        if (rdp->state == CONNECTION_STATE_ACTIVE)
                rdp->deactivation_reactivation = TRUE;
@@ -288,18 +291,22 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
 
        rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
 
-       while (rdp->state != CONNECTION_STATE_ACTIVE)
+       for (timeout = 0; timeout < rdp->settings->TcpAckTimeout; timeout += 100)
        {
                if (rdp_check_fds(rdp) < 0)
                        return FALSE;
 
                if (freerdp_shall_disconnect(rdp->instance))
-                       break;
+                       return TRUE;
 
-               SwitchToThread();
+               if (rdp->state == CONNECTION_STATE_ACTIVE)
+                       return TRUE;
+
+               Sleep(100);
        }
 
-       return TRUE;
+       WLog_ERR(TAG, "Timeout waiting for activation");
+       return FALSE;
 }
 
 BOOL rdp_send_deactivate_all(rdpRdp* rdp)
index 3643d0f..817fbba 100644 (file)
@@ -233,6 +233,7 @@ BOOL rdp_client_connect(rdpRdp* rdp)
        /* make sure SSL is initialize for earlier enough for crypto, by taking advantage of winpr SSL
         * FIPS flag for openssl initialization */
        DWORD flags = WINPR_SSL_INIT_DEFAULT;
+       UINT32 timeout;
 
        if (!rdp_client_reset_codecs(rdp->context))
                return FALSE;
@@ -361,18 +362,22 @@ BOOL rdp_client_connect(rdpRdp* rdp)
                        return FALSE;
        }
 
-       while (rdp->state != CONNECTION_STATE_ACTIVE)
+       for (timeout = 0; timeout < settings->TcpAckTimeout; timeout += 100)
        {
                if (rdp_check_fds(rdp) < 0)
                {
                        freerdp_set_last_error_if_not(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
-
                        return FALSE;
                }
-               SwitchToThread();
+
+               if (rdp->state == CONNECTION_STATE_ACTIVE)
+                       return TRUE;
+
+               Sleep(100);
        }
 
-       return TRUE;
+       WLog_ERR(TAG, "Timeout waiting for activation");
+       return FALSE;
 }
 
 BOOL rdp_client_disconnect(rdpRdp* rdp)