Commit message: Fixed CVE-2018-8787

Thanks to Eyal Itkin from Check Point Software Technologies.
CVE: CVE-2018-8787
CWE: CWE-190
Vulnerability description: FreeRDP prior to version 2.0.0-rc4 contains an Integer Overflow that leads to a Heap-Based Buffer Overflow in function gdi_Bitmap_Decompress() and results in a memory corruption and probably even a remote code execution.

Project: FreeRDP

static void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
{
	gdiBitmap* gdi_bitmap = (gdiBitmap*) bitmap;

	if (gdi_bitmap)
	{
		if (gdi_bitmap->hdc)
			gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT) gdi_bitmap->org_bitmap);

		gdi_DeleteObject((HGDIOBJECT) gdi_bitmap->bitmap);
		gdi_DeleteDC(gdi_bitmap->hdc);
		_aligned_free(bitmap->data);
	}

	free(bitmap);
}

Project: FreeRDP

static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
{
	gdiBitmap* gdi_bitmap;
	rdpGdi* gdi = context->gdi;
	gdi_bitmap = (gdiBitmap*) bitmap;
	gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc);

	if (!gdi_bitmap->hdc)
		return FALSE;

	if (!bitmap->data)
		gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(
		                         gdi->hdc, bitmap->width,
		                         bitmap->height);
	else
	{
		UINT32 format = bitmap->format;
		gdi_bitmap->bitmap = gdi_create_bitmap(gdi, bitmap->width,
		                                       bitmap->height,
		                                       format, bitmap->data);
	}

	if (!gdi_bitmap->bitmap)
	{
		gdi_DeleteDC(gdi_bitmap->hdc);
		return FALSE;
	}

	gdi_bitmap->hdc->format = gdi_bitmap->bitmap->format;
	gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT) gdi_bitmap->bitmap);
	gdi_bitmap->org_bitmap = NULL;
	return TRUE;
}

Project: FreeRDP

static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
{
	gdiBitmap* gdi_bitmap = (gdiBitmap*) bitmap;
	UINT32 width = bitmap->right - bitmap->left + 1;
	UINT32 height = bitmap->bottom - bitmap->top + 1;
	return gdi_BitBlt(context->gdi->primary->hdc,
	                  bitmap->left, bitmap->top,
	                  width, height, gdi_bitmap->hdc,
	                  0, 0, GDI_SRCCOPY, &context->gdi->palette);
}

Project: FreeRDP

static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap,
                                  BOOL primary)
{
	rdpGdi* gdi;

	if (!context)
		return FALSE;

	gdi = context->gdi;

	if (!gdi)
		return FALSE;

	if (primary)
		gdi->drawing = gdi->primary;
	else
		gdi->drawing = (gdiBitmap*) bitmap;

	return TRUE;
}

Project: FreeRDP

static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y,
                                INT32 width, INT32 height, UINT32 bgcolor,
                                UINT32 fgcolor, BOOL fOpRedundant)
{
	rdpGdi* gdi;

	if (!context || !context->gdi)
		return FALSE;

	gdi = context->gdi;

	if (!gdi->drawing || !gdi->drawing->hdc)
		return FALSE;

	if (!fOpRedundant)
	{
		if (!gdi_decode_color(gdi, bgcolor, &bgcolor, NULL))
			return FALSE;

		if (!gdi_decode_color(gdi, fgcolor, &fgcolor, NULL))
			return FALSE;

		gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
		gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
		gdi_SetBkColor(gdi->drawing->hdc, fgcolor);

		if (1)
		{
			GDI_RECT rect = { 0 };
			HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);

			if (!brush)
				return FALSE;

			if (x > 0)
				rect.left = x;

			if (y > 0)
				rect.top = y;

			rect.right = x + width - 1;
			rect.bottom = y + height - 1;

			if ((x + width > rect.left) && (y + height > rect.top))
				gdi_FillRect(gdi->drawing->hdc, &rect, brush);

			gdi_DeleteObject((HGDIOBJECT)brush);
		}

		return gdi_SetNullClipRgn(gdi->drawing->hdc);
	}

	return TRUE;
}

Project: FreeRDP

