[PATCH 1/3] gdi32: Add bounds checking for metafile records.
Vincent Povirk
vincent at codeweavers.com
Wed May 16 11:29:21 CDT 2018
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
---
dlls/gdi32/enhmetafile.c | 610 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 610 insertions(+)
diff --git a/dlls/gdi32/enhmetafile.c b/dlls/gdi32/enhmetafile.c
index 2d8a9b04fb2..d8f72c98718 100644
--- a/dlls/gdi32/enhmetafile.c
+++ b/dlls/gdi32/enhmetafile.c
@@ -743,6 +743,604 @@ static BOOL emr_produces_output(int type)
}
}
+static BOOL emr_validate_size(const ENHMETARECORD *emr)
+{
+ switch(emr->iType) {
+ case EMR_HEADER:
+ if (emr->nSize < FIELD_OFFSET(ENHMETAHEADER, cbPixelFormat)) return FALSE;
+ break;
+ case EMR_EOF:
+ {
+ const EMREOF *lpEof = (const EMREOF *)emr;
+ if (emr->nSize < sizeof(EMREOF) ||
+ (lpEof->nPalEntries * 4 / 4) != lpEof->nPalEntries ||
+ lpEof->offPalEntries > lpEof->offPalEntries + lpEof->nPalEntries * 4 ||
+ emr->nSize < lpEof->offPalEntries + lpEof->nPalEntries * 4)
+ return FALSE;
+ break;
+ }
+ case EMR_GDICOMMENT:
+ {
+ const EMRGDICOMMENT *lpGdiComment = (const EMRGDICOMMENT *)emr;
+ if (emr->nSize < FIELD_OFFSET(EMRGDICOMMENT, Data) ||
+ lpGdiComment->cbData > lpGdiComment->cbData + FIELD_OFFSET(EMRGDICOMMENT, Data) ||
+ emr->nSize < lpGdiComment->cbData + FIELD_OFFSET(EMRGDICOMMENT, Data))
+ return FALSE;
+ break;
+ }
+ case EMR_SETMAPMODE:
+ if (emr->nSize < sizeof(EMRSETMAPMODE)) return FALSE;
+ break;
+ case EMR_SETBKMODE:
+ if (emr->nSize < sizeof(EMRSETBKMODE)) return FALSE;
+ break;
+ case EMR_SETBKCOLOR:
+ if (emr->nSize < sizeof(EMRSETBKCOLOR)) return FALSE;
+ break;
+ case EMR_SETPOLYFILLMODE:
+ if (emr->nSize < sizeof(EMRSETPOLYFILLMODE)) return FALSE;
+ break;
+ case EMR_SETROP2:
+ if (emr->nSize < sizeof(EMRSETROP2)) return FALSE;
+ break;
+ case EMR_SETTEXTALIGN:
+ if (emr->nSize < sizeof(EMRSETTEXTALIGN)) return FALSE;
+ break;
+ case EMR_SETTEXTCOLOR:
+ if (emr->nSize < sizeof(EMRSETTEXTCOLOR)) return FALSE;
+ break;
+ case EMR_SAVEDC:
+ if (emr->nSize < sizeof(EMRSAVEDC)) return FALSE;
+ break;
+ case EMR_RESTOREDC:
+ if (emr->nSize < sizeof(EMRRESTOREDC)) return FALSE;
+ break;
+ case EMR_INTERSECTCLIPRECT:
+ if (emr->nSize < sizeof(EMRINTERSECTCLIPRECT)) return FALSE;
+ break;
+ case EMR_SELECTOBJECT:
+ if (emr->nSize < sizeof(EMRSELECTOBJECT)) return FALSE;
+ break;
+ case EMR_DELETEOBJECT:
+ if (emr->nSize < sizeof(EMRDELETEOBJECT)) return FALSE;
+ break;
+ case EMR_SETWINDOWORGEX:
+ if (emr->nSize < sizeof(EMRSETWINDOWORGEX)) return FALSE;
+ break;
+ case EMR_SETWINDOWEXTEX:
+ if (emr->nSize < sizeof(EMRSETWINDOWEXTEX)) return FALSE;
+ break;
+ case EMR_SETVIEWPORTORGEX:
+ if (emr->nSize < sizeof(EMRSETVIEWPORTORGEX)) return FALSE;
+ break;
+ case EMR_SETVIEWPORTEXTEX:
+ if (emr->nSize < sizeof(EMRSETVIEWPORTEXTEX)) return FALSE;
+ break;
+ case EMR_CREATEPEN:
+ if (emr->nSize < sizeof(EMRCREATEPEN)) return FALSE;
+ break;
+ case EMR_EXTCREATEPEN:
+ {
+ const EMREXTCREATEPEN *pPen = (const EMREXTCREATEPEN *)emr;
+ if (emr->nSize < sizeof(EMREXTCREATEPEN) ||
+ pPen->cbBmi > pPen->offBmi + pPen->cbBmi ||
+ emr->nSize < pPen->offBmi + pPen->cbBmi ||
+ pPen->cbBits > pPen->offBits + pPen->cbBits ||
+ emr->nSize < pPen->offBits + pPen->cbBits ||
+ (pPen->elp.elpNumEntries * 4 / 4) != pPen->elp.elpNumEntries ||
+ 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 */
+ break;
+ }
+ case EMR_CREATEBRUSHINDIRECT:
+ if (emr->nSize < sizeof(EMRCREATEBRUSHINDIRECT)) return FALSE;
+ break;
+ case EMR_EXTCREATEFONTINDIRECTW:
+ if (emr->nSize < sizeof(EMREXTCREATEFONTINDIRECTW)) return FALSE;
+ break;
+ case EMR_MOVETOEX:
+ if (emr->nSize < sizeof(EMRMOVETOEX)) return FALSE;
+ break;
+ case EMR_LINETO:
+ if (emr->nSize < sizeof(EMRLINETO)) return FALSE;
+ break;
+ case EMR_RECTANGLE:
+ if (emr->nSize < sizeof(EMRRECTANGLE)) return FALSE;
+ break;
+ case EMR_ELLIPSE:
+ if (emr->nSize < sizeof(EMRELLIPSE)) return FALSE;
+ break;
+ case EMR_POLYGON16:
+ case EMR_POLYLINE16:
+ case EMR_POLYLINETO16:
+ case EMR_POLYBEZIER16:
+ case EMR_POLYBEZIERTO16:
+ {
+ const EMRPOLYGON16 *pPoly = (const EMRPOLYGON16 *)emr;
+ DWORD pts_ofs = FIELD_OFFSET(EMRPOLYGON16, apts);
+ if (emr->nSize < FIELD_OFFSET(EMRPOLYGON16, apts) ||
+ (pPoly->cpts * 4 / 4) != pPoly->cpts ||
+ pts_ofs > pts_ofs + pPoly->cpts * 4 ||
+ emr->nSize < pts_ofs + pPoly->cpts * 4)
+ return FALSE;
+ break;
+ }
+ case EMR_POLYPOLYGON16:
+ case EMR_POLYPOLYLINE16:
+ {
+ const EMRPOLYPOLYGON16 *pPolyPoly = (const EMRPOLYPOLYGON16 *)emr;
+ DWORD counts_ofs = FIELD_OFFSET(EMRPOLYPOLYGON16, aPolyCounts);
+ DWORD points_ofs, total_points=0, i;
+ if (emr->nSize < FIELD_OFFSET(EMRPOLYPOLYGON16, aPolyCounts) ||
+ (pPolyPoly->nPolys * 4 / 4) != pPolyPoly->nPolys ||
+ counts_ofs > counts_ofs + pPolyPoly->nPolys * 4 ||
+ emr->nSize < counts_ofs + pPolyPoly->nPolys * 4)
+ return FALSE;
+ points_ofs = counts_ofs + pPolyPoly->nPolys * 4;
+ if ((pPolyPoly->cpts * 4 / 4) != pPolyPoly->cpts ||
+ points_ofs > points_ofs + pPolyPoly->cpts * 4 ||
+ emr->nSize < points_ofs + pPolyPoly->cpts * 4)
+ return FALSE;
+
+ for(i = 0; i < pPolyPoly->nPolys; i++)
+ {
+ if (total_points > total_points + pPolyPoly->aPolyCounts[i] ||
+ pPolyPoly->cpts < total_points + pPolyPoly->aPolyCounts[i])
+ return FALSE;
+ total_points += pPolyPoly->aPolyCounts[i];
+ }
+ break;
+ }
+ case EMR_STRETCHDIBITS:
+ if (emr->nSize < sizeof(EMRSTRETCHDIBITS)) return FALSE;
+ /* FIXME: validate DIB size */
+ break;
+ case EMR_EXTTEXTOUTA:
+ {
+ const EMREXTTEXTOUTA *pExtTextOutA = (const EMREXTTEXTOUTA *)emr;
+ DWORD string_ofs, dx_ofs;
+ if (emr->nSize < sizeof(EMREXTTEXTOUTA))
+ return FALSE;
+ string_ofs = pExtTextOutA->emrtext.offString;
+ if (string_ofs > string_ofs + pExtTextOutA->emrtext.nChars ||
+ emr->nSize < string_ofs + pExtTextOutA->emrtext.nChars)
+ return FALSE;
+ dx_ofs = pExtTextOutA->emrtext.offDx;
+ if (dx_ofs && (
+ pExtTextOutA->emrtext.nChars * 4 / 4 != pExtTextOutA->emrtext.nChars ||
+ dx_ofs > dx_ofs + pExtTextOutA->emrtext.nChars * 4 ||
+ emr->nSize < dx_ofs + pExtTextOutA->emrtext.nChars * 4))
+ return FALSE;
+ break;
+ }
+
+ case EMR_EXTTEXTOUTW:
+ {
+ const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)emr;
+ DWORD string_ofs, dx_ofs;
+ if (emr->nSize < sizeof(EMREXTTEXTOUTW))
+ return FALSE;
+ string_ofs = pExtTextOutW->emrtext.offString;
+ if (string_ofs > string_ofs + pExtTextOutW->emrtext.nChars ||
+ pExtTextOutW->emrtext.nChars * 2 / 2 != pExtTextOutW->emrtext.nChars ||
+ emr->nSize < string_ofs + pExtTextOutW->emrtext.nChars * 2)
+ return FALSE;
+ dx_ofs = pExtTextOutW->emrtext.offDx;
+ if (dx_ofs && (
+ pExtTextOutW->emrtext.nChars * 4 / 4 != pExtTextOutW->emrtext.nChars ||
+ dx_ofs > dx_ofs + pExtTextOutW->emrtext.nChars * 4 ||
+ emr->nSize < dx_ofs + pExtTextOutW->emrtext.nChars * 4))
+ return FALSE;
+ break;
+ }
+
+ case EMR_CREATEPALETTE:
+ {
+ const EMRCREATEPALETTE *lpCreatePal = (const EMRCREATEPALETTE *)emr;
+ DWORD entries_ofs = FIELD_OFFSET(EMRCREATEPALETTE, lgpl.palPalEntry);
+
+ if (emr->nSize < FIELD_OFFSET(EMRCREATEPALETTE, lgpl.palPalEntry) ||
+ lpCreatePal->lgpl.palNumEntries * 4 / 4 != lpCreatePal->lgpl.palNumEntries ||
+ entries_ofs > entries_ofs + lpCreatePal->lgpl.palNumEntries * 4 ||
+ emr->nSize < entries_ofs + lpCreatePal->lgpl.palNumEntries * 4)
+ return FALSE;
+
+ break;
+ }
+
+ case EMR_SELECTPALETTE:
+ if (emr->nSize < sizeof(EMRSELECTPALETTE)) return FALSE;
+ break;
+ case EMR_REALIZEPALETTE:
+ if (emr->nSize < sizeof(EMRREALIZEPALETTE)) return FALSE;
+ break;
+ case EMR_EXTSELECTCLIPRGN:
+ {
+ const EMREXTSELECTCLIPRGN *lpRgn = (const EMREXTSELECTCLIPRGN *)emr;
+ DWORD data_ofs = FIELD_OFFSET(EMREXTSELECTCLIPRGN, RgnData);
+
+ if (emr->nSize < FIELD_OFFSET(EMREXTSELECTCLIPRGN, RgnData) ||
+ data_ofs > data_ofs + lpRgn->cbRgnData ||
+ emr->nSize < data_ofs + lpRgn->cbRgnData)
+ return FALSE;
+
+ break;
+ }
+
+ case EMR_SETMETARGN:
+ if (emr->nSize < sizeof(EMRSETMETARGN)) return FALSE;
+ break;
+ case EMR_SETWORLDTRANSFORM:
+ if (emr->nSize < sizeof(EMRSETWORLDTRANSFORM)) return FALSE;
+ break;
+ case EMR_POLYBEZIER:
+ case EMR_POLYGON:
+ case EMR_POLYLINE:
+ case EMR_POLYBEZIERTO:
+ case EMR_POLYLINETO:
+ {
+ const EMRPOLYBEZIER *pPoly = (const EMRPOLYBEZIER *)emr;
+ DWORD pts_ofs = FIELD_OFFSET(EMRPOLYBEZIER, aptl);
+ if (emr->nSize < FIELD_OFFSET(EMRPOLYBEZIER, aptl) ||
+ (pPoly->cptl * 8 / 8) != pPoly->cptl ||
+ pts_ofs > pts_ofs + pPoly->cptl * 8 ||
+ emr->nSize < pts_ofs + pPoly->cptl * 8)
+ return FALSE;
+ break;
+ }
+ case EMR_POLYPOLYLINE:
+ case EMR_POLYPOLYGON:
+ {
+ const EMRPOLYPOLYLINE *pPolyPoly = (const EMRPOLYPOLYLINE *)emr;
+ DWORD counts_ofs = FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts);
+ DWORD points_ofs, total_points=0, i;
+ if (emr->nSize < FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts) ||
+ (pPolyPoly->nPolys * 4 / 4) != pPolyPoly->nPolys ||
+ counts_ofs > counts_ofs + pPolyPoly->nPolys * 4 ||
+ emr->nSize < counts_ofs + pPolyPoly->nPolys * 4)
+ return FALSE;
+ points_ofs = counts_ofs + pPolyPoly->nPolys * 4;
+ if ((pPolyPoly->cptl * 8 / 8) != pPolyPoly->cptl ||
+ points_ofs > points_ofs + pPolyPoly->cptl * 8 ||
+ emr->nSize < points_ofs + pPolyPoly->cptl * 8)
+ return FALSE;
+
+ for(i = 0; i < pPolyPoly->nPolys; i++)
+ {
+ if (total_points > total_points + pPolyPoly->aPolyCounts[i] ||
+ pPolyPoly->cptl < total_points + pPolyPoly->aPolyCounts[i])
+ return FALSE;
+ total_points += pPolyPoly->aPolyCounts[i];
+ }
+ break;
+ }
+ case EMR_SETBRUSHORGEX:
+ if (emr->nSize < sizeof(EMRSETBRUSHORGEX)) return FALSE;
+ break;
+ case EMR_SETPIXELV:
+ if (emr->nSize < sizeof(EMRSETPIXELV)) return FALSE;
+ break;
+ case EMR_SETMAPPERFLAGS:
+ if (emr->nSize < sizeof(EMRSETMAPPERFLAGS)) return FALSE;
+ break;
+ case EMR_SETCOLORADJUSTMENT:
+ if (emr->nSize < sizeof(EMRSETCOLORADJUSTMENT)) return FALSE;
+ break;
+ case EMR_OFFSETCLIPRGN:
+ if (emr->nSize < sizeof(EMROFFSETCLIPRGN)) return FALSE;
+ break;
+ case EMR_EXCLUDECLIPRECT:
+ if (emr->nSize < sizeof(EMREXCLUDECLIPRECT)) return FALSE;
+ break;
+ case EMR_SCALEVIEWPORTEXTEX:
+ if (emr->nSize < sizeof(EMRSCALEVIEWPORTEXTEX)) return FALSE;
+ break;
+ case EMR_SCALEWINDOWEXTEX:
+ if (emr->nSize < sizeof(EMRSCALEWINDOWEXTEX)) return FALSE;
+ break;
+ case EMR_MODIFYWORLDTRANSFORM:
+ if (emr->nSize < sizeof(EMRMODIFYWORLDTRANSFORM)) return FALSE;
+ break;
+ case EMR_ANGLEARC:
+ if (emr->nSize < sizeof(EMRANGLEARC)) return FALSE;
+ break;
+ case EMR_ROUNDRECT:
+ if (emr->nSize < sizeof(EMRROUNDRECT)) return FALSE;
+ break;
+ case EMR_ARC:
+ if (emr->nSize < sizeof(EMRARC)) return FALSE;
+ break;
+ case EMR_CHORD:
+ if (emr->nSize < sizeof(EMRCHORD)) return FALSE;
+ break;
+ case EMR_PIE:
+ if (emr->nSize < sizeof(EMRPIE)) return FALSE;
+ break;
+ case EMR_ARCTO:
+ if (emr->nSize < sizeof(EMRARCTO)) return FALSE;
+ break;
+ case EMR_EXTFLOODFILL:
+ if (emr->nSize < sizeof(EMREXTFLOODFILL)) return FALSE;
+ break;
+ case EMR_POLYDRAW:
+ {
+ const EMRPOLYDRAW *lpPolyDraw = (const EMRPOLYDRAW *)emr;
+ DWORD pts_ofs = FIELD_OFFSET(EMRPOLYDRAW, aptl);
+ if (emr->nSize < FIELD_OFFSET(EMRPOLYDRAW, aptl) ||
+ (lpPolyDraw->cptl * 5 / 5) != lpPolyDraw->cptl ||
+ pts_ofs > pts_ofs + lpPolyDraw->cptl * 5 ||
+ emr->nSize < pts_ofs + lpPolyDraw->cptl * 5)
+ return FALSE;
+ break;
+ }
+ case EMR_SETARCDIRECTION:
+ if (emr->nSize < sizeof(EMRSETARCDIRECTION)) return FALSE;
+ break;
+ case EMR_SETMITERLIMIT:
+ if (emr->nSize < sizeof(EMRSETMITERLIMIT)) return FALSE;
+ break;
+ case EMR_BEGINPATH:
+ if (emr->nSize < sizeof(EMRBEGINPATH)) return FALSE;
+ break;
+ case EMR_ENDPATH:
+ if (emr->nSize < sizeof(EMRENDPATH)) return FALSE;
+ break;
+ case EMR_CLOSEFIGURE:
+ if (emr->nSize < sizeof(EMRCLOSEFIGURE)) return FALSE;
+ break;
+ case EMR_FILLPATH:
+ if (emr->nSize < sizeof(EMRFILLPATH)) return FALSE;
+ break;
+ case EMR_STROKEANDFILLPATH:
+ if (emr->nSize < sizeof(EMRSTROKEANDFILLPATH)) return FALSE;
+ break;
+ case EMR_STROKEPATH:
+ if (emr->nSize < sizeof(EMRSTROKEPATH)) return FALSE;
+ break;
+ case EMR_FLATTENPATH:
+ if (emr->nSize < sizeof(EMRFLATTENPATH)) return FALSE;
+ break;
+ case EMR_WIDENPATH:
+ if (emr->nSize < sizeof(EMRWIDENPATH)) return FALSE;
+ break;
+ case EMR_SELECTCLIPPATH:
+ if (emr->nSize < sizeof(EMRSELECTCLIPPATH)) return FALSE;
+ break;
+ case EMR_ABORTPATH:
+ if (emr->nSize < sizeof(EMRABORTPATH)) return FALSE;
+ break;
+ case EMR_CREATECOLORSPACE:
+ {
+ const EMRCREATECOLORSPACE *lpCreateColorSpace = (const EMRCREATECOLORSPACE*)emr;
+ DWORD i;
+ if (emr->nSize < FIELD_OFFSET(EMRCREATECOLORSPACE, lcs.lcsFilename)) return FALSE;
+ for (i=0; i<MAX_PATH; i++)
+ {
+ if (emr->nSize < FIELD_OFFSET(EMRCREATECOLORSPACE, lcs.lcsFilename[i+1])) return FALSE;
+ if (!lpCreateColorSpace->lcs.lcsFilename[i]) break;
+ }
+ if (i == MAX_PATH) return FALSE;
+ break;
+ }
+
+ case EMR_SETCOLORSPACE:
+ if (emr->nSize < sizeof(EMRSETCOLORSPACE)) return FALSE;
+ break;
+ case EMR_DELETECOLORSPACE:
+ if (emr->nSize < sizeof(EMRDELETECOLORSPACE)) return FALSE;
+ break;
+ case EMR_SETICMMODE:
+ if (emr->nSize < sizeof(EMRSETICMMODE)) return FALSE;
+ break;
+ case EMR_PIXELFORMAT:
+ if (emr->nSize < sizeof(EMRPIXELFORMAT)) return FALSE;
+ break;
+ case EMR_SETPALETTEENTRIES:
+ {
+ const EMRSETPALETTEENTRIES *lpSetPaletteEntries = (const EMRSETPALETTEENTRIES *)emr;
+ DWORD entries_ofs = FIELD_OFFSET(EMRSETPALETTEENTRIES, aPalEntries);
+
+ if (emr->nSize < FIELD_OFFSET(EMRSETPALETTEENTRIES, aPalEntries) ||
+ (lpSetPaletteEntries->cEntries * 4 / 4) != lpSetPaletteEntries->cEntries ||
+ entries_ofs > entries_ofs + lpSetPaletteEntries->cEntries * 4 ||
+ emr->nSize < entries_ofs + lpSetPaletteEntries->cEntries * 4)
+ return FALSE;
+
+ break;
+ }
+ case EMR_RESIZEPALETTE:
+ if (emr->nSize < sizeof(EMRRESIZEPALETTE)) return FALSE;
+ break;
+ case EMR_CREATEDIBPATTERNBRUSHPT:
+ if (emr->nSize < sizeof(EMRCREATEDIBPATTERNBRUSHPT)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_CREATEMONOBRUSH:
+ if (emr->nSize < sizeof(EMRCREATEMONOBRUSH)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_BITBLT:
+ if (emr->nSize < sizeof(EMRBITBLT)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_STRETCHBLT:
+ if (emr->nSize < sizeof(EMRSTRETCHBLT)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_ALPHABLEND:
+ if (emr->nSize < sizeof(EMRALPHABLEND)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_MASKBLT:
+ if (emr->nSize < sizeof(EMRMASKBLT)) return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ case EMR_PLGBLT:
+ {
+ const EMRPLGBLT *pPlgBlt = (const EMRPLGBLT *)emr;
+ if (emr->nSize < sizeof(EMRPLGBLT) ||
+ pPlgBlt->offBmiSrc > pPlgBlt->offBmiSrc + pPlgBlt->cbBmiSrc ||
+ emr->nSize < pPlgBlt->offBmiSrc + pPlgBlt->cbBmiSrc ||
+ pPlgBlt->offBitsSrc > pPlgBlt->offBitsSrc + pPlgBlt->cbBitsSrc ||
+ emr->nSize < pPlgBlt->offBitsSrc + pPlgBlt->cbBitsSrc ||
+ pPlgBlt->offBmiMask > pPlgBlt->offBmiMask + pPlgBlt->cbBmiMask ||
+ emr->nSize < pPlgBlt->offBmiMask + pPlgBlt->cbBmiMask ||
+ pPlgBlt->offBitsMask > pPlgBlt->offBitsMask + pPlgBlt->cbBitsMask ||
+ emr->nSize < pPlgBlt->offBitsMask + pPlgBlt->cbBitsMask)
+ return FALSE;
+ /* FIXME: validate dib size */
+ break;
+ }
+
+ case EMR_SETDIBITSTODEVICE:
+ {
+ const EMRSETDIBITSTODEVICE *pSetDIBitsToDevice = (const EMRSETDIBITSTODEVICE *)emr;
+ if (emr->nSize < sizeof(EMRSETDIBITSTODEVICE) ||
+ pSetDIBitsToDevice->offBmiSrc > pSetDIBitsToDevice->offBmiSrc + pSetDIBitsToDevice->cbBmiSrc ||
+ emr->nSize < pSetDIBitsToDevice->offBmiSrc + pSetDIBitsToDevice->cbBmiSrc ||
+ pSetDIBitsToDevice->offBitsSrc > pSetDIBitsToDevice->offBitsSrc + pSetDIBitsToDevice->cbBitsSrc ||
+ emr->nSize < pSetDIBitsToDevice->offBitsSrc + pSetDIBitsToDevice->cbBitsSrc)
+ return FALSE;
+ break;
+ }
+
+ case EMR_POLYTEXTOUTA:
+ {
+ const EMRPOLYTEXTOUTA *pPolyTextOutA = (const EMRPOLYTEXTOUTA *)emr;
+ int ofs_text = FIELD_OFFSET(EMRPOLYTEXTOUTA, aemrtext);
+ DWORD i;
+ if (emr->nSize < ofs_text ||
+ pPolyTextOutA->cStrings * sizeof(EMRTEXT) / sizeof(EMRTEXT) != pPolyTextOutA->cStrings ||
+ ofs_text < ofs_text + pPolyTextOutA->cStrings * sizeof(EMRTEXT) ||
+ emr->nSize < ofs_text + pPolyTextOutA->cStrings * sizeof(EMRTEXT))
+ return FALSE;
+ for (i=0; i < pPolyTextOutA->cStrings; i++)
+ {
+ const EMRTEXT *text = &pPolyTextOutA->aemrtext[i];
+ DWORD string_ofs, dx_ofs;
+ string_ofs = text->offString;
+ if (string_ofs > string_ofs + text->nChars ||
+ emr->nSize < string_ofs + text->nChars)
+ return FALSE;
+ dx_ofs = text->offDx;
+ if (dx_ofs && (
+ text->nChars * 4 / 4 != text->nChars ||
+ dx_ofs > dx_ofs + text->nChars * 4 ||
+ emr->nSize < dx_ofs + text->nChars * 4))
+ return FALSE;
+ }
+ break;
+ }
+
+ case EMR_POLYTEXTOUTW:
+ {
+ const EMRPOLYTEXTOUTW *pPolyTextOutW = (const EMRPOLYTEXTOUTW *)emr;
+ DWORD ofs_text = FIELD_OFFSET(EMRPOLYTEXTOUTW, aemrtext);
+ DWORD i;
+ if (emr->nSize < ofs_text ||
+ pPolyTextOutW->cStrings * sizeof(EMRTEXT) / sizeof(EMRTEXT) != pPolyTextOutW->cStrings ||
+ ofs_text < ofs_text + pPolyTextOutW->cStrings * sizeof(EMRTEXT) ||
+ emr->nSize < ofs_text + pPolyTextOutW->cStrings * sizeof(EMRTEXT))
+ return FALSE;
+ for (i=0; i < pPolyTextOutW->cStrings; i++)
+ {
+ const EMRTEXT *text = &pPolyTextOutW->aemrtext[i];
+ DWORD string_ofs, dx_ofs;
+ string_ofs = text->offString;
+ if (text->nChars * 2 / 2 != text->nChars ||
+ string_ofs > string_ofs + text->nChars * 2 ||
+ emr->nSize < string_ofs + text->nChars * 2)
+ return FALSE;
+ dx_ofs = text->offDx;
+ if (dx_ofs && (
+ text->nChars * 4 / 4 != text->nChars ||
+ dx_ofs > dx_ofs + text->nChars * 4 ||
+ emr->nSize < dx_ofs + text->nChars * 4))
+ return FALSE;
+ }
+ break;
+ }
+
+ case EMR_FILLRGN:
+ {
+ const EMRFILLRGN *pFillRgn = (const EMRFILLRGN *)emr;
+ DWORD ofs_data = FIELD_OFFSET(EMRFILLRGN, RgnData);
+ if (emr->nSize < ofs_data ||
+ ofs_data > ofs_data + pFillRgn->cbRgnData ||
+ emr->nSize < ofs_data + pFillRgn->cbRgnData)
+ return FALSE;
+ break;
+ }
+
+ case EMR_FRAMERGN:
+ {
+ const EMRFRAMERGN *pFrameRgn = (const EMRFRAMERGN *)emr;
+ DWORD ofs_data = FIELD_OFFSET(EMRFRAMERGN, RgnData);
+ if (emr->nSize < ofs_data ||
+ ofs_data > ofs_data + pFrameRgn->cbRgnData ||
+ emr->nSize < ofs_data + pFrameRgn->cbRgnData)
+ return FALSE;
+ break;
+ }
+
+ case EMR_INVERTRGN:
+ case EMR_PAINTRGN:
+ {
+ const EMRINVERTRGN *pInvertRgn = (const EMRINVERTRGN *)emr;
+ DWORD ofs_data = FIELD_OFFSET(EMRINVERTRGN, RgnData);
+ if (emr->nSize < ofs_data ||
+ ofs_data > ofs_data + pInvertRgn->cbRgnData ||
+ emr->nSize < ofs_data + pInvertRgn->cbRgnData)
+ return FALSE;
+ break;
+ }
+
+ case EMR_SETTEXTJUSTIFICATION:
+ {
+ if (emr->nSize < sizeof(EMRSETTEXTJUSTIFICATION)) return FALSE;
+ break;
+ }
+
+ case EMR_SETLAYOUT:
+ {
+ if (emr->nSize < sizeof(EMRSETLAYOUT)) return FALSE;
+ break;
+ }
+
+ case EMR_GRADIENTFILL:
+ {
+ EMRGRADIENTFILL *grad = (EMRGRADIENTFILL *)emr;
+ DWORD vertex_ofs, mesh_item_size, mesh_ofs;
+ vertex_ofs = FIELD_OFFSET(EMRGRADIENTFILL, Ver);
+ if (emr->nSize < vertex_ofs) return FALSE;
+
+ mesh_ofs = vertex_ofs + grad->nVer * sizeof(TRIVERTEX);
+ if (grad->nVer * sizeof(TRIVERTEX) / sizeof(TRIVERTEX) != grad->nVer ||
+ vertex_ofs > mesh_ofs ||
+ emr->nSize < mesh_ofs)
+ return FALSE;
+
+ if (grad->ulMode == GRADIENT_FILL_TRIANGLE)
+ mesh_item_size = sizeof(GRADIENT_TRIANGLE);
+ else
+ mesh_item_size = sizeof(GRADIENT_RECT);
+
+ if (grad->nTri * mesh_item_size / mesh_item_size != grad->nTri ||
+ mesh_ofs > mesh_ofs + grad->nTri * mesh_item_size ||
+ emr->nSize < mesh_ofs + grad->nTri * mesh_item_size)
+ return FALSE;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
/*****************************************************************************
* PlayEnhMetaFileRecord (GDI32.@)
@@ -774,6 +1372,12 @@ BOOL WINAPI PlayEnhMetaFileRecord(
hdc, handletable, mr, handles);
if (!mr) return FALSE;
+ if (!emr_validate_size(mr))
+ {
+ ERR("record has insufficient size\n");
+ return FALSE;
+ }
+
type = mr->iType;
TRACE("record %s\n", get_emr_name(type));
@@ -2478,6 +3082,12 @@ BOOL WINAPI EnumEnhMetaFile(
break;
}
+ if (!emr_validate_size(emr))
+ {
+ ERR("record has insufficient size\n");
+ break;
+ }
+
/* In Win9x mode we update the xform if the record will produce output */
if (hdc && IS_WIN9X() && emr_produces_output(emr->iType))
EMF_Update_MF_Xform(hdc, info);
--
2.14.1
More information about the wine-devel
mailing list