Skip to content
Permalink
Browse files Browse the repository at this point in the history
Fixed oob read in cliprdr_read_format_list
  • Loading branch information
akallabeth committed May 5, 2020
1 parent 495cb2e commit b73143c
Showing 1 changed file with 39 additions and 46 deletions.
85 changes: 39 additions & 46 deletions channels/cliprdr/cliprdr_common.c
Expand Up @@ -400,29 +400,32 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL
int formatNameLength;
char* szFormatName;
WCHAR* wszFormatName;
UINT32 dataLen = formatList->dataLen;
wStream sub1, sub2;
CLIPRDR_FORMAT* formats = NULL;
UINT error = CHANNEL_RC_OK;

asciiNames = (formatList->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE;

index = 0;
/* empty format list */
formatList->formats = NULL;
formatList->numFormats = 0;
position = Stream_GetPosition(s);

Stream_StaticInit(&sub1, Stream_Pointer(s), formatList->dataLen);
if (!Stream_SafeSeek(s, formatList->dataLen))
return ERROR_INVALID_DATA;

if (!formatList->dataLen)
{
/* empty format list */
formatList->formats = NULL;
formatList->numFormats = 0;
}
else if (!useLongFormatNames)
{
formatList->numFormats = (dataLen / 36);
const size_t cap = Stream_Capacity(&sub1);
formatList->numFormats = (cap / 36);

if ((formatList->numFormats * 36) != dataLen)
if ((formatList->numFormats * 36) != cap)
{
WLog_ERR(TAG, "Invalid short format list length: %" PRIu32 "", dataLen);
WLog_ERR(TAG, "Invalid short format list length: %" PRIuz "", cap);
return ERROR_INTERNAL_ERROR;
}

Expand All @@ -437,10 +440,9 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL

formatList->formats = formats;

while (dataLen)
while (Stream_GetRemainingLength(&sub1) >= 4)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
Stream_Read_UINT32(&sub1, formats[index].formatId); /* formatId (4 bytes) */

formats[index].formatName = NULL;

Expand All @@ -452,10 +454,12 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL
* These are 16 unicode charaters - *without* terminating null !
*/

szFormatName = (char*)Stream_Pointer(&sub1);
wszFormatName = (WCHAR*)Stream_Pointer(&sub1);
if (!Stream_SafeSeek(&sub1, 32))
goto error_out;
if (asciiNames)
{
szFormatName = (char*)Stream_Pointer(s);

if (szFormatName[0])
{
/* ensure null termination */
Expand All @@ -472,8 +476,6 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL
}
else
{
wszFormatName = (WCHAR*)Stream_Pointer(s);

if (wszFormatName[0])
{
/* ConvertFromUnicode always returns a null-terminated
Expand All @@ -489,34 +491,27 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL
}
}

Stream_Seek(s, 32);
dataLen -= 32;
index++;
}
}
else
{
while (dataLen)
sub2 = sub1;
while (Stream_GetRemainingLength(&sub1) > 0)
{
Stream_Seek(s, 4); /* formatId (4 bytes) */
dataLen -= 4;
size_t rest;
if (!Stream_SafeSeek(&sub1, 4)) /* formatId (4 bytes) */
goto error_out;

wszFormatName = (WCHAR*)Stream_Pointer(s);

if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);

Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
wszFormatName = (WCHAR*)Stream_Pointer(&sub1);
rest = Stream_GetRemainingLength(&sub1);
formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR));

if (!Stream_SafeSeek(&sub1, (formatNameLength + 1) * sizeof(WCHAR)))
goto error_out;
formatList->numFormats++;
}

dataLen = formatList->dataLen;
Stream_SetPosition(s, position);

if (formatList->numFormats)
formats = (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT));

Expand All @@ -528,34 +523,30 @@ UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL

formatList->formats = formats;

while (dataLen)
while (Stream_GetRemainingLength(&sub2) >= 4)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
size_t rest;
Stream_Read_UINT32(&sub2, formats[index].formatId); /* formatId (4 bytes) */

formats[index].formatName = NULL;

wszFormatName = (WCHAR*)Stream_Pointer(s);

if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);
wszFormatName = (WCHAR*)Stream_Pointer(&sub2);
rest = Stream_GetRemainingLength(&sub2);
formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR));
if (!Stream_SafeSeek(&sub2, (formatNameLength + 1) * sizeof(WCHAR)))
goto error_out;

if (formatNameLength)
{
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, &(formats[index].formatName),
0, NULL, NULL) < 1)
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, formatNameLength,
&(formats[index].formatName), 0, NULL, NULL) < 1)
{
WLog_ERR(TAG, "failed to convert long clipboard format name");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
}

Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);

index++;
}
}
Expand All @@ -582,5 +573,7 @@ void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList)
}

free(formatList->formats);
formatList->formats = NULL;
formatList->numFormats = 0;
}
}

0 comments on commit b73143c

Please sign in to comment.