static BOOL gdi_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x,
                           INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
{
	gdiGlyph* gdi_glyph;
	rdpGdi* gdi;
	HGDI_BRUSH brush;
	BOOL rc = FALSE;

	if (!context || !glyph)
		return FALSE;

	gdi = context->gdi;
	gdi_glyph = (gdiGlyph*) glyph;

	if (!fOpRedundant && 0)
	{
		GDI_RECT rect = { 0 };

		if (x > 0)
			rect.left = x;

		if (y > 0)
			rect.top = y;

		if (x + w > 0)
			rect.right = x + w - 1;

		if (y + h > 0)
			rect.bottom = y + h - 1;

		if ((rect.left < rect.right) && (rect.top < rect.bottom))
		{
			brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);

			if (!brush)
				return FALSE;

			gdi_FillRect(gdi->drawing->hdc, &rect, brush);
			gdi_DeleteObject((HGDIOBJECT)brush);
		}
	}

	brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);

	if (!brush)
		return FALSE;

	gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)brush);
	rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h, gdi_glyph->hdc, sx, sy,
	                GDI_GLYPH_ORDER, &context->gdi->palette);
	gdi_DeleteObject((HGDIOBJECT)brush);
	return rc;
}

Project: FreeRDP

static BOOL gdi_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y,
                              INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor)
{
	rdpGdi* gdi;

	if (!context || !context->gdi)
		return FALSE;

	gdi = context->gdi;

	if (!gdi->drawing || !gdi->drawing->hdc)
		return FALSE;

	gdi_SetNullClipRgn(gdi->drawing->hdc);
	return TRUE;
}

Project: FreeRDP

static void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
{
	gdiGlyph* gdi_glyph;
	gdi_glyph = (gdiGlyph*) glyph;

	if (gdi_glyph)
	{
		gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT) gdi_glyph->org_bitmap);
		gdi_DeleteObject((HGDIOBJECT) gdi_glyph->bitmap);
		gdi_DeleteDC(gdi_glyph->hdc);
		free(glyph->aj);
		free(glyph);
	}
}

Project: FreeRDP

static BOOL gdi_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
{
	BYTE* data;
	gdiGlyph* gdi_glyph;

	if (!context || !glyph)
		return FALSE;

	gdi_glyph = (gdiGlyph*) glyph;
	gdi_glyph->hdc = gdi_GetDC();

	if (!gdi_glyph->hdc)
		return FALSE;

	gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
	data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);

	if (!data)
	{
		gdi_DeleteDC(gdi_glyph->hdc);
		return FALSE;
	}

	gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO,
	                                     data);

	if (!gdi_glyph->bitmap)
	{
		gdi_DeleteDC(gdi_glyph->hdc);
		_aligned_free(data);
		return FALSE;
	}

	gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT) gdi_glyph->bitmap);
	gdi_glyph->org_bitmap = NULL;
	return TRUE;
}

Project: FreeRDP

static BOOL gdi_Glyph_SetBounds(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height)
{
	rdpGdi* gdi;

	if (!context || !context->gdi)
		return FALSE;

	gdi = context->gdi;

	if (!gdi->drawing || !gdi->drawing->hdc)
		return FALSE;

	return gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
}

Project: FreeRDP

HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight,
                              UINT32 SrcFormat, BYTE* data)
{
	UINT32 nSrcStep;
	UINT32 nDstStep;
	BYTE* pSrcData;
	BYTE* pDstData;
	HGDI_BITMAP bitmap;

	if (!gdi)
		return NULL;

	nDstStep = nWidth * GetBytesPerPixel(gdi->dstFormat);
	pDstData = _aligned_malloc(nHeight * nDstStep, 16);

	if (!pDstData)
		return NULL;

	pSrcData = data;
	nSrcStep = nWidth * GetBytesPerPixel(SrcFormat);

	if (!freerdp_image_copy(pDstData, gdi->dstFormat, nDstStep, 0, 0,
	                        nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, 0, 0,
	                        &gdi->palette, FREERDP_FLIP_NONE))
	{
		_aligned_free(pDstData);
		return NULL;
	}

	bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
	return bitmap;
}