Skip to content

Commit

Permalink
[codec,zgfx] allocate in segment steps
Browse files Browse the repository at this point in the history
do not trust the uncompressedSize of a ZGFX_SEGMENTED_MULTIPART and
allocate the output buffer in steps after decoding a segment.
  • Loading branch information
akallabeth committed Apr 20, 2024
1 parent 9314b54 commit 5e5d27c
Showing 1 changed file with 46 additions and 29 deletions.
75 changes: 46 additions & 29 deletions libfreerdp/codec/zgfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,16 +382,46 @@ static BYTE* aligned_zgfx_malloc(size_t size)
return malloc(size + 64);
}

static BOOL zgfx_append(ZGFX_CONTEXT* zgfx, BYTE** ppConcatenated, size_t uncompressedSize,
size_t* pUsed)
{
WINPR_ASSERT(zgfx);
WINPR_ASSERT(ppConcatenated);
WINPR_ASSERT(pUsed);

const size_t used = *pUsed;
if (zgfx->OutputCount > UINT32_MAX - used)
return FALSE;

if (used + zgfx->OutputCount > uncompressedSize)
return FALSE;

BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull);
if (!tmp)
return FALSE;
*ppConcatenated = tmp;
CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount);
*pUsed = used + zgfx->OutputCount;
return TRUE;
}

int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
UINT32* pDstSize, UINT32 flags)
{
int status = -1;
BYTE descriptor = 0;
wStream sbuffer = { 0 };
size_t used = 0;
BYTE* pConcatenated = NULL;
wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);

WINPR_ASSERT(zgfx);
WINPR_ASSERT(stream);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);

*ppDstData = NULL;
*pDstSize = 0;

if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
goto fail;
Expand All @@ -403,43 +433,29 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY
if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
goto fail;

*ppDstData = NULL;

if (zgfx->OutputCount > 0)
*ppDstData = aligned_zgfx_malloc(zgfx->OutputCount);

if (!*ppDstData)
goto fail;

*pDstSize = zgfx->OutputCount;
CopyMemory(*ppDstData, zgfx->OutputBuffer, zgfx->OutputCount);
{
if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used))
goto fail;
if (used != zgfx->OutputCount)
goto fail;
*ppDstData = pConcatenated;
*pDstSize = zgfx->OutputCount;
}
}
else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
{
UINT32 segmentSize = 0;
UINT16 segmentNumber = 0;
UINT16 segmentCount = 0;
UINT32 uncompressedSize = 0;
BYTE* pConcatenated = NULL;
size_t used = 0;

if (!Stream_CheckAndLogRequiredLength(TAG, stream, 6))
goto fail;

Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */
Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */

if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, stream, segmentCount, sizeof(UINT32)))
goto fail;

pConcatenated = aligned_zgfx_malloc(uncompressedSize);

if (!pConcatenated)
goto fail;

*ppDstData = pConcatenated;
*pDstSize = uncompressedSize;

for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
{
if (!Stream_CheckAndLogRequiredLength(TAG, stream, sizeof(UINT32)))
Expand All @@ -450,16 +466,15 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY
if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
goto fail;

if (zgfx->OutputCount > UINT32_MAX - used)
if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used))
goto fail;
}

if (used + zgfx->OutputCount > uncompressedSize)
goto fail;
if (used != uncompressedSize)
goto fail;

CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount);
pConcatenated += zgfx->OutputCount;
used += zgfx->OutputCount;
}
*ppDstData = pConcatenated;
*pDstSize = uncompressedSize;
}
else
{
Expand All @@ -468,6 +483,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY

status = 1;
fail:
if (status < 0)
free(pConcatenated);
return status;
}

Expand Down

0 comments on commit 5e5d27c

Please sign in to comment.