CVE-2020-11095: Out-of-bounds Read (CWE-125)
value: In FreeRDP before version 2.1.2, an out of bound reads occurs resulting in accessing a memory location that is outside of the boundaries of the static array PRIMARY_DRAWING_ORDER_FIELD_BYTES. This is fixed in version 2.1.2.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 5.4
Published: 2020-06-22T22:15Z
Repository: https://github.com/FreeRDP/FreeRDP
Language: C
Files changed: libfreerdp/core/orders.c, libfreerdp/core/orders.h, libfreerdp/core/update.c
Commit date: 2020-06-22 11:51:38 +0200
Commit message: Fixed invalid access in update_recv_primary_order

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

Diff: diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c
index 87e0959642..90d79f54d6 100644
--- a/libfreerdp/core/orders.c
+++ b/libfreerdp/core/orders.c
@@ -41,40 +41,79 @@
 #include "../cache/brush.h"
 #include "../cache/cache.h"
 
 #define TAG FREERDP_TAG("core.orders")
 
-const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[] = { DSTBLT_ORDER_FIELD_BYTES,
-	                                               PATBLT_ORDER_FIELD_BYTES,
-	                                               SCRBLT_ORDER_FIELD_BYTES,
-	                                               0,
-	                                               0,
-	                                               0,
-	                                               0,
-	                                               DRAW_NINE_GRID_ORDER_FIELD_BYTES,
-	                                               MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES,
-	                                               LINE_TO_ORDER_FIELD_BYTES,
-	                                               OPAQUE_RECT_ORDER_FIELD_BYTES,
-	                                               SAVE_BITMAP_ORDER_FIELD_BYTES,
-	                                               0,
-	                                               MEMBLT_ORDER_FIELD_BYTES,
-	                                               MEM3BLT_ORDER_FIELD_BYTES,
-	                                               MULTI_DSTBLT_ORDER_FIELD_BYTES,
-	                                               MULTI_PATBLT_ORDER_FIELD_BYTES,
-	                                               MULTI_SCRBLT_ORDER_FIELD_BYTES,
-	                                               MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES,
-	                                               FAST_INDEX_ORDER_FIELD_BYTES,
-	                                               POLYGON_SC_ORDER_FIELD_BYTES,
-	                                               POLYGON_CB_ORDER_FIELD_BYTES,
-	                                               POLYLINE_ORDER_FIELD_BYTES,
-	                                               0,
-	                                               FAST_GLYPH_ORDER_FIELD_BYTES,
-	                                               ELLIPSE_SC_ORDER_FIELD_BYTES,
-	                                               ELLIPSE_CB_ORDER_FIELD_BYTES,
-	                                               GLYPH_INDEX_ORDER_FIELD_BYTES };
-
-#define PRIMARY_DRAWING_ORDER_COUNT (ARRAYSIZE(PRIMARY_DRAWING_ORDER_FIELD_BYTES))
+BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid)
+{
+	if (pValid)
+		*pValid = TRUE;
+	switch (orderType)
+	{
+		case 0:
+			return DSTBLT_ORDER_FIELD_BYTES;
+		case 1:
+			return PATBLT_ORDER_FIELD_BYTES;
+		case 2:
+			return SCRBLT_ORDER_FIELD_BYTES;
+		case 3:
+			return 0;
+		case 4:
+			return 0;
+		case 5:
+			return 0;
+		case 6:
+			return 0;
+		case 7:
+			return DRAW_NINE_GRID_ORDER_FIELD_BYTES;
+		case 8:
+			return MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES;
+		case 9:
+			return LINE_TO_ORDER_FIELD_BYTES;
+		case 10:
+			return OPAQUE_RECT_ORDER_FIELD_BYTES;
+		case 11:
+			return SAVE_BITMAP_ORDER_FIELD_BYTES;
+		case 12:
+			return 0;
+		case 13:
+			return MEMBLT_ORDER_FIELD_BYTES;
+		case 14:
+			return MEM3BLT_ORDER_FIELD_BYTES;
+		case 15:
+			return MULTI_DSTBLT_ORDER_FIELD_BYTES;
+		case 16:
+			return MULTI_PATBLT_ORDER_FIELD_BYTES;
+		case 17:
+			return MULTI_SCRBLT_ORDER_FIELD_BYTES;
+		case 18:
+			return MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES;
+		case 19:
+			return FAST_INDEX_ORDER_FIELD_BYTES;
+		case 20:
+			return POLYGON_SC_ORDER_FIELD_BYTES;
+		case 21:
+			return POLYGON_CB_ORDER_FIELD_BYTES;
+		case 22:
+			return POLYLINE_ORDER_FIELD_BYTES;
+		case 23:
+			return 0;
+		case 24:
+			return FAST_GLYPH_ORDER_FIELD_BYTES;
+		case 25:
+			return ELLIPSE_SC_ORDER_FIELD_BYTES;
+		case 26:
+			return ELLIPSE_CB_ORDER_FIELD_BYTES;
+		case 27:
+			return GLYPH_INDEX_ORDER_FIELD_BYTES;
+		default:
+			if (pValid)
+				*pValid = FALSE;
+			WLog_WARN(TAG, "Invalid orderType 0x%08X received", orderType);
+			return 0;
+	}
+}
 
 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 };
