From a58129346d20dcc0b9728a67eee6c8ebbd57d0b0 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 18 May 2020 09:24:01 +0200 Subject: [PATCH] Fixed extended info packet alignment. (cherry picked from commit 03ebaf2dc1547c75f8693dd5087ce2e8dc17765a) --- libfreerdp/core/info.c | 117 ++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 99f3986..584c6f8 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -67,6 +67,54 @@ static struct { INFO_HIDEF_RAIL_SUPPORTED, "INFO_HIDEF_RAIL_SUPPORTED" }, }; +static BOOL rdp_read_info_null_string(UINT32 flags, wStream* s, size_t cbLen, CHAR** dst, + size_t max) +{ + CHAR* ret = NULL; + + const BOOL unicode = flags & INFO_UNICODE; + const size_t nullSize = unicode ? sizeof(WCHAR) : sizeof(CHAR); + + if (Stream_GetRemainingLength(s) < (size_t)(cbLen)) + return FALSE; + + if (cbLen > 0) + { + WCHAR domain[512 / sizeof(WCHAR) + sizeof(WCHAR)] = { 0 }; + /* cbDomain is the size in bytes of the character data in the Domain field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbLen % 2) || (cbLen > (max - nullSize))) + { + WLog_ERR(TAG, "protocol error: invalid value: %" PRIuz "", cbLen); + return FALSE; + } + + Stream_Read(s, domain, cbLen); + + if (unicode) + { + if (ConvertFromUnicode(CP_UTF8, 0, domain, cbLen, &ret, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert Domain string"); + return FALSE; + } + } + else + { + ret = calloc(cbLen + 1, nullSize); + if (!ret) + return FALSE; + memcpy(ret, domain, cbLen); + } + } + + free(*dst); + *dst = ret; + return TRUE; +} + static char* rdp_info_package_flags_description(UINT32 flags) { char* result; @@ -245,10 +293,6 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) UINT16 cbClientDir; UINT16 cbAutoReconnectLen; rdpSettings* settings = rdp->settings; - union { - BYTE* bp; - WCHAR* wp; - } ptrconv; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -275,33 +319,9 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < cbClientAddress) return FALSE; - if (settings->ClientAddress) - { - free(settings->ClientAddress); - settings->ClientAddress = NULL; - } - - if (cbClientAddress) - { - ptrconv.bp = Stream_Pointer(s); - - if ((cbClientAddress < sizeof(WCHAR)) || (ptrconv.bp[cbClientAddress - 1]) || - (ptrconv.bp[cbClientAddress - 2])) - { - WLog_ERR(TAG, "protocol error: clientAddress must be null terminated"); - return FALSE; - } - - if (ConvertFromUnicode(CP_UTF8, 0, ptrconv.wp, -1, &settings->ClientAddress, 0, NULL, - NULL) < 1) - { - WLog_ERR(TAG, "failed to convert client address"); - return FALSE; - } - - Stream_Seek(s, cbClientAddress); - WLog_DBG(TAG, "rdp client address: [%s]", settings->ClientAddress); - } + if (!rdp_read_info_null_string(INFO_UNICODE, s, cbClientAddress, &settings->ClientAddress, + (settings->RdpVersion < RDP_VERSION_10_0) ? 64 : 80)) + return FALSE; if (Stream_GetRemainingLength(s) < 2) return FALSE; @@ -316,42 +336,9 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) * sets cbClientDir to 0. */ - if ((cbClientDir % 2) || cbClientDir > 512) - { - WLog_ERR(TAG, "protocol error: invalid cbClientDir value: %" PRIu16 "", cbClientDir); - return FALSE; - } - - if (Stream_GetRemainingLength(s) < cbClientDir) + if (!rdp_read_info_null_string(INFO_UNICODE, s, cbClientDir, &settings->ClientDir, 512)) return FALSE; - if (settings->ClientDir) - { - free(settings->ClientDir); - settings->ClientDir = NULL; - } - - if (cbClientDir) - { - ptrconv.bp = Stream_Pointer(s); - - if ((cbClientDir < sizeof(WCHAR)) || (ptrconv.bp[cbClientDir - 1]) || - (ptrconv.bp[cbClientDir - 2])) - { - WLog_ERR(TAG, "protocol error: clientDir must be null terminated"); - return FALSE; - } - - if (ConvertFromUnicode(CP_UTF8, 0, ptrconv.wp, -1, &settings->ClientDir, 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert client directory"); - return FALSE; - } - - Stream_Seek(s, cbClientDir); - WLog_DBG(TAG, "rdp client dir: [%s]", settings->ClientDir); - } - /** * down below all fields are optional but if one field is not present, * then all of the subsequent fields also MUST NOT be present. -- 2.7.4