Signed-off-by: Vincent Povirk vincent@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;