From 9a1ee1bae5a9561f5031a7b69129f10458b62d4a Mon Sep 17 00:00:00 2001 From: akallabeth <akallabeth@posteo.net> Date: Tue, 22 Aug 2023 10:48:57 +0200 Subject: [PATCH] [codec,nsc] fix input length validation (cherry picked from commit e6bb37bea1a645610cc7e030e11fa3ec9e758dc9) --- libfreerdp/codec/nsc.c | 32 ++++++++++++++++++++++++++++---- libfreerdp/codec/nsc_types.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index cd65f072f000..645ca7512716 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -119,12 +119,17 @@ static BOOL nsc_decode(NSC_CONTEXT* context) return TRUE; } -static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalSize) +static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outSize, + UINT32 originalSize) { UINT32 left = originalSize; while (left > 4) { + if (inSize < 1) + return FALSE; + inSize--; + const BYTE value = *in++; UINT32 len = 0; @@ -137,17 +142,26 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS *out++ = value; left--; } + else if (inSize < 1) + return FALSE; else if (value == *in) { + inSize--; in++; - if (*in < 0xFF) + if (inSize < 1) + return FALSE; + else if (*in < 0xFF) { + inSize--; len = (UINT32)*in++; len += 2; } else { + if (inSize < 5) + return FALSE; + inSize -= 5; in++; len = ((UINT32)(*in++)); len |= ((UINT32)(*in++)) << 8U; @@ -177,6 +191,8 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS if ((outSize < 4) || (left < 4)) return FALSE; + if (inSize < 4) + return FALSE; memcpy(out, in, 4); return TRUE; } @@ -186,7 +202,8 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) if (!context) return FALSE; - BYTE* rle = context->Planes; + const BYTE* rle = context->Planes; + size_t rleSize = context->PlanesSize; WINPR_ASSERT(rle); for (size_t i = 0; i < 4; i++) @@ -194,6 +211,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) const UINT32 originalSize = context->OrgByteCount[i]; const UINT32 planeSize = context->PlaneByteCount[i]; + if (rleSize < planeSize) + return FALSE; + if (planeSize == 0) { if (context->priv->PlaneBuffersLength < originalSize) @@ -203,7 +223,7 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) } else if (planeSize < originalSize) { - if (!nsc_rle_decode(rle, context->priv->PlaneBuffers[i], + if (!nsc_rle_decode(rle, rleSize, context->priv->PlaneBuffers[i], context->priv->PlaneBuffersLength, originalSize)) return FALSE; } @@ -212,6 +232,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) if (context->priv->PlaneBuffersLength < originalSize) return FALSE; + if (rleSize < originalSize) + return FALSE; + CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize); } @@ -239,6 +262,7 @@ static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Seek(s, 2); /* Reserved (2 bytes) */ context->Planes = Stream_Pointer(s); + context->PlanesSize = total; return Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, total); } diff --git a/libfreerdp/codec/nsc_types.h b/libfreerdp/codec/nsc_types.h index 14c1a946bcd1..5a6506baea5a 100644 --- a/libfreerdp/codec/nsc_types.h +++ b/libfreerdp/codec/nsc_types.h @@ -61,6 +61,7 @@ struct _NSC_CONTEXT UINT32 BitmapDataLength; BYTE* Planes; + size_t PlanesSize; UINT32 PlaneByteCount[4]; UINT32 ColorLossLevel; UINT32 ChromaSubsamplingLevel;