[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