From baee520e3dd9be6511c45a14c5f5e77784de1471 Mon Sep 17 00:00:00 2001 From: Armin Novak 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(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 631b6f1cc..6924546fb 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -639,8 +639,7 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, 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_Print(drdynvc->log, WLOG_ERROR, "data exceeding declared length!"); Stream_Release(channel->dvc_data); @@ -648,7 +647,7 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, return ERROR_INVALID_DATA; } - Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize); + Stream_Copy(data, channel->dvc_data, dataSize); if (Stream_GetPosition(channel->dvc_data) >= channel->dvc_data_length) { @@ -880,6 +879,9 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, if (!drdynvc) return CHANNEL_RC_BAD_INIT_HANDLE; + if (Stream_GetRemainingLength(s) < 3) + return ERROR_INVALID_DATA; + WLog_Print(drdynvc->log, WLOG_TRACE, "capability_request Sp=%d cbChId=%d", Sp, cbChId); Stream_Seek(s, 1); /* pad */ Stream_Read_UINT16(s, drdynvc->version); @@ -889,6 +891,9 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, */ 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); @@ -900,6 +905,21 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, 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; @@ -935,6 +955,8 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, UINT32 ChannelId; wStream* data_out; UINT channel_status; + char* name; + size_t length; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -957,13 +979,20 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, 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); + name = Stream_Pointer(s); + length = Stream_GetRemainingLength(s); + + if (strnlen(name, length) >= length) + return ERROR_INVALID_DATA; + WLog_Print(drdynvc->log, WLOG_DEBUG, "process_create_request: ChannelId=%"PRIu32" ChannelName=%s", - ChannelId, - Stream_Pointer(s)); - channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, - (char*) Stream_Pointer(s)); + ChannelId, name); + channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, name); data_out = Stream_New(NULL, pos + 4); if (!data_out) @@ -1024,6 +1053,10 @@ static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, UINT status; 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_Print(drdynvc->log, WLOG_DEBUG, @@ -1047,6 +1080,10 @@ static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { UINT32 ChannelId; + + if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) + return ERROR_INVALID_DATA; + ChannelId = drdynvc_read_variable_uint(s, cbChId); WLog_Print(drdynvc->log, WLOG_TRACE, "process_data: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp, cbChId, @@ -1066,6 +1103,10 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, UINT error; 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_Print(drdynvc->log, WLOG_DEBUG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp, @@ -1108,6 +1149,10 @@ static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc, wStream* s) int Cmd; int Sp; int cbChId; + + if (Stream_GetRemainingLength(s) < 1) + return ERROR_INVALID_DATA; + Stream_Read_UINT8(s, value); Cmd = (value & 0xf0) >> 4; Sp = (value & 0x0c) >> 2; @@ -1166,7 +1211,7 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, return CHANNEL_RC_NO_MEMORY; } - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); Stream_Free(drdynvc->data_in, TRUE);