From cd1da25a87358eb3b5512fd259310e95b19a05ec Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 10:48:57 +0200 Subject: [PATCH] [codec,nsc] fix input length validation --- 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 5884fe684..5a5056075 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -112,12 +112,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; @@ -130,17 +135,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; @@ -170,6 +184,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; } @@ -179,7 +195,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++) @@ -187,6 +204,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) @@ -196,7 +216,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; } @@ -205,6 +225,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); } @@ -232,6 +255,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 eaf73895e..731a08af5 100644 --- a/libfreerdp/codec/nsc_types.h +++ b/libfreerdp/codec/nsc_types.h @@ -57,6 +57,7 @@ struct S_NSC_CONTEXT UINT32 BitmapDataLength; BYTE* Planes; + size_t PlanesSize; UINT32 PlaneByteCount[4]; UINT32 ColorLossLevel; UINT32 ChromaSubsamplingLevel;