Author: tkreuzer Date: Tue Dec 29 20:28:23 2015 New Revision: 70464
URL: http://svn.reactos.org/svn/reactos?rev=70464&view=rev Log: [WIN32K] 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
Modified: trunk/reactos/win32ss/gdi/gdi32/objects/bitmap.c trunk/reactos/win32ss/gdi/ntgdi/dibobj.c
Modified: trunk/reactos/win32ss/gdi/gdi32/objects/bitmap.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/gdi32/objects/b... ============================================================================== --- trunk/reactos/win32ss/gdi/gdi32/objects/bitmap.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/gdi32/objects/bitmap.c [iso-8859-1] Tue Dec 29 20:28:23 2015 @@ -408,23 +408,30 @@ // 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) - { - return 0; + if (pbmiConverted == NULL) + { + 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 @@ /* 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 @@ // 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 @@
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 @@ 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; }
Modified: trunk/reactos/win32ss/gdi/ntgdi/dibobj.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/dibobj.c?... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/dibobj.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/dibobj.c [iso-8859-1] Tue Dec 29 20:28:23 2015 @@ -259,11 +259,37 @@ 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 @@ BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression), bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, - bmi->bmiHeader.biSizeImage, + cjSizeImage, (PVOID)Bits, 0); if (!SourceBitmap) @@ -314,6 +340,8 @@ rcDst.right = psurfDst->SurfObj.sizlBitmap.cx; ptSrc.x = 0; ptSrc.y = 0; + + NT_ASSERT(psurfSrc->SurfObj.cjBits <= cjMaxBits);
result = IntEngCopyBits(&psurfDst->SurfObj, &psurfSrc->SurfObj, @@ -1366,7 +1394,11 @@ /* 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 @@ 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 @@
if(!NT_SUCCESS(Status)) { + DPRINT1("Got an exception! pjInit = %p\n", pjInit); SetLastNtError(Status); goto cleanup; } @@ -1498,6 +1532,7 @@ hdcDest = NtGdiCreateCompatibleDC(0); if(!hdcDest) { + DPRINT1("NtGdiCreateCompatibleDC failed\n"); return NULL; } } @@ -1509,6 +1544,7 @@ Dc = DC_LockDc(hdcDest); if (!Dc) { + DPRINT1("Failed to lock hdcDest %p\n", hdcDest); EngSetLastError(ERROR_INVALID_HANDLE); return NULL; }