From baee520e3dd9be6511c45a14c5f5e77784de1471 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Thu, 20 Sep 2018 09:06:01 +0200
Subject: [PATCH] Fix for #4866: Added additional length checks

---
 channels/drdynvc/client/drdynvc_main.c | 61 +++++++++++++++++++++++++++++-----
 1 file changed, 53 insertions(+), 8 deletions(-)

Index: b/channels/drdynvc/client/drdynvc_main.c
===================================================================
--- a/channels/drdynvc/client/drdynvc_main.c	2019-01-10 17:03:57.153015287 +0800
+++ b/channels/drdynvc/client/drdynvc_main.c	2019-01-11 13:24:47.499539805 +0800
@@ -655,7 +655,7 @@ static UINT dvcman_receive_channel_data(
 	if (channel->dvc_data)
 	{
 		/* Fragmented data */
-		if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data))
+		if (Stream_GetPosition(channel->dvc_data) + dataSize > Stream_Capacity(channel->dvc_data))
 		{
 			WLog_ERR(TAG, "data exceeding declared length!");
 			Stream_Release(channel->dvc_data);
@@ -663,7 +663,7 @@ static UINT dvcman_receive_channel_data(
 			return ERROR_INVALID_DATA;
 		}
 
-		Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize);
+		Stream_Copy(data, channel->dvc_data, dataSize);
 
 		if (((size_t) Stream_GetPosition(channel->dvc_data)) >= channel->dvc_data_length)
 		{
@@ -885,6 +885,9 @@ static UINT drdynvc_process_capability_r
 
 	WLog_DBG(TAG, "capability_request Sp=%d cbChId=%d", Sp, cbChId);
 
+	if (Stream_GetRemainingLength(s) < 3)
+		return ERROR_INVALID_DATA;
+
 	Stream_Seek(s, 1); /* pad */
 	Stream_Read_UINT16(s, drdynvc->version);
 
@@ -893,6 +896,9 @@ static UINT drdynvc_process_capability_r
 	 */
 	if ((drdynvc->version == 2) || (drdynvc->version == 3))
 	{
+		if (Stream_GetRemainingLength(s) < 8)
+			return ERROR_INVALID_DATA;
+
 		Stream_Read_UINT16(s, drdynvc->PriorityCharge0);
 		Stream_Read_UINT16(s, drdynvc->PriorityCharge1);
 		Stream_Read_UINT16(s, drdynvc->PriorityCharge2);
@@ -906,6 +912,21 @@ static UINT drdynvc_process_capability_r
 	return status;
 }
 
+static UINT32 drdynvc_cblen_to_bytes(int cbLen)
+{
+	switch (cbLen)
+	{
+		case 0:
+			return 1;
+
+		case 1:
+			return 2;
+
+		default:
+			return 4;
+	}
+}
+
 static UINT32 drdynvc_read_variable_uint(wStream* s, int cbLen)
 {
 	UINT32 val;
@@ -941,6 +962,8 @@ static UINT drdynvc_process_create_reque
 	UINT32 ChannelId;
 	wStream* data_out;
 	UINT channel_status;
+	char* name;
+	size_t length;
 
 	if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES)
 	{
@@ -959,11 +982,20 @@ static UINT drdynvc_process_create_reque
 		drdynvc->state = DRDYNVC_STATE_READY;
 	}
 
+	if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId))
+		return ERROR_INVALID_DATA;
+
 	ChannelId = drdynvc_read_variable_uint(s, cbChId);
 	pos = Stream_GetPosition(s);
-	WLog_DBG(TAG, "process_create_request: ChannelId=%d ChannelName=%s", ChannelId, Stream_Pointer(s));
+	name = Stream_Pointer(s);
+	length = Stream_GetRemainingLength(s);
+
+	if (strnlen(name, length) >= length)
+		return ERROR_INVALID_DATA;
 
-	channel_status = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*) Stream_Pointer(s));
+	WLog_DBG(TAG, "process_create_request: ChannelId=%d ChannelName=%s", ChannelId, name);
+
+	channel_status = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, name);
 
 	data_out = Stream_New(NULL, pos + 4);
 
@@ -1026,6 +1058,9 @@ static UINT drdynvc_process_data_first(d
 	UINT32 Length;
 	UINT32 ChannelId;
 
+	if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId) + drdynvc_cblen_to_bytes(Sp))
+		return ERROR_INVALID_DATA;
+
 	ChannelId = drdynvc_read_variable_uint(s, cbChId);
 	Length = drdynvc_read_variable_uint(s, Sp);
 	WLog_DBG(TAG, "process_data_first: Sp=%d cbChId=%d, ChannelId=%d Length=%d", Sp, cbChId, ChannelId, Length);
@@ -1047,6 +1082,9 @@ static UINT drdynvc_process_data(drdynvc
 {
 	UINT32 ChannelId;
 
+	if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId))
+		return ERROR_INVALID_DATA;
+
 	ChannelId = drdynvc_read_variable_uint(s, cbChId);
 	WLog_DBG(TAG, "process_data: Sp=%d cbChId=%d, ChannelId=%d", Sp, cbChId, ChannelId);
 
@@ -1066,6 +1104,9 @@ static UINT drdynvc_process_close_reques
 	UINT32 ChannelId;
 	wStream* data_out;
 
+	if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId))
+		return ERROR_INVALID_DATA;
+
 	ChannelId = drdynvc_read_variable_uint(s, cbChId);
 
 	WLog_DBG(TAG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%d", Sp, cbChId, ChannelId);
@@ -1110,6 +1151,9 @@ static UINT drdynvc_order_recv(drdynvcPl
 	int Sp;
 	int cbChId;
 
+	if (Stream_GetRemainingLength(s) < 1)
+		return ERROR_INVALID_DATA;
+
 	Stream_Read_UINT8(s, value);
 
 	Cmd = (value & 0xf0) >> 4;
@@ -1275,7 +1319,7 @@ static UINT drdynvc_virtual_channel_even
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
-	if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength))
+	if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
 	{
 		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
 		Stream_Free(drdynvc->data_in, TRUE);
