diff --git a/CMakeLists.txt b/CMakeLists.txt index e2eba2f..67f3437 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.5") +set(RAW_VERSION_STRING "2.11.7") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 545d99b..a2209be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +# 2024-04-22 Version 2.11.7 + +Noteworthy changes: +* Backported oss-fuzz fixes + +For a complete and detailed change log since the last release run: +git log 2.11.7...2.11.6 + +# 2024-04-17 Version 2.11.6 + +CVE: + CVE-2024-32041 [Low[ OutOfBound Read in zgfx_decompress_segment + CVE-2024-32039 [Moderate] Integer overflow & OutOfBound Write in clear_decompress_residual_data + CVE-2024-32040 [Low] integer underflow in nsc_rle_decode + CVE-2024-32458 [Low] OutOfBound Read in planar_skip_plane_rle + CVE-2024-32459 [Low] OutOfBound Read in ncrush_decompress + CVE-2024-32460 [Low] OutOfBound Read in interleaved_decompress + +Noteworthy changes: +* Backported #10077 + +For a complete and detailed change log since the last release run: +git log 2.11.6...2.11.5 + # 2024-01-19 Version 2.11.5 Noteworthy changes: diff --git a/cmake/ClangDetectTool.cmake b/cmake/ClangDetectTool.cmake new file mode 100644 index 0000000..a1ecd56 --- /dev/null +++ b/cmake/ClangDetectTool.cmake @@ -0,0 +1,48 @@ +function (clang_detect_tool VAR NAME OPTS) + set(NAMES "") + foreach(CNT RANGE 12 22) + list(APPEND NAMES "${NAME}-${CNT}") + endforeach() + list(REVERSE NAMES) + list(APPEND NAMES ${NAME}) + + find_program(${VAR} + NAMES ${NAMES} + ${OPTS} + ) + if (NOT ${VAR}) + message(WARNING "clang tool ${NAME} (${VAR}) not detected, skipping") + unset(${VAR}) + return() + endif() + + execute_process( + COMMAND ${${VAR}} "--version" + OUTPUT_VARIABLE _CLANG_TOOL_VERSION + RESULT_VARIABLE _CLANG_TOOL_VERSION_FAILED + ) + + if (_CLANG_TOOL_VERSION_FAILED) + message(WARNING "A problem was encounterd with ${${VAR}}") + message(WARNING "${_CLANG_TOOL_VERSION_FAILED}") + unset(${VAR}) + return() + endif() + + string(REGEX MATCH "([7-9]|[1-9][0-9])\\.[0-9]\\.[0-9]" CLANG_TOOL_VERSION + "${_CLANG_TOOL_VERSION}") + + if (NOT CLANG_TOOL_VERSION) + message(WARNING "problem parsing ${NAME} version for ${${VAR}}") + unset(${VAR}) + return() + endif() + + set(_CLANG_TOOL_MINIMUM_VERSION "12.0.0") + if (${CLANG_TOOL_VERSION} VERSION_LESS ${_CLANG_TOOL_MINIMUM_VERSION}) + message(WARNING "clang-format version ${CLANG_TOOL_VERSION} not supported") + message(WARNING "Minimum version required: ${_CLANG_TOOL_MINIMUM_VERSION}") + unset(${VAR}) + return() + endif() +endfunction() diff --git a/cmake/ClangFormat.cmake b/cmake/ClangFormat.cmake index 8985ef3..b815822 100644 --- a/cmake/ClangFormat.cmake +++ b/cmake/ClangFormat.cmake @@ -1,43 +1,12 @@ # get all project files file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.c *.h *.m *.java) -# minimum version required -set(_CLANG_FORMAT_MINIMUM_VERSION 7.0.0) -find_program(CLANG_FORMAT - NAMES - clang-format-8 - clang-format-7 - clang-format - ) +include(ClangDetectTool) +clang_detect_tool(CLANG_FORMAT clang-format "") if (NOT CLANG_FORMAT) message(WARNING "clang-format not found in path! code format target not available.") else() - execute_process( - COMMAND ${CLANG_FORMAT} "--version" - OUTPUT_VARIABLE _CLANG_FORMAT_VERSION - RESULT_VARIABLE _CLANG_FORMAT_VERSION_FAILED - ) - - if (_CLANG_FORMAT_VERSION_FAILED) - message(WARNING "A problem was encounterd with ${CLANG_FORMAT}") - return() - endif() - - string(REGEX MATCH "([7-9]|[1-9][0-9])\\.[0-9]\\.[0-9]" CLANG_FORMAT_VERSION - "${_CLANG_FORMAT_VERSION}") - - if (NOT CLANG_FORMAT_VERSION) - message(WARNING "problem parsing clang-fromat version for ${CLANG_FORMAT}") - return() - endif() - - if (${CLANG_FORMAT_VERSION} VERSION_LESS ${_CLANG_FORMAT_MINIMUM_VERSION}) - message(WARNING "clang-format version ${CLANG_FORMAT_VERSION} not supported") - message(WARNING "Minimum version required: ${_CLANG_FORMAT_MINIMUM_VERSION}") - return() - endif() - add_custom_target( clangformat COMMAND ${CLANG_FORMAT} diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index 1012607..e38fa0d 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -410,7 +410,7 @@ static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* clear, wStream* s, } } - if ((pixelIndex + runLengthFactor) > pixelCount) + if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex))) { WLog_ERR(TAG, "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32 @@ -512,12 +512,12 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* clear, wStream* s, { case 0: /* Uncompressed */ { - UINT32 nSrcStep = width * GetBytesPerPixel(PIXEL_FORMAT_BGR24); - UINT32 nSrcSize = nSrcStep * height; + const UINT32 nSrcStep = width * GetBytesPerPixel(PIXEL_FORMAT_BGR24); + const size_t nSrcSize = 1ull * nSrcStep * height; if (bitmapDataByteCount != nSrcSize) { - WLog_ERR(TAG, "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIu32 "", + WLog_ERR(TAG, "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIuz "", bitmapDataByteCount, nSrcSize); return FALSE; } @@ -821,8 +821,15 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; if (count > 0) - pSrcPixel = - &vBarShortEntry->pixels[(y - vBarYOn) * GetBytesPerPixel(clear->format)]; + { + const size_t offset = (1ull * y - vBarYOn) * GetBytesPerPixel(clear->format); + pSrcPixel = &vBarShortEntry->pixels[offset]; + if (offset + count > vBarShortEntry->count) + { + WLog_ERR(TAG, "offset + count > vBarShortEntry->count"); + return FALSE; + } + } for (x = 0; x < count; x++) { diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 0091998..f8467c2 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -613,6 +613,9 @@ BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 if (!pDstData || !pSrcData) return FALSE; + if ((nWidth == 0) || (nHeight == 0)) + return TRUE; + if (nDstStep == 0) nDstStep = nWidth * GetBytesPerPixel(DstFormat); diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c index 38bcaa8..af83387 100644 --- a/libfreerdp/codec/include/bitmap.c +++ b/libfreerdp/codec/include/bitmap.c @@ -31,7 +31,10 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r BYTE mask = 0x01; if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); return NULL; + } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) return NULL; @@ -46,7 +49,6 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r data = xorPixel; DESTWRITEPIXEL(pbDest, data); - DESTNEXTPIXEL(pbDest); mask = mask << 1; }); return pbDest; @@ -62,7 +64,10 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE mask = 0x01; if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); return NULL; + } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) return NULL; @@ -76,7 +81,6 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, data = BLACK_PIXEL; DESTWRITEPIXEL(pbDest, data); - DESTNEXTPIXEL(pbDest); mask = mask << 1; }); return pbDest; @@ -88,6 +92,9 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer, UINT32 rowDelta, UINT32 width, UINT32 height) { +#if defined(WITH_DEBUG_CODECS) + char sbuffer[128] = { 0 }; +#endif const BYTE* pbSrc = pbSrcBuffer; const BYTE* pbEnd; const BYTE* pbDestEnd; @@ -100,14 +107,22 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY PIXEL pixelA, pixelB; UINT32 runLength; UINT32 code; - UINT32 advance; + UINT32 advance = 0; RLEEXTRA if ((rowDelta == 0) || (rowDelta < width)) + { + WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta, + width); return FALSE; + } if (!pbSrcBuffer || !pbDestBuffer) + { + WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", pbSrcBuffer, + pbDestBuffer); return FALSE; + } pbEnd = pbSrcBuffer + cbSrcBuffer; pbDestEnd = pbDestBuffer + rowDelta * height; @@ -130,10 +145,17 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY */ code = ExtractCodeId(*pbSrc); +#if defined(WITH_DEBUG_CODECS) + WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, + rle_code_str_buffer(code, sbuffer, sizeof(sbuffer)), pbEnd - pbSrc); +#endif + /* Handle Background Run Orders. */ - if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN) + if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN)) { - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (fFirstLine) @@ -144,17 +166,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY return FALSE; DESTWRITEPIXEL(pbDest, fgPel); - DESTNEXTPIXEL(pbDest); runLength = runLength - 1; } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, BLACK_PIXEL); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); }); } else { @@ -166,7 +184,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY return FALSE; DESTWRITEPIXEL(pbDest, temp ^ fgPel); - DESTNEXTPIXEL(pbDest); runLength--; } @@ -176,7 +193,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY UNROLL(runLength, { DESTREADPIXEL(temp, pbDest - rowDelta); DESTWRITEPIXEL(pbDest, temp); - DESTNEXTPIXEL(pbDest); }); } @@ -196,15 +212,16 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY case MEGA_MEGA_FG_RUN: case LITE_SET_FG_FG_RUN: case MEGA_MEGA_SET_FG_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN) { - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(fgPel, pbSrc); - SRCNEXTPIXEL(pbSrc); } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) @@ -212,17 +229,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY if (fFirstLine) { - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, fgPel); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); }); } else { UNROLL(runLength, { DESTREADPIXEL(temp, pbDest - rowDelta); DESTWRITEPIXEL(pbDest, temp ^ fgPel); - DESTNEXTPIXEL(pbDest); }); } @@ -231,45 +244,41 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Dithered Run Orders. */ case LITE_DITHERED_RUN: case MEGA_MEGA_DITHERED_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelA, pbSrc); - SRCNEXTPIXEL(pbSrc); - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelB, pbSrc); - SRCNEXTPIXEL(pbSrc); if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2)) return FALSE; UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); - DESTNEXTPIXEL(pbDest); DESTWRITEPIXEL(pbDest, pixelB); - DESTNEXTPIXEL(pbDest); }); break; /* Handle Color Run Orders. */ case REGULAR_COLOR_RUN: case MEGA_MEGA_COLOR_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelA, pbSrc); - SRCNEXTPIXEL(pbSrc); if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, pixelA); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); }); break; /* Handle Foreground/Background Image Orders. */ @@ -277,17 +286,20 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY case MEGA_MEGA_FGBG_IMAGE: case LITE_SET_FG_FGBG_IMAGE: case MEGA_MEGA_SET_FGBG_IMAGE: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) - return FALSE; if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE) { + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; SRCREADPIXEL(fgPel, pbSrc); - SRCNEXTPIXEL(pbSrc); } + if (!buffer_within_range(pbSrc, runLength / 8, pbEnd)) + return FALSE; if (fFirstLine) { while (runLength > 8) @@ -306,8 +318,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY { while (runLength > 8) { - bitmask = *pbSrc; - pbSrc = pbSrc + 1; + bitmask = *pbSrc++; + pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8); if (!pbDest) @@ -319,8 +331,9 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY if (runLength > 0) { - bitmask = *pbSrc; - pbSrc = pbSrc + 1; + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + bitmask = *pbSrc++; if (fFirstLine) { @@ -342,23 +355,25 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Color Image Orders. */ case REGULAR_COLOR_IMAGE: case MEGA_MEGA_COLOR_IMAGE: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; + if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength)) + return FALSE; UNROLL(runLength, { - if (pbSrc >= pbEnd) - return FALSE; SRCREADPIXEL(temp, pbSrc); - SRCNEXTPIXEL(pbSrc); DESTWRITEPIXEL(pbDest, temp); - DESTNEXTPIXEL(pbDest); }); break; /* Handle Special Order 1. */ case SPECIAL_FGBG_1: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (fFirstLine) @@ -379,6 +394,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Special Order 2. */ case SPECIAL_FGBG_2: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (fFirstLine) @@ -399,27 +416,31 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle White Order. */ case SPECIAL_WHITE: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) return FALSE; DESTWRITEPIXEL(pbDest, WHITE_PIXEL); - DESTNEXTPIXEL(pbDest); break; /* Handle Black Order. */ case SPECIAL_BLACK: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) return FALSE; DESTWRITEPIXEL(pbDest, BLACK_PIXEL); - DESTNEXTPIXEL(pbDest); break; default: + WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p", + code, pbSrcBuffer, pbSrc, pbEnd); return FALSE; } } diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index b76fe1c..e419876 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -21,6 +21,7 @@ * limitations under the License. */ +#include #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -30,15 +31,16 @@ #define TAG FREERDP_TAG("codec") -#define UNROLL_BODY(_exp, _count) \ - do \ - { \ - size_t x; \ - for (x = 0; x < (_count); x++) \ - { \ - do \ - _exp while (FALSE); \ - } \ +#define UNROLL_BODY(_exp, _count) \ + do \ + { \ + for (size_t x = 0; x < (_count); x++) \ + { \ + do \ + { \ + _exp \ + } while (FALSE); \ + } \ } while (FALSE) #define UNROLL_MULTIPLE(_condition, _exp, _count) \ @@ -97,6 +99,80 @@ static const BYTE g_MaskSpecialFgBg2 = 0x05; static const BYTE g_MaskRegularRunLength = 0x1F; static const BYTE g_MaskLiteRunLength = 0x0F; +static const char* rle_code_str(UINT32 code) +{ + switch (code) + { + case REGULAR_BG_RUN: + return "REGULAR_BG_RUN"; + case MEGA_MEGA_BG_RUN: + return "MEGA_MEGA_BG_RUN"; + case REGULAR_FG_RUN: + return "REGULAR_FG_RUN"; + case MEGA_MEGA_FG_RUN: + return "MEGA_MEGA_FG_RUN"; + case LITE_SET_FG_FG_RUN: + return "LITE_SET_FG_FG_RUN"; + case MEGA_MEGA_SET_FG_RUN: + return "MEGA_MEGA_SET_FG_RUN"; + case LITE_DITHERED_RUN: + return "LITE_DITHERED_RUN"; + case MEGA_MEGA_DITHERED_RUN: + return "MEGA_MEGA_DITHERED_RUN"; + case REGULAR_COLOR_RUN: + return "REGULAR_COLOR_RUN"; + case MEGA_MEGA_COLOR_RUN: + return "MEGA_MEGA_COLOR_RUN"; + case REGULAR_FGBG_IMAGE: + return "REGULAR_FGBG_IMAGE"; + case MEGA_MEGA_FGBG_IMAGE: + return "MEGA_MEGA_FGBG_IMAGE"; + case LITE_SET_FG_FGBG_IMAGE: + return "LITE_SET_FG_FGBG_IMAGE"; + case MEGA_MEGA_SET_FGBG_IMAGE: + return "MEGA_MEGA_SET_FGBG_IMAGE"; + case REGULAR_COLOR_IMAGE: + return "REGULAR_COLOR_IMAGE"; + case MEGA_MEGA_COLOR_IMAGE: + return "MEGA_MEGA_COLOR_IMAGE"; + case SPECIAL_FGBG_1: + return "SPECIAL_FGBG_1"; + case SPECIAL_FGBG_2: + return "SPECIAL_FGBG_2"; + case SPECIAL_WHITE: + return "SPECIAL_WHITE"; + case SPECIAL_BLACK: + return "SPECIAL_BLACK"; + default: + return "UNKNOWN"; + } +} + +static const char* rle_code_str_buffer(UINT32 code, char* buffer, size_t size) +{ + const char* str = rle_code_str(code); + _snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, code); + return buffer; +} + +#define buffer_within_range(pbSrc, size, pbEnd) \ + buffer_within_range_((pbSrc), (size), (pbEnd), __func__, __FILE__, __LINE__) +static INLINE BOOL buffer_within_range_(const void* pbSrc, size_t size, const void* pbEnd, + const char* fkt, const char* file, size_t line) +{ + WINPR_UNUSED(file); + WINPR_ASSERT(pbSrc); + WINPR_ASSERT(pbEnd); + + if ((const char*)pbSrc + size > (const char*)pbEnd) + { + WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size, + pbEnd); + return FALSE; + } + return TRUE; +} + /** * Reads the supplied order header and extracts the compression * order code ID. @@ -127,71 +203,155 @@ static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr) /** * Extract the run length of a compression order. */ -static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT32* advance) +static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) { - UINT32 runLength; - UINT32 ladvance; - ladvance = 1; - runLength = 0; + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = (*pbOrderHdr) & g_MaskRegularRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 1; + (*advance)++; + } + else + runLength = runLength * 8; + + return runLength; +} + +static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = *pbOrderHdr & g_MaskLiteRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 1; + (*advance)++; + } + else + runLength = runLength * 8; + + return runLength; +} + +static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = *pbOrderHdr & g_MaskRegularRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 32; + (*advance)++; + } + + return runLength; +} + +static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + if (!buffer_within_range(pbOrderHdr, 3, pbEnd)) + { + *advance = 0; + return 0; + } + + runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8); + (*advance) += 2; + + return runLength; +} + +static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = *pbOrderHdr & g_MaskLiteRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 16; + (*advance)++; + } + return runLength; +} + +static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd, + UINT32* advance) +{ + UINT32 runLength = 0; + UINT32 ladvance = 1; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + *advance = 0; + if (!buffer_within_range(pbOrderHdr, 0, pbEnd)) + return 0; switch (code) { case REGULAR_FGBG_IMAGE: - runLength = (*pbOrderHdr) & g_MaskRegularRunLength; - - if (runLength == 0) - { - runLength = (*(pbOrderHdr + 1)) + 1; - ladvance += 1; - } - else - { - runLength = runLength * 8; - } - + runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance); break; case LITE_SET_FG_FGBG_IMAGE: - runLength = (*pbOrderHdr) & g_MaskLiteRunLength; - - if (runLength == 0) - { - runLength = (*(pbOrderHdr + 1)) + 1; - ladvance += 1; - } - else - { - runLength = runLength * 8; - } - + runLength = ExtractRunLengthLiteFgBg(pbOrderHdr, pbEnd, &ladvance); break; case REGULAR_BG_RUN: case REGULAR_FG_RUN: case REGULAR_COLOR_RUN: case REGULAR_COLOR_IMAGE: - runLength = (*pbOrderHdr) & g_MaskRegularRunLength; - - if (runLength == 0) - { - /* An extended (MEGA) run. */ - runLength = (*(pbOrderHdr + 1)) + 32; - ladvance += 1; - } - + runLength = ExtractRunLengthRegular(pbOrderHdr, pbEnd, &ladvance); break; case LITE_SET_FG_FG_RUN: case LITE_DITHERED_RUN: - runLength = (*pbOrderHdr) & g_MaskLiteRunLength; - - if (runLength == 0) - { - /* An extended (MEGA) run. */ - runLength = (*(pbOrderHdr + 1)) + 16; - ladvance += 1; - } - + runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance); break; case MEGA_MEGA_BG_RUN: @@ -202,8 +362,12 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3 case MEGA_MEGA_FGBG_IMAGE: case MEGA_MEGA_SET_FGBG_IMAGE: case MEGA_MEGA_COLOR_IMAGE: - runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8)); - ladvance += 2; + runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance); + break; + + default: + runLength = 0; + ladvance = 0; break; } @@ -211,20 +375,32 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3 return runLength; } -static INLINE BOOL ensure_capacity(const BYTE* start, const BYTE* end, size_t size, size_t base) +#define ensure_capacity(start, end, size, base) \ + ensure_capacity_((start), (end), (size), (base), __func__, __FILE__, __LINE__) +static INLINE BOOL ensure_capacity_(const BYTE* start, const BYTE* end, size_t size, size_t base, + const char* fkt, const char* file, size_t line) { const size_t available = (uintptr_t)end - (uintptr_t)start; const BOOL rc = available >= size * base; - return rc && (start <= end); + const BOOL res = rc && (start <= end); + + if (!res) + WLog_ERR(TAG, + "[%s:%" PRIuz "] failed: start=%p <= end=%p, available=%" PRIuz " >= size=%" PRIuz + " * base=%" PRIuz, + fkt, line, start, end, available, size, base); + return res; } static INLINE void write_pixel_8(BYTE* _buf, BYTE _pix) { + WINPR_ASSERT(_buf); *_buf = _pix; } static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix) { + WINPR_ASSERT(_buf); (_buf)[0] = (BYTE)(_pix); (_buf)[1] = (BYTE)((_pix) >> 8); (_buf)[2] = (BYTE)((_pix) >> 16); @@ -232,6 +408,7 @@ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix) static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) { + WINPR_ASSERT(_buf); _buf[0] = _pix & 0xFF; _buf[1] = (_pix >> 8) & 0xFF; } @@ -239,19 +416,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 1 +#define PIXEL BYTE #define WHITE_PIXEL 0xFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix) +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_8(_buf, _pix); \ + _buf += 1; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] -#define DESTNEXTPIXEL(_buf) _buf += 1 -#define SRCNEXTPIXEL(_buf) _buf += 1 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0]; \ + _buf += 1; \ + } while (0) + #define WRITEFGBGIMAGE WriteFgBgImage8to8 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8 #define RLEDECOMPRESS RleDecompress8to8 @@ -263,19 +451,29 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 2 +#define PIXEL UINT16 #define WHITE_PIXEL 0xFFFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix) +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_16(_buf, _pix); \ + _buf += 2; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0] -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) -#define DESTNEXTPIXEL(_buf) _buf += 2 -#define SRCNEXTPIXEL(_buf) _buf += 2 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0] | ((_buf)[1] << 8); \ + _buf += 2; \ + } while (0) #define WRITEFGBGIMAGE WriteFgBgImage16to16 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16 #define RLEDECOMPRESS RleDecompress16to16 @@ -287,19 +485,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL -#define WHITE_PIXEL 0xFFFFFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix) +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 3 +#define PIXEL UINT32 +#define WHITE_PIXEL 0xffffff +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_24(_buf, _pix); \ + _buf += 3; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16) -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16) -#define DESTNEXTPIXEL(_buf) _buf += 3 -#define SRCNEXTPIXEL(_buf) _buf += 3 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16); \ + _buf += 3; \ + } while (0) + #define WRITEFGBGIMAGE WriteFgBgImage24to24 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24 #define RLEDECOMPRESS RleDecompress24to24 @@ -308,18 +517,32 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3) #include "include/bitmap.c" +struct S_BITMAP_INTERLEAVED_CONTEXT +{ + BOOL Compressor; + + UINT32 TempSize; + BYTE* TempBuffer; + + wStream* bts; +}; + BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* pSrcData, UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, UINT32 bpp, BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight, const gdiPalette* palette) { - UINT32 scanline; - UINT32 SrcFormat; - UINT32 BufferSize; + UINT32 scanline = 0; + UINT32 SrcFormat = 0; + UINT32 BufferSize = 0; if (!interleaved || !pSrcData || !pDstData) + { + WLog_ERR(TAG, "invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p", interleaved, + pSrcData, pDstData); return FALSE; + } switch (bpp) { @@ -352,19 +575,26 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* if (BufferSize > interleaved->TempSize) { - interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16); + interleaved->TempBuffer = + _aligned_recalloc(interleaved->TempBuffer, BufferSize, sizeof(BYTE), 16); interleaved->TempSize = BufferSize; } if (!interleaved->TempBuffer) + { + WLog_ERR(TAG, "interleaved->TempBuffer=%p", interleaved->TempBuffer); return FALSE; + } switch (bpp) { case 24: if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress24to24 failed"); return FALSE; + } break; @@ -372,24 +602,36 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* case 15: if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress16to16 failed"); return FALSE; + } break; case 8: if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress8to8 failed"); return FALSE; + } break; default: + WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp); return FALSE; } - return freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, - interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette, - FREERDP_FLIP_VERTICAL); + if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, + interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette, + FREERDP_FLIP_VERTICAL)) + { + WLog_ERR(TAG, "freerdp_image_copy failed"); + return FALSE; + } + return TRUE; } BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize, @@ -397,10 +639,10 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette, UINT32 bpp) { - BOOL status; - wStream* s; + BOOL status = 0; + wStream* s = NULL; UINT32 DstFormat = 0; - const size_t maxSize = 64 * 64 * 4; + const UINT32 maxSize = 64 * 64 * 4; if (!interleaved || !pDstData || !pSrcData) return FALSE; @@ -442,7 +684,7 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat } if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight, pSrcData, - SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE)) + SrcFormat, nSrcStep, nXSrc, nYSrc, palette, 0)) return FALSE; s = Stream_New(pDstData, *pDstSize); @@ -474,33 +716,29 @@ BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) { - BITMAP_INTERLEAVED_CONTEXT* interleaved; - interleaved = (BITMAP_INTERLEAVED_CONTEXT*)calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT)); + BITMAP_INTERLEAVED_CONTEXT* interleaved = NULL; + interleaved = (BITMAP_INTERLEAVED_CONTEXT*)_aligned_recalloc( + NULL, 1, sizeof(BITMAP_INTERLEAVED_CONTEXT), 32); if (interleaved) { interleaved->TempSize = 64 * 64 * 4; - interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize, 16); + interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize * sizeof(BYTE), 16); if (!interleaved->TempBuffer) - { - free(interleaved); - WLog_ERR(TAG, "_aligned_malloc failed!"); - return NULL; - } + goto fail; interleaved->bts = Stream_New(NULL, interleaved->TempSize); if (!interleaved->bts) - { - _aligned_free(interleaved->TempBuffer); - free(interleaved); - WLog_ERR(TAG, "Stream_New failed!"); - return NULL; - } + goto fail; } return interleaved; + +fail: + bitmap_interleaved_context_free(interleaved); + return NULL; } void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) @@ -510,5 +748,5 @@ void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) _aligned_free(interleaved->TempBuffer); Stream_Free(interleaved->bts, TRUE); - free(interleaved); + _aligned_free(interleaved); } diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c index c1d622a..199f1ed 100644 --- a/libfreerdp/codec/ncrush.c +++ b/libfreerdp/codec/ncrush.c @@ -2041,6 +2041,12 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY return 1; } + if (SrcSize < 4) + { + WLog_ERR(TAG, "Input size short: SrcSize %" PRIu32 " < 4", SrcSize); + return -1; + } + const BYTE* SrcEnd = &pSrcData[SrcSize]; const BYTE* SrcPtr = pSrcData + 4; diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 645ca75..5dd2646 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -95,8 +95,8 @@ static BOOL nsc_decode(NSC_CONTEXT* context) for (x = 0; x < context->width; x++) { INT16 y_val = (INT16)*yplane; - INT16 co_val = (INT16)(INT8)(*coplane << shift); - INT16 cg_val = (INT16)(INT8)(*cgplane << shift); + INT16 co_val = (INT16)(INT8)(((INT16)*coplane) << shift); + INT16 cg_val = (INT16)(INT8)(((INT16)*cgplane) << shift); INT16 r_val = y_val + co_val - cg_val; INT16 g_val = y_val + cg_val; INT16 b_val = y_val - co_val - cg_val; @@ -169,7 +169,7 @@ static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outS len |= ((UINT32)(*in++)) << 24U; } - if (outSize < len) + if ((outSize < len) || (left < len)) return FALSE; outSize -= len; @@ -259,6 +259,13 @@ static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) } Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */ + if ((context->ColorLossLevel < 1) || (context->ColorLossLevel > 7)) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "ColorLossLevel=%" PRIu8 " out of range, must be [1,7] inclusive", + context->ColorLossLevel); + return FALSE; + } Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Seek(s, 2); /* Reserved (2 bytes) */ context->Planes = Stream_Pointer(s); diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 0a5ec58..fe27011 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -689,6 +689,13 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT rawHeights[3] = nSrcHeight; } + const size_t diff = srcp - pSrcData; + if (SrcSize < diff) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff); + return FALSE; + } + if (!rle) /* RAW */ { UINT32 base = planeSize * 3; @@ -697,8 +704,12 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT if (alpha) { - if ((SrcSize - (srcp - pSrcData)) < (planeSize + base)) + if ((SrcSize - diff) < (planeSize + base)) + { + WLog_ERR(TAG, "Alpha plane size mismatch %" PRIuz " < %" PRIu32, SrcSize - diff, + (planeSize + base)); return FALSE; + } planes[3] = srcp; /* AlphaPlane */ planes[0] = planes[3] + rawSizes[3]; /* LumaOrRedPlane */ @@ -710,8 +721,11 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT } else { - if ((SrcSize - (srcp - pSrcData)) < base) + if ((SrcSize - diff) < base) + { + WLog_ERR(TAG, "plane size mismatch %" PRIu32 " < %" PRIu32, SrcSize - diff, base); return FALSE; + } planes[0] = srcp; /* LumaOrRedPlane */ planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */ @@ -726,8 +740,8 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT if (alpha) { planes[3] = srcp; - rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - (planes[3] - pSrcData), - rawWidths[3], rawHeights[3]); /* AlphaPlane */ + rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - diff, rawWidths[3], + rawHeights[3]); /* AlphaPlane */ if (rleSizes[3] < 0) return FALSE; @@ -737,22 +751,41 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT else planes[0] = srcp; - rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData), - rawWidths[0], rawHeights[0]); /* RedPlane */ + const size_t diff0 = (planes[0] - pSrcData); + if (SrcSize < diff0) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff0); + return FALSE; + } + rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - diff0, rawWidths[0], + rawHeights[0]); /* RedPlane */ if (rleSizes[0] < 0) return FALSE; planes[1] = planes[0] + rleSizes[0]; - rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData), - rawWidths[1], rawHeights[1]); /* GreenPlane */ + + const size_t diff1 = (planes[1] - pSrcData); + if (SrcSize < diff1) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff1); + return FALSE; + } + rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - diff1, rawWidths[1], + rawHeights[1]); /* GreenPlane */ if (rleSizes[1] < 1) return FALSE; planes[2] = planes[1] + rleSizes[1]; - rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData), - rawWidths[2], rawHeights[2]); /* BluePlane */ + const size_t diff2 = (planes[2] - pSrcData); + if (SrcSize < diff2) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff); + return FALSE; + } + rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - diff2, rawWidths[2], + rawHeights[2]); /* BluePlane */ if (rleSizes[2] < 1) return FALSE; diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 841b508..c632294 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -230,7 +230,10 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t BYTE* pbSegment; size_t cbSegment; - if (!zgfx || !stream || (segmentSize < 2)) + WINPR_ASSERT(zgfx); + WINPR_ASSERT(stream); + + if (segmentSize < 2) return FALSE; cbSegment = segmentSize - 1; @@ -349,8 +352,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) return FALSE; - - if (count > zgfx->cBitsRemaining / 8) + else if (count > zgfx->cBitsRemaining / 8) + return FALSE; + else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd) return FALSE; CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, @@ -381,15 +385,45 @@ 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; + BYTE descriptor = 0; + size_t used = 0; + BYTE* pConcatenated = NULL; wStream* stream = Stream_New((BYTE*)pSrcData, SrcSize); - if (!stream) - return -1; + WINPR_ASSERT(zgfx); + WINPR_ASSERT(stream); + WINPR_ASSERT(ppDstData); + WINPR_ASSERT(pDstSize); + + *ppDstData = NULL; + *pDstSize = 0; if (Stream_GetRemainingLength(stream) < 1) goto fail; @@ -401,16 +435,15 @@ 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) { @@ -418,8 +451,6 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY UINT16 segmentNumber; UINT16 segmentCount; UINT32 uncompressedSize; - BYTE* pConcatenated; - size_t used = 0; if (Stream_GetRemainingLength(stream) < 6) goto fail; @@ -427,17 +458,6 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */ Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */ - if (Stream_GetRemainingLength(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_GetRemainingLength(stream) < sizeof(UINT32)) @@ -448,16 +468,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; - - CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount); - pConcatenated += zgfx->OutputCount; - used += zgfx->OutputCount; } + + if (used != uncompressedSize) + goto fail; + + *ppDstData = pConcatenated; + *pDstSize = uncompressedSize; } else { @@ -466,6 +485,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY status = 1; fail: + if (status < 0) + free(pConcatenated); Stream_Free(stream, FALSE); return status; } diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 0f19914..d8bf58d 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -797,6 +797,7 @@ static INLINE BOOL update_write_4byte_unsigned(wStream* s, UINT32 value) static INLINE BOOL update_read_delta(wStream* s, INT32* value) { BYTE byte; + UINT32 uvalue = 0; if (Stream_GetRemainingLength(s) < 1) { @@ -807,9 +808,9 @@ static INLINE BOOL update_read_delta(wStream* s, INT32* value) Stream_Read_UINT8(s, byte); if (byte & 0x40) - *value = (byte | ~0x3F); + uvalue = (byte | ~0x3F); else - *value = (byte & 0x3F); + uvalue = (byte & 0x3F); if (byte & 0x80) { @@ -820,8 +821,9 @@ static INLINE BOOL update_read_delta(wStream* s, INT32* value) } Stream_Read_UINT8(s, byte); - *value = (*value << 8) | byte; + uvalue = (uvalue << 8) | byte; } + *value = (INT32)uvalue; return TRUE; } diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index b332241..748582b 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.5") +set(RAW_VERSION_STRING "2.11.7") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG)