CVE-2020-11096 (C, published 2020-06-22T22:15Z)
Description: value: In FreeRDP before version 2.1.2, there is a global OOB read in update_read_cache_bitmap_v3_order. As a workaround, one can disable bitmap cache with -bitmap-cache (default). This is fixed in version 2.1.2.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/FreeRDP/FreeRDP
Files changed:
libfreerdp/core/orders.c
Commit message: Fixed OOB read in update_read_cache_bitmap_v3_order

CVE-2020-11096 thanks @antonio-morales for finding this.


Vulnerable code:
static const BYTE CBR2_BPP[] = { 0, 0, 0, 8, 16, 24, 32 };

static const BYTE BPP_CBR2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
	                             0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };

static const BYTE CBR23_BPP[] = { 0, 0, 0, 8, 16, 24, 32 };

static const BYTE BPP_CBR23[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
	                              0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };

static const BYTE BMF_BPP[] = { 0, 1, 0, 8, 16, 24, 32, 0 };
static const BYTE BPP_BMF[] = { 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
	                            0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };
		brush->bpp = BMF_BPP[brush->style & 0x07];

		brush->bpp = BMF_BPP[brush->style & 0x07];

	cache_bitmap_v2->bitmapBpp = CBR2_BPP[bitsPerPixelId];
	bitsPerPixelId = BPP_CBR2[cache_bitmap_v2->bitmapBpp];
	cache_bitmap_v3->bpp = CBR23_BPP[bitsPerPixelId];
	bitsPerPixelId = BPP_CBR23[cache_bitmap_v3->bpp];
	if (iBitmapFormat >= ARRAYSIZE(BMF_BPP))
	cache_brush->bpp = BMF_BPP[iBitmapFormat];
	iBitmapFormat = BPP_BMF[cache_brush->bpp];

Fixed code:
static BYTE get_cbr2_bpp(UINT32 bpp, BOOL* pValid)
{
	if (pValid)
		*pValid = TRUE;
	switch (bpp)
	{
		case 3:
			return 8;
		case 4:
			return 16;
		case 5:
			return 24;
		case 6:
			return 32;
		default:
			WLog_WARN(TAG, "Invalid bpp %" PRIu32, bpp);
			if (pValid)
				*pValid = FALSE;
			return 0;
	}
}
static BYTE get_bmf_bpp(UINT32 bmf, BOOL* pValid)
{
	if (pValid)
		*pValid = TRUE;
	switch (bmf)
	{
		case 1:
			return 1;
		case 3:
			return 8;
		case 4:
			return 16;
		case 5:
			return 24;
		case 6:
			return 32;
		default:
			WLog_WARN(TAG, "Invalid bmf %" PRIu32, bmf);
			if (pValid)
				*pValid = FALSE;
			return 0;
	}
}
static BYTE get_bpp_bmf(UINT32 bpp, BOOL* pValid)
{
	if (pValid)
		*pValid = TRUE;
	switch (bpp)
	{
		case 1:
			return 1;
		case 8:
			return 3;
		case 16:
			return 4;
		case 24:
			return 5;
		case 32:
			return 6;
		default:
			WLog_WARN(TAG, "Invalid color depth %" PRIu32, bpp);
			if (pValid)
				*pValid = FALSE;
			return 0;
	}
}
		BOOL rc;
		brush->bpp = get_bmf_bpp(brush->style, &rc);
		if (!rc)
			return FALSE;
		BOOL rc;
		brush->bpp = get_bmf_bpp(brush->style, &rc);
		if (!rc)
			return FALSE;
	BOOL rc;
	cache_bitmap_v2->bitmapBpp = get_cbr2_bpp(bitsPerPixelId, &rc);
	if (!rc)
		goto fail;
	BOOL rc;
	bitsPerPixelId = get_bpp_bmf(cache_bitmap_v2->bitmapBpp, &rc);
	if (!rc)
		return FALSE;
	BOOL rc;
	cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc);
	if (!rc)
		goto fail;
	BOOL rc;
	bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc);
	if (!rc)
		return FALSE;
	BOOL rc;
	cache_brush->bpp = get_bmf_bpp(iBitmapFormat, &rc);
	if (!rc)
	BOOL rc;
	iBitmapFormat = get_bpp_bmf(cache_brush->bpp, &rc);
	if (!rc)
		return FALSE;