[PATCH 3/3] gdi32: Add bounds checking for DIBs embedded in metafiles.
Vincent Povirk
vincent at codeweavers.com
Wed May 16 11:29:23 CDT 2018
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
---
dlls/gdi32/dib.c | 9 ++++
dlls/gdi32/enhmetafile.c | 136 +++++++++++++++++++++++++++++++++++++++++------
dlls/gdi32/gdi_private.h | 1 +
3 files changed, 131 insertions(+), 15 deletions(-)
diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c
index c7dcdb122c2..8d7111dbc2a 100644
--- a/dlls/gdi32/dib.c
+++ b/dlls/gdi32/dib.c
@@ -305,6 +305,15 @@ BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
return TRUE;
}
+DWORD bitmap_bits_size( const BITMAPINFO * info )
+{
+ BITMAPINFOHEADER bmih;
+
+ if (!bitmapinfoheader_from_user_bitmapinfo( &bmih, &info->bmiHeader )) return 0;
+
+ return bmih.biSizeImage;
+}
+
static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
{
const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
diff --git a/dlls/gdi32/enhmetafile.c b/dlls/gdi32/enhmetafile.c
index c66e382c1d6..d72ba3e8a47 100644
--- a/dlls/gdi32/enhmetafile.c
+++ b/dlls/gdi32/enhmetafile.c
@@ -743,6 +743,22 @@ static BOOL emr_produces_output(int type)
}
}
+static BOOL emr_validate_bmi(const BITMAPINFO *bmi, DWORD bmi_size, WORD coloruse)
+{
+ if (bmi_size < 4 ||
+ bmi_size < bmi->bmiHeader.biSize)
+ return FALSE;
+
+ if (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) &&
+ bmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
+ return FALSE;
+
+ if (bmi_size < bitmap_info_size( bmi, coloruse ))
+ return FALSE;
+
+ return TRUE;
+}
+
static BOOL emr_validate_size(const ENHMETARECORD *emr)
{
switch(emr->iType) {
@@ -831,7 +847,9 @@ static BOOL emr_validate_size(const ENHMETARECORD *emr)
pPen->elp.elpNumEntries * 4 > pPen->elp.elpNumEntries * 4 + FIELD_OFFSET(EMREXTCREATEPEN, elp.elpStyleEntry) ||
emr->nSize < pPen->elp.elpNumEntries * 4 + FIELD_OFFSET(EMREXTCREATEPEN, elp.elpStyleEntry))
return FALSE;
- /* FIXME: validate DIB size */
+ if (!emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pPen->offBmi), pPen->cbBmi, DIB_RGB_COLORS) ||
+ pPen->cbBits < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pPen->offBmi)))
+ return FALSE;
break;
}
case EMR_CREATEBRUSHINDIRECT:
@@ -894,9 +912,19 @@ static BOOL emr_validate_size(const ENHMETARECORD *emr)
break;
}
case EMR_STRETCHDIBITS:
- if (emr->nSize < sizeof(EMRSTRETCHDIBITS)) return FALSE;
- /* FIXME: validate DIB size */
+ {
+ const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)emr;
+ if (emr->nSize < sizeof(EMRSTRETCHDIBITS) ||
+ pStretchDIBits->offBmiSrc > pStretchDIBits->offBmiSrc + pStretchDIBits->cbBmiSrc ||
+ emr->nSize < pStretchDIBits->offBmiSrc + pStretchDIBits->cbBmiSrc ||
+ pStretchDIBits->offBitsSrc > pStretchDIBits->offBitsSrc + pStretchDIBits->cbBitsSrc ||
+ emr->nSize < pStretchDIBits->offBitsSrc + pStretchDIBits->cbBitsSrc ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pStretchDIBits->offBmiSrc),
+ pStretchDIBits->cbBmiSrc, pStretchDIBits->iUsageSrc) ||
+ pStretchDIBits->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pStretchDIBits->offBmiSrc)))
+ return FALSE;
break;
+ }
case EMR_EXTTEXTOUTA:
{
const EMREXTTEXTOUTA *pExtTextOutA = (const EMREXTTEXTOUTA *)emr;
@@ -1154,29 +1182,99 @@ static BOOL emr_validate_size(const ENHMETARECORD *emr)
if (emr->nSize < sizeof(EMRRESIZEPALETTE)) return FALSE;
break;
case EMR_CREATEDIBPATTERNBRUSHPT:
- if (emr->nSize < sizeof(EMRCREATEDIBPATTERNBRUSHPT)) return FALSE;
- /* FIXME: validate dib size */
+ {
+ const EMRCREATEDIBPATTERNBRUSHPT* pCreate = (const EMRCREATEDIBPATTERNBRUSHPT*)emr;
+ if (emr->nSize < sizeof(EMRCREATEDIBPATTERNBRUSHPT) ||
+ pCreate->offBmi > pCreate->offBmi + pCreate->cbBmi ||
+ emr->nSize < pCreate->offBmi + pCreate->cbBmi ||
+ pCreate->offBits > pCreate->offBits + pCreate->cbBits ||
+ emr->nSize < pCreate->offBits + pCreate->cbBits ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pCreate->offBmi),
+ pCreate->cbBmi, pCreate->iUsage) ||
+ pCreate->cbBits < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pCreate->offBmi)))
+ return FALSE;
break;
+ }
case EMR_CREATEMONOBRUSH:
- if (emr->nSize < sizeof(EMRCREATEMONOBRUSH)) return FALSE;
- /* FIXME: validate dib size */
+ {
+ const EMRCREATEMONOBRUSH* pCreate = (const EMRCREATEMONOBRUSH*)emr;
+ if (emr->nSize < sizeof(EMRCREATEMONOBRUSH) ||
+ pCreate->offBmi > pCreate->offBmi + pCreate->cbBmi ||
+ emr->nSize < pCreate->offBmi + pCreate->cbBmi ||
+ pCreate->offBits > pCreate->offBits + pCreate->cbBits ||
+ emr->nSize < pCreate->offBits + pCreate->cbBits ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pCreate->offBmi),
+ pCreate->cbBmi, pCreate->iUsage) ||
+ pCreate->cbBits < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pCreate->offBmi)))
+ return FALSE;
break;
+ }
case EMR_BITBLT:
+ {
+ const EMRBITBLT* pBlt = (const EMRBITBLT*)emr;
if (emr->nSize < sizeof(EMRBITBLT)) return FALSE;
- /* FIXME: validate dib size */
+ if (pBlt->offBmiSrc &&
+ (pBlt->offBmiSrc > pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ emr->nSize < pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ pBlt->offBitsSrc > pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ emr->nSize < pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc),
+ pBlt->cbBmiSrc, pBlt->iUsageSrc) ||
+ pBlt->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc))))
+ return FALSE;
break;
+ }
case EMR_STRETCHBLT:
+ {
+ const EMRSTRETCHBLT* pBlt = (const EMRSTRETCHBLT*)emr;
if (emr->nSize < sizeof(EMRSTRETCHBLT)) return FALSE;
- /* FIXME: validate dib size */
+ if (pBlt->offBmiSrc &&
+ (pBlt->offBmiSrc > pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ emr->nSize < pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ pBlt->offBitsSrc > pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ emr->nSize < pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc),
+ pBlt->cbBmiSrc, pBlt->iUsageSrc) ||
+ pBlt->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc))))
+ return FALSE;
break;
+ }
case EMR_ALPHABLEND:
+ {
+ const EMRALPHABLEND* pBlt = (const EMRALPHABLEND*)emr;
if (emr->nSize < sizeof(EMRALPHABLEND)) return FALSE;
- /* FIXME: validate dib size */
+ if (pBlt->offBmiSrc &&
+ (pBlt->offBmiSrc > pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ emr->nSize < pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ pBlt->offBitsSrc > pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ emr->nSize < pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc),
+ pBlt->cbBmiSrc, pBlt->iUsageSrc) ||
+ pBlt->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc))))
+ return FALSE;
break;
+ }
case EMR_MASKBLT:
- if (emr->nSize < sizeof(EMRMASKBLT)) return FALSE;
- /* FIXME: validate dib size */
+ {
+ const EMRMASKBLT* pBlt = (const EMRMASKBLT*)emr;
+ if (emr->nSize < sizeof(EMRMASKBLT) ||
+ pBlt->offBmiSrc > pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ emr->nSize < pBlt->offBmiSrc + pBlt->cbBmiSrc ||
+ pBlt->offBitsSrc > pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ emr->nSize < pBlt->offBitsSrc + pBlt->cbBitsSrc ||
+ pBlt->offBmiMask > pBlt->offBmiMask + pBlt->cbBmiMask ||
+ emr->nSize < pBlt->offBmiMask + pBlt->cbBmiMask ||
+ pBlt->offBitsMask > pBlt->offBitsMask + pBlt->cbBitsMask ||
+ emr->nSize < pBlt->offBitsMask + pBlt->cbBitsMask ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc),
+ pBlt->cbBmiSrc, pBlt->iUsageSrc) ||
+ pBlt->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiSrc)) ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiMask),
+ pBlt->cbBmiMask, pBlt->iUsageMask) ||
+ pBlt->cbBitsMask < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pBlt->offBmiMask)))
+ return FALSE;
break;
+ }
case EMR_PLGBLT:
{
const EMRPLGBLT *pPlgBlt = (const EMRPLGBLT *)emr;
@@ -1188,9 +1286,14 @@ static BOOL emr_validate_size(const ENHMETARECORD *emr)
pPlgBlt->offBmiMask > pPlgBlt->offBmiMask + pPlgBlt->cbBmiMask ||
emr->nSize < pPlgBlt->offBmiMask + pPlgBlt->cbBmiMask ||
pPlgBlt->offBitsMask > pPlgBlt->offBitsMask + pPlgBlt->cbBitsMask ||
- emr->nSize < pPlgBlt->offBitsMask + pPlgBlt->cbBitsMask)
+ emr->nSize < pPlgBlt->offBitsMask + pPlgBlt->cbBitsMask ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pPlgBlt->offBmiSrc),
+ pPlgBlt->cbBmiSrc, pPlgBlt->iUsageSrc) ||
+ pPlgBlt->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pPlgBlt->offBmiSrc)) ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pPlgBlt->offBmiMask),
+ pPlgBlt->cbBmiMask, pPlgBlt->iUsageMask) ||
+ pPlgBlt->cbBitsMask < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pPlgBlt->offBmiMask)))
return FALSE;
- /* FIXME: validate dib size */
break;
}
@@ -1201,7 +1304,10 @@ static BOOL emr_validate_size(const ENHMETARECORD *emr)
pSetDIBitsToDevice->offBmiSrc > pSetDIBitsToDevice->offBmiSrc + pSetDIBitsToDevice->cbBmiSrc ||
emr->nSize < pSetDIBitsToDevice->offBmiSrc + pSetDIBitsToDevice->cbBmiSrc ||
pSetDIBitsToDevice->offBitsSrc > pSetDIBitsToDevice->offBitsSrc + pSetDIBitsToDevice->cbBitsSrc ||
- emr->nSize < pSetDIBitsToDevice->offBitsSrc + pSetDIBitsToDevice->cbBitsSrc)
+ emr->nSize < pSetDIBitsToDevice->offBitsSrc + pSetDIBitsToDevice->cbBitsSrc ||
+ !emr_validate_bmi((const BITMAPINFO*)((const BYTE*)emr + pSetDIBitsToDevice->offBmiSrc),
+ pSetDIBitsToDevice->cbBmiSrc, pSetDIBitsToDevice->iUsageSrc) ||
+ pSetDIBitsToDevice->cbBitsSrc < bitmap_bits_size((const BITMAPINFO*)((const BYTE*)emr + pSetDIBitsToDevice->offBmiSrc)))
return FALSE;
break;
}
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 5b09b848466..e0cddd9075f 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -232,6 +232,7 @@ extern void DC_UpdateXforms( DC * dc ) DECLSPEC_HIDDEN;
/* dib.c */
extern int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) DECLSPEC_HIDDEN;
+extern DWORD bitmap_bits_size( const BITMAPINFO * info ) DECLSPEC_HIDDEN;
extern BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc ) DECLSPEC_HIDDEN;
extern const RGBQUAD *get_default_color_table( int bpp ) DECLSPEC_HIDDEN;
extern void fill_default_color_table( BITMAPINFO *info ) DECLSPEC_HIDDEN;
--
2.14.1
More information about the wine-devel
mailing list