Fixed freerdp_channel_process length checks
authorArmin Novak <armin.novak@thincast.com>
Wed, 4 Mar 2020 13:26:41 +0000 (14:26 +0100)
committerArmin Novak <armin.novak@thincast.com>
Wed, 4 Mar 2020 13:44:03 +0000 (14:44 +0100)
Fragmented data was not handled properly.

libfreerdp/core/channels.c

index b20c23f..d286702 100644 (file)
@@ -122,23 +122,46 @@ BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, int s
        return TRUE;
 }
 
-BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId)
+BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength)
 {
+       int rc = 0;
        UINT32 length;
        UINT32 flags;
        size_t chunkLength;
 
+       if (packetLength < 8)
+       {
+               WLog_ERR(TAG, "Header length %" PRIdz " bytes promised, none available", packetLength);
+               return FALSE;
+       }
+       packetLength -= 8;
+
        if (Stream_GetRemainingLength(s) < 8)
                return FALSE;
 
        Stream_Read_UINT32(s, length);
        Stream_Read_UINT32(s, flags);
        chunkLength = Stream_GetRemainingLength(s);
-       if (length > chunkLength)
+       if (packetLength != chunkLength)
+       {
+               WLog_ERR(TAG, "Header length %" PRIdz " != actual length %" PRIdz, packetLength,
+                        chunkLength);
+               return FALSE;
+       }
+       if (length < chunkLength)
+       {
+               WLog_ERR(TAG, "Expected %" PRIu32 " bytes, but only have %" PRIdz, length, chunkLength);
+               return FALSE;
+       }
+       IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength,
+                 flags, length);
+       if (rc != CHANNEL_RC_OK)
+       {
+               WLog_WARN(TAG, "ReceiveChannelData returned %d", rc);
                return FALSE;
-       IFCALL(instance->ReceiveChannelData, instance, channelId, Stream_Pointer(s), chunkLength, flags,
-              length);
-       return Stream_SafeSeek(s, length);
+       }
+
+       return Stream_SafeSeek(s, chunkLength);
 }
 
 BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId)
@@ -186,7 +209,7 @@ BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 chann
        else if (client->ReceiveChannelData)
        {
                int rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s), chunkLength,
-                                                   flags, length);
+                                                    flags, length);
                if (rc < 0)
                        return FALSE;
        }