[WIN32K]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 29 Dec 2015 20:28:23 +0000 (20:28 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 29 Dec 2015 20:28:23 +0000 (20:28 +0000)
Properly check the bitmap size in IntSetDIBits, taking into account that it might be set to 0, then we have to calculate it ourselves. Fixes a crash when invalid data is passed to NtGdiCreateDIBitmapInternal.
[GDI32]
Convert COREINFOHEADER to BITMAPINFOHEADER before passing it to NtGdiCreateDIBitmapInternal, which doesn't support it.
CORE-10583 #resolve

svn path=/trunk/; revision=70464

reactos/win32ss/gdi/gdi32/objects/bitmap.c
reactos/win32ss/gdi/ntgdi/dibobj.c

index d5b81dc..a2d6c2b 100644 (file)
@@ -408,23 +408,30 @@ CreateDIBitmap(
 //  PDC_ATTR pDc_Attr;
     UINT InfoSize = 0;
     UINT cjBmpScanSize = 0;
-    HBITMAP hBmp;
+    HBITMAP hBmp = NULL;
     NTSTATUS Status = STATUS_SUCCESS;
+    PBITMAPINFO pbmiConverted;
+    UINT cjInfoSize;
+
+    /* Convert the BITMAPINFO if it is a COREINFO */
+    pbmiConverted = ConvertBitmapInfo(Data, ColorUse, &cjInfoSize, FALSE);
 
     /* Check for CBM_CREATDIB */
     if (Init & CBM_CREATDIB)
     {
         /* CBM_CREATDIB needs Data. */
-        if (!Data)
+        if (pbmiConverted == NULL)
         {
-            return 0;
+            DPRINT1("CBM_CREATDIB needs a BITMAINFO!\n");
+            goto Exit;
         }
 
         /* It only works with PAL or RGB */
         if (ColorUse > DIB_PAL_COLORS)
         {
+            DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
             GdiSetLastError(ERROR_INVALID_PARAMETER);
-            return 0;
+            goto Exit;
         }
 
         /* Use the header from the data */
@@ -434,38 +441,48 @@ CreateDIBitmap(
     /* Header is required */
     if (!Header)
     {
+        DPRINT1("Header is NULL\n");
         GdiSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        goto Exit;
     }
 
     /* Get the bitmap format and dimensions */
     if (DIB_GetBitmapInfo(Header, &width, &height, &planes, &bpp, &compr, &dibsize) == -1)
     {
+        DPRINT1("DIB_GetBitmapInfo failed!\n");
         GdiSetLastError(ERROR_INVALID_PARAMETER);
-        return NULL;
+        goto Exit;
     }
 
     /* Check if the Compr is incompatible */
     if ((compr == BI_JPEG) || (compr == BI_PNG) || (compr == BI_BITFIELDS))
-        return 0;
+    {
+        DPRINT1("invalid compr: %lu!\n", compr);
+        goto Exit;
+    }
 
     /* Only DIB_RGB_COLORS (0), DIB_PAL_COLORS (1) and 2 are valid. */
     if (ColorUse > DIB_PAL_COLORS + 1)
     {
+        DPRINT1("invalid compr: %lu!\n", compr);
         GdiSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        goto Exit;
     }
 
     /* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */
     if (Bits && (ColorUse > DIB_PAL_COLORS))
     {
+        DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
         GdiSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        goto Exit;
     }
 
     /* Negative width is not allowed */
     if (width < 0)
-        return 0;
+    {
+        DPRINT1("Negative width: %li\n", width);
+        goto Exit;
+    }
 
     /* Top-down DIBs have a negative height. */
     height = abs(height);
@@ -473,13 +490,13 @@ CreateDIBitmap(
 // For Icm support.
 // GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
 
-    if (Data)
+    if (pbmiConverted)
     {
         _SEH2_TRY
         {
-            cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) Data);
-            CalculateColorTableSize(&Data->bmiHeader, &ColorUse, &InfoSize);
-            InfoSize += Data->bmiHeader.biSize;
+            cjBmpScanSize = GdiGetBitmapBitsSize(pbmiConverted);
+            CalculateColorTableSize(&pbmiConverted->bmiHeader, &ColorUse, &InfoSize);
+            InfoSize += pbmiConverted->bmiHeader.biSize;
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -490,8 +507,9 @@ CreateDIBitmap(
 
     if (!NT_SUCCESS(Status))
     {
+        DPRINT1("Got an exception!\n");
         GdiSetLastError(ERROR_INVALID_PARAMETER);
-        return NULL;
+        goto Exit;
     }
 
     DPRINT("pBMI %p, Size bpp %u, dibsize %d, Conv %u, BSS %u\n", Data, bpp, dibsize, InfoSize,
@@ -501,9 +519,18 @@ CreateDIBitmap(
         hBmp = GetStockObject(DEFAULT_BITMAP);
     else
     {
-        hBmp = NtGdiCreateDIBitmapInternal(hDC, width, height, Init, (LPBYTE) Bits,
-            (LPBITMAPINFO) Data, ColorUse, InfoSize, cjBmpScanSize, 0, 0);
+        hBmp = NtGdiCreateDIBitmapInternal(hDC, width, height, Init, (LPBYTE)Bits,
+            (LPBITMAPINFO)pbmiConverted, ColorUse, InfoSize, cjBmpScanSize, 0, 0);
     }
+
+Exit:
+
+    /* Cleanup converted BITMAPINFO */
+    if ((pbmiConverted != NULL) && (pbmiConverted != Data))
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, pbmiConverted);
+    }
+
     return hBmp;
 }
 
index 8199623..36bfa4d 100644 (file)
@@ -259,11 +259,37 @@ IntSetDIBits(
     POINTL             ptSrc;
     EXLATEOBJ  exlo;
     PPALETTE    ppalDIB = 0;
+    ULONG cjSizeImage;
 
     if (!bmi) return 0;
 
-    if (bmi->bmiHeader.biSizeImage > cjMaxBits)
+    /* Check if the header provided an image size */
+    if (bmi->bmiHeader.biSizeImage != 0)
     {
+        /* Use the given size */
+        cjSizeImage = bmi->bmiHeader.biSizeImage;
+    }
+    /* Otherwise check for uncompressed formats */
+    else if ((bmi->bmiHeader.biCompression == BI_RGB) ||
+             (bmi->bmiHeader.biCompression == BI_BITFIELDS))
+    {
+        /* Calculate the image size */
+        cjSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
+                                           ScanLines,
+                                           bmi->bmiHeader.biBitCount);
+    }
+    else
+    {
+        /* Compressed format without a size. This is invalid. */
+        DPRINT1("Compressed format without a size!");
+        return 0;
+    }
+
+    /* Check if the size that we have is ok */
+    if (cjSizeImage > cjMaxBits)
+    {
+        DPRINT1("Size too large! cjSizeImage = %lu, cjMaxBits = %lu\n",
+                cjSizeImage, cjMaxBits);
         return 0;
     }
 
@@ -273,7 +299,7 @@ IntSetDIBits(
                                      BitmapFormat(bmi->bmiHeader.biBitCount,
                                                   bmi->bmiHeader.biCompression),
                                      bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
-                                     bmi->bmiHeader.biSizeImage,
+                                     cjSizeImage,
                                      (PVOID)Bits,
                                      0);
     if (!SourceBitmap)
@@ -315,6 +341,8 @@ IntSetDIBits(
     ptSrc.x = 0;
     ptSrc.y = 0;
 
+    NT_ASSERT(psurfSrc->SurfObj.cjBits <= cjMaxBits);
+
     result = IntEngCopyBits(&psurfDst->SurfObj,
                             &psurfSrc->SurfObj,
                             NULL,
@@ -1366,7 +1394,11 @@ IntCreateDIBitmap(
             /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */
             handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp);
             if (!handle)
+            {
+                DPRINT1("IntCreateCompatibleBitmap() failed!\n");
                 return NULL;
+            }
+
             /* The palette must also match the given data */
             Surface = SURFACE_ShareLockSurface(handle);
             ASSERT(Surface);
@@ -1430,6 +1462,7 @@ NtGdiCreateDIBitmapInternal(
         safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
         if(!safeBits)
         {
+            DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
             return NULL;
         }
@@ -1452,6 +1485,7 @@ NtGdiCreateDIBitmapInternal(
 
     if(!NT_SUCCESS(Status))
     {
+        DPRINT1("Got an exception! pjInit = %p\n", pjInit);
         SetLastNtError(Status);
         goto cleanup;
     }
@@ -1498,6 +1532,7 @@ GreCreateDIBitmapInternal(
         hdcDest = NtGdiCreateCompatibleDC(0);
         if(!hdcDest)
         {
+            DPRINT1("NtGdiCreateCompatibleDC failed\n");
             return NULL;
         }
     }
@@ -1509,6 +1544,7 @@ GreCreateDIBitmapInternal(
     Dc = DC_LockDc(hdcDest);
     if (!Dc)
     {
+        DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return NULL;
     }