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
This commit is contained in:
Timo Kreuzer 2015-12-29 20:28:23 +00:00
parent 64820cf82f
commit 89cb03b072
2 changed files with 82 additions and 19 deletions

View File

@ -408,23 +408,30 @@ CreateDIBitmap(
// PDC_ATTR pDc_Attr; // PDC_ATTR pDc_Attr;
UINT InfoSize = 0; UINT InfoSize = 0;
UINT cjBmpScanSize = 0; UINT cjBmpScanSize = 0;
HBITMAP hBmp; HBITMAP hBmp = NULL;
NTSTATUS Status = STATUS_SUCCESS; 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 */ /* Check for CBM_CREATDIB */
if (Init & CBM_CREATDIB) if (Init & CBM_CREATDIB)
{ {
/* CBM_CREATDIB needs Data. */ /* 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 */ /* It only works with PAL or RGB */
if (ColorUse > DIB_PAL_COLORS) if (ColorUse > DIB_PAL_COLORS)
{ {
DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
GdiSetLastError(ERROR_INVALID_PARAMETER); GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0; goto Exit;
} }
/* Use the header from the data */ /* Use the header from the data */
@ -434,38 +441,48 @@ CreateDIBitmap(
/* Header is required */ /* Header is required */
if (!Header) if (!Header)
{ {
DPRINT1("Header is NULL\n");
GdiSetLastError(ERROR_INVALID_PARAMETER); GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0; goto Exit;
} }
/* Get the bitmap format and dimensions */ /* Get the bitmap format and dimensions */
if (DIB_GetBitmapInfo(Header, &width, &height, &planes, &bpp, &compr, &dibsize) == -1) if (DIB_GetBitmapInfo(Header, &width, &height, &planes, &bpp, &compr, &dibsize) == -1)
{ {
DPRINT1("DIB_GetBitmapInfo failed!\n");
GdiSetLastError(ERROR_INVALID_PARAMETER); GdiSetLastError(ERROR_INVALID_PARAMETER);
return NULL; goto Exit;
} }
/* Check if the Compr is incompatible */ /* Check if the Compr is incompatible */
if ((compr == BI_JPEG) || (compr == BI_PNG) || (compr == BI_BITFIELDS)) 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. */ /* Only DIB_RGB_COLORS (0), DIB_PAL_COLORS (1) and 2 are valid. */
if (ColorUse > DIB_PAL_COLORS + 1) if (ColorUse > DIB_PAL_COLORS + 1)
{ {
DPRINT1("invalid compr: %lu!\n", compr);
GdiSetLastError(ERROR_INVALID_PARAMETER); GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0; goto Exit;
} }
/* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */ /* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */
if (Bits && (ColorUse > DIB_PAL_COLORS)) if (Bits && (ColorUse > DIB_PAL_COLORS))
{ {
DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
GdiSetLastError(ERROR_INVALID_PARAMETER); GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0; goto Exit;
} }
/* Negative width is not allowed */ /* Negative width is not allowed */
if (width < 0) if (width < 0)
return 0; {
DPRINT1("Negative width: %li\n", width);
goto Exit;
}
/* Top-down DIBs have a negative height. */ /* Top-down DIBs have a negative height. */
height = abs(height); height = abs(height);
@ -473,13 +490,13 @@ CreateDIBitmap(
// For Icm support. // For Icm support.
// GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr)) // GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
if (Data) if (pbmiConverted)
{ {
_SEH2_TRY _SEH2_TRY
{ {
cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) Data); cjBmpScanSize = GdiGetBitmapBitsSize(pbmiConverted);
CalculateColorTableSize(&Data->bmiHeader, &ColorUse, &InfoSize); CalculateColorTableSize(&pbmiConverted->bmiHeader, &ColorUse, &InfoSize);
InfoSize += Data->bmiHeader.biSize; InfoSize += pbmiConverted->bmiHeader.biSize;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
@ -490,8 +507,9 @@ CreateDIBitmap(
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Got an exception!\n");
GdiSetLastError(ERROR_INVALID_PARAMETER); 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, 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); hBmp = GetStockObject(DEFAULT_BITMAP);
else else
{ {
hBmp = NtGdiCreateDIBitmapInternal(hDC, width, height, Init, (LPBYTE) Bits, hBmp = NtGdiCreateDIBitmapInternal(hDC, width, height, Init, (LPBYTE)Bits,
(LPBITMAPINFO) Data, ColorUse, InfoSize, cjBmpScanSize, 0, 0); (LPBITMAPINFO)pbmiConverted, ColorUse, InfoSize, cjBmpScanSize, 0, 0);
} }
Exit:
/* Cleanup converted BITMAPINFO */
if ((pbmiConverted != NULL) && (pbmiConverted != Data))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, pbmiConverted);
}
return hBmp; return hBmp;
} }

View File

@ -259,11 +259,37 @@ IntSetDIBits(
POINTL ptSrc; POINTL ptSrc;
EXLATEOBJ exlo; EXLATEOBJ exlo;
PPALETTE ppalDIB = 0; PPALETTE ppalDIB = 0;
ULONG cjSizeImage;
if (!bmi) return 0; 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; return 0;
} }
@ -273,7 +299,7 @@ IntSetDIBits(
BitmapFormat(bmi->bmiHeader.biBitCount, BitmapFormat(bmi->bmiHeader.biBitCount,
bmi->bmiHeader.biCompression), bmi->bmiHeader.biCompression),
bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
bmi->bmiHeader.biSizeImage, cjSizeImage,
(PVOID)Bits, (PVOID)Bits,
0); 0);
if (!SourceBitmap) if (!SourceBitmap)
@ -315,6 +341,8 @@ IntSetDIBits(
ptSrc.x = 0; ptSrc.x = 0;
ptSrc.y = 0; ptSrc.y = 0;
NT_ASSERT(psurfSrc->SurfObj.cjBits <= cjMaxBits);
result = IntEngCopyBits(&psurfDst->SurfObj, result = IntEngCopyBits(&psurfDst->SurfObj,
&psurfSrc->SurfObj, &psurfSrc->SurfObj,
NULL, NULL,
@ -1366,7 +1394,11 @@ IntCreateDIBitmap(
/* Undocumented flag which creates a DDB of the format specified by the bitmap info. */ /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */
handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp); handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp);
if (!handle) if (!handle)
{
DPRINT1("IntCreateCompatibleBitmap() failed!\n");
return NULL; return NULL;
}
/* The palette must also match the given data */ /* The palette must also match the given data */
Surface = SURFACE_ShareLockSurface(handle); Surface = SURFACE_ShareLockSurface(handle);
ASSERT(Surface); ASSERT(Surface);
@ -1430,6 +1462,7 @@ NtGdiCreateDIBitmapInternal(
safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
if(!safeBits) if(!safeBits)
{ {
DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL; return NULL;
} }
@ -1452,6 +1485,7 @@ NtGdiCreateDIBitmapInternal(
if(!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
DPRINT1("Got an exception! pjInit = %p\n", pjInit);
SetLastNtError(Status); SetLastNtError(Status);
goto cleanup; goto cleanup;
} }
@ -1498,6 +1532,7 @@ GreCreateDIBitmapInternal(
hdcDest = NtGdiCreateCompatibleDC(0); hdcDest = NtGdiCreateCompatibleDC(0);
if(!hdcDest) if(!hdcDest)
{ {
DPRINT1("NtGdiCreateCompatibleDC failed\n");
return NULL; return NULL;
} }
} }
@ -1509,6 +1544,7 @@ GreCreateDIBitmapInternal(
Dc = DC_LockDc(hdcDest); Dc = DC_LockDc(hdcDest);
if (!Dc) if (!Dc)
{ {
DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
EngSetLastError(ERROR_INVALID_HANDLE); EngSetLastError(ERROR_INVALID_HANDLE);
return NULL; return NULL;
} }