From 64649715f9aa691c8435d05cc17ccf468cbb3afa Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 16 Jun 2026 10:53:16 +0200 Subject: [PATCH] [core,orders] add codecID checks Abort early if an unsupported/deactivated codecID value is found for a CACHE_BITMAP_V3_ORDER. --- libfreerdp/core/orders.c | 94 +++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 6c5f98ab6..c725aa790 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -2446,7 +2446,7 @@ static CACHE_BITMAP_V2_ORDER* update_read_cache_bitmap_v2_order(rdpUpdate* updat if (!cache_bitmap_v2) goto fail; - cache_bitmap_v2->cacheId = flags & 0x0003; + cache_bitmap_v2->cacheId = flags & 0x0007; cache_bitmap_v2->flags = (flags & 0xFF80) >> 7; bitsPerPixelId = (flags & 0x0078) >> 3; cache_bitmap_v2->bitmapBpp = get_cbr2_bpp(bitsPerPixelId, &rc); @@ -2620,27 +2620,43 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat UINT16 flags) { BOOL rc = 0; - BYTE bitsPerPixelId = 0; - BITMAP_DATA_EX* bitmapData = NULL; UINT32 new_len = 0; BYTE* new_data = NULL; - CACHE_BITMAP_V3_ORDER* cache_bitmap_v3 = NULL; rdp_update_internal* up = update_cast(update); if (!update || !s) return NULL; - cache_bitmap_v3 = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER)); + WINPR_ASSERT(update->context); + + const rdpSettings* settings = update->context->settings; + WINPR_ASSERT(settings); + + if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheV3Enabled)) + { + WLog_Print(up->log, WLOG_ERROR, "BitmapCacheV3 not enabled for this connection, aborting"); + return NULL; + } + + CACHE_BITMAP_V3_ORDER* cache_bitmap_v3 = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER)); if (!cache_bitmap_v3) goto fail; - cache_bitmap_v3->cacheId = flags & 0x00000003; - cache_bitmap_v3->flags = (flags & 0x0000FF80) >> 7; - bitsPerPixelId = (flags & 0x00000078) >> 3; - cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc); - if (!rc) + cache_bitmap_v3->cacheId = flags & 0x00000007; + const UINT32 NumCellCaches = + freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells); + if (cache_bitmap_v3->cacheId >= NumCellCaches) + { + WLog_Print(up->log, WLOG_ERROR, + "BitmapCacheV3::cacheId %" PRIu32 " > NumCellCaches %" PRIu32, + cache_bitmap_v3->cacheId, NumCellCaches); goto fail; + } + cache_bitmap_v3->flags = (flags >> 7) & 0x000001FF; + + const BYTE bitsPerPixelId = (flags >> 3) & 0x000000F; + cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc); if (!Stream_CheckAndLogRequiredLength(TAG, s, 21)) goto fail; @@ -2648,7 +2664,20 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat Stream_Read_UINT16(s, cache_bitmap_v3->cacheIndex); /* cacheIndex (2 bytes) */ Stream_Read_UINT32(s, cache_bitmap_v3->key1); /* key1 (4 bytes) */ Stream_Read_UINT32(s, cache_bitmap_v3->key2); /* key2 (4 bytes) */ - bitmapData = &cache_bitmap_v3->bitmapData; + + if ((cache_bitmap_v3->flags & CBR3_DO_NOT_CACHE) != 0) + { + rdpCache* cache = update->context->cache; + WINPR_ASSERT(cache); + + if (cache_bitmap_v3->cacheId >= cache->bitmap->maxCells) + goto fail; + + BITMAP_V2_CELL* cell = &cache->bitmap->cells[cache_bitmap_v3->cacheId]; + cache_bitmap_v3->cacheIndex = cell->number; + } + + BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData; Stream_Read_UINT8(s, bitmapData->bpp); if ((bitmapData->bpp < 1) || (bitmapData->bpp > 32)) @@ -2657,6 +2686,13 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat goto fail; } + /* [MS-RDPEGDI] 2.2.2.2.1.2.8 Cache Bitmap - Revision 3 (CACHE_BITMAP_REV3_ORDER) + * tells this should not be 0, but it is for some windows versions. + * fall back to setting color depth from bitmapData + */ + if (!rc) + cache_bitmap_v3->bpp = bitmapData->bpp; + Stream_Seek_UINT8(s); /* reserved1 (1 byte) */ Stream_Seek_UINT8(s); /* reserved2 (1 byte) */ Stream_Read_UINT8(s, bitmapData->codecID); /* codecID (1 byte) */ @@ -2664,6 +2700,40 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat Stream_Read_UINT16(s, bitmapData->height); /* height (2 bytes) */ Stream_Read_UINT32(s, new_len); /* length (4 bytes) */ + switch (bitmapData->codecID) + { + case RDP_CODEC_ID_IMAGE_REMOTEFX: + if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxImageCodec)) + { + WLog_Print(up->log, WLOG_ERROR, + "codecID RDP_CODEC_ID_IMAGE_REMOTEFX not enabled for this " + "connection, aborting"); + goto fail; + } + break; + case RDP_CODEC_ID_REMOTEFX: + if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec)) + { + WLog_ERR(TAG, + "codecID RDP_CODEC_ID_REMOTEFX not enabled for this connection, aborting"); + goto fail; + } + break; + case RDP_CODEC_ID_NSCODEC: + if (!freerdp_settings_get_bool(settings, FreeRDP_NSCodec)) + { + WLog_ERR(TAG, + "codecID RDP_CODEC_ID_NSCODEC not enabled for this connection, aborting"); + goto fail; + } + break; + case RDP_CODEC_ID_NONE: + break; + default: + WLog_ERR(TAG, "Unsupported codecID 0x%08" PRIx32, bitmapData->codecID); + goto fail; + } + if ((new_len == 0) || (!Stream_CheckAndLogRequiredLength(TAG, s, new_len))) goto fail; @@ -2706,7 +2776,7 @@ BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc); if (!rc) return FALSE; - *flags = (cache_bitmap_v3->cacheId & 0x00000003) | + *flags = (cache_bitmap_v3->cacheId & 0x00000007) | ((cache_bitmap_v3->flags << 7) & 0x0000FF80) | ((bitsPerPixelId << 3) & 0x00000078); Stream_Write_UINT16(s, get_checked_uint16(cache_bitmap_v3->cacheIndex)); /* cacheIndex (2 bytes) */