@@ -3238,10 +3277,11 @@ static BOOL read_primary_order(wLog* log, const char* orderName, wStream* s,
 	return TRUE;
 }
 
 static BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags)
 {
+	BYTE field;
 	BOOL rc = FALSE;
 	rdpContext* context = update->context;
 	rdpPrimaryUpdate* primary = update->primary;
 	ORDER_INFO* orderInfo = &(primary->order_info);
 	rdpSettings* settings = context->settings;
@@ -3261,12 +3301,15 @@ static BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags)
 	orderName = primary_order_string(orderInfo->orderType);
 
 	if (!check_primary_order_supported(update->log, settings, orderInfo->orderType, orderName))
 		return FALSE;
 
-	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags,
-	                             PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]))
+	field = get_primary_drawing_order_field_bytes(orderInfo->orderType, &rc);
+	if (!rc)
+		return FALSE;
+
+	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags, field))
 	{
 		WLog_Print(update->log, WLOG_ERROR, "update_read_field_flags() failed");
 		return FALSE;
 	}
 
diff --git a/libfreerdp/core/orders.h b/libfreerdp/core/orders.h
index 76e3d3fe34..d429dff704 100644
--- a/libfreerdp/core/orders.h
+++ b/libfreerdp/core/orders.h
@@ -187,11 +187,11 @@
 #define ORDER_TYPE_COMPDESK_FIRST 0x0C
 #define ORDER_TYPE_FRAME_MARKER 0x0D
 
 #define CG_GLYPH_UNICODE_PRESENT 0x0010
 
-FREERDP_LOCAL extern const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[];
+FREERDP_LOCAL BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid);
 
 FREERDP_LOCAL BOOL update_recv_order(rdpUpdate* update, wStream* s);
 
 FREERDP_LOCAL BOOL update_write_field_flags(wStream* s, UINT32 fieldFlags, BYTE flags,
                                             BYTE fieldBytes);
diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c
index aac58819fd..ebb82fc2df 100644
--- a/libfreerdp/core/update.c
+++ b/libfreerdp/core/update.c
@@ -1085,11 +1085,11 @@ static int update_prepare_order_info(rdpContext* context, ORDER_INFO* orderInfo,
 	orderInfo->fieldFlags = 0;
 	orderInfo->orderType = orderType;
 	orderInfo->controlFlags = ORDER_STANDARD;
 	orderInfo->controlFlags |= ORDER_TYPE_CHANGE;
 	length += 1;
-	length += PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType];
+	length += get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL);
 	length += update_prepare_bounds(context, orderInfo);
 	return length;
 }
 
 static int update_write_order_info(rdpContext* context, wStream* s, ORDER_INFO* orderInfo,
@@ -1103,11 +1103,11 @@ static int update_write_order_info(rdpContext* context, wStream* s, ORDER_INFO*
 
 	if (orderInfo->controlFlags & ORDER_TYPE_CHANGE)
 		Stream_Write_UINT8(s, orderInfo->orderType); /* orderType (1 byte) */
 
 	update_write_field_flags(s, orderInfo->fieldFlags, orderInfo->controlFlags,
-	                         PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]);
+	                         get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL));
 	update_write_bounds(s, orderInfo);
 	Stream_SetPosition(s, position);
 	return 0;
 }
 

Vulnerable code: const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[] = { DSTBLT_ORDER_FIELD_BYTES,
	                                               PATBLT_ORDER_FIELD_BYTES,
	                                               SCRBLT_ORDER_FIELD_BYTES,
	                                               0,
	                                               0,
	                                               0,
	                                               0,
	                                               DRAW_NINE_GRID_ORDER_FIELD_BYTES,
	                                               MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES,
	                                               LINE_TO_ORDER_FIELD_BYTES,
	                                               OPAQUE_RECT_ORDER_FIELD_BYTES,
	                                               SAVE_BITMAP_ORDER_FIELD_BYTES,
	                                               0,
	                                               MEMBLT_ORDER_FIELD_BYTES,
	                                               MEM3BLT_ORDER_FIELD_BYTES,
	                                               MULTI_DSTBLT_ORDER_FIELD_BYTES,
	                                               MULTI_PATBLT_ORDER_FIELD_BYTES,
	                                               MULTI_SCRBLT_ORDER_FIELD_BYTES,
	                                               MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES,
	                                               FAST_INDEX_ORDER_FIELD_BYTES,
	                                               POLYGON_SC_ORDER_FIELD_BYTES,
	                                               POLYGON_CB_ORDER_FIELD_BYTES,
	                                               POLYLINE_ORDER_FIELD_BYTES,
	                                               0,
	                                               FAST_GLYPH_ORDER_FIELD_BYTES,
	                                               ELLIPSE_SC_ORDER_FIELD_BYTES,
	                                               ELLIPSE_CB_ORDER_FIELD_BYTES,
	                                               GLYPH_INDEX_ORDER_FIELD_BYTES };

#define PRIMARY_DRAWING_ORDER_COUNT (ARRAYSIZE(PRIMARY_DRAWING_ORDER_FIELD_BYTES))
	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags,
	                             PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]))
FREERDP_LOCAL extern const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[];
	length += PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType];
	                         PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]);
Fixed code: BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid)
{
	if (pValid)
		*pValid = TRUE;
	switch (orderType)
	{
		case 0:
			return DSTBLT_ORDER_FIELD_BYTES;
		case 1:
			return PATBLT_ORDER_FIELD_BYTES;
		case 2:
			return SCRBLT_ORDER_FIELD_BYTES;
		case 3:
			return 0;
		case 4:
			return 0;
		case 5:
			return 0;
		case 6:
			return 0;
		case 7:
			return DRAW_NINE_GRID_ORDER_FIELD_BYTES;
		case 8:
			return MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES;
		case 9:
			return LINE_TO_ORDER_FIELD_BYTES;
		case 10:
			return OPAQUE_RECT_ORDER_FIELD_BYTES;
		case 11:
			return SAVE_BITMAP_ORDER_FIELD_BYTES;
		case 12:
			return 0;
		case 13:
			return MEMBLT_ORDER_FIELD_BYTES;
		case 14:
			return MEM3BLT_ORDER_FIELD_BYTES;
		case 15:
			return MULTI_DSTBLT_ORDER_FIELD_BYTES;
		case 16:
			return MULTI_PATBLT_ORDER_FIELD_BYTES;
		case 17:
			return MULTI_SCRBLT_ORDER_FIELD_BYTES;
		case 18:
			return MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES;
		case 19:
			return FAST_INDEX_ORDER_FIELD_BYTES;
		case 20:
			return POLYGON_SC_ORDER_FIELD_BYTES;
		case 21:
			return POLYGON_CB_ORDER_FIELD_BYTES;
		case 22:
			return POLYLINE_ORDER_FIELD_BYTES;
		case 23:
			return 0;
		case 24:
			return FAST_GLYPH_ORDER_FIELD_BYTES;
		case 25:
			return ELLIPSE_SC_ORDER_FIELD_BYTES;
		case 26:
			return ELLIPSE_CB_ORDER_FIELD_BYTES;
		case 27:
			return GLYPH_INDEX_ORDER_FIELD_BYTES;
		default:
			if (pValid)
				*pValid = FALSE;
			WLog_WARN(TAG, "Invalid orderType 0x%08X received", orderType);
			return 0;
	}
}
	BYTE field;
	field = get_primary_drawing_order_field_bytes(orderInfo->orderType, &rc);
	if (!rc)
		return FALSE;

	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags, field))
FREERDP_LOCAL BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid);
	length += get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL);
	                         get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL));