- Pass bitmap buffer size to SURFACE_AllocSurface and validate it
- Fix arithmetic overflow checks by using RtlULongMult
- GreExtTextOutW: do not allocate / blit zero sized bitmaps
- NtGdiStretchDIBitsInternal: do not pass negative y size to GreCreateBitmapEx
- DIB_CreateDIBSection: use calculated bitmap size, instead of biSizeImage when calculating the section view size and as size parameter to GreCreateBitmapEx
CORE-9245 #resolve

svn path=/trunk/; revision=66611
This commit is contained in:
Timo Kreuzer 2015-03-08 17:25:44 +00:00
parent 15f19bca32
commit ff14566384
8 changed files with 116 additions and 72 deletions

View file

@ -1078,6 +1078,7 @@ IntEngMaskBlt(
psoDest->iBitmapFormat, psoDest->iBitmapFormat,
0, 0,
0, 0,
0,
NULL); NULL);
if (psurfTemp == NULL) if (psurfTemp == NULL)
{ {

View file

@ -120,6 +120,7 @@ SURFACE_AllocSurface(
_In_ ULONG iFormat, _In_ ULONG iFormat,
_In_ ULONG fjBitmap, _In_ ULONG fjBitmap,
_In_opt_ ULONG cjWidth, _In_opt_ ULONG cjWidth,
_In_opt_ ULONG cjBufSize,
_In_opt_ PVOID pvBits) _In_opt_ PVOID pvBits)
{ {
ULONG cBitsPixel, cjBits, cjObject; ULONG cBitsPixel, cjBits, cjObject;
@ -127,7 +128,9 @@ SURFACE_AllocSurface(
SURFOBJ *pso; SURFOBJ *pso;
PVOID pvSection; PVOID pvSection;
ASSERT(!pvBits || (iType == STYPE_BITMAP)); NT_ASSERT(!pvBits || (iType == STYPE_BITMAP));
NT_ASSERT((iFormat <= BMF_32BPP) || (cjBufSize != 0));
NT_ASSERT((LONG)cy > 0);
/* Verify format */ /* Verify format */
if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG)) if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG))
@ -151,8 +154,35 @@ SURFACE_AllocSurface(
cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel); cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel);
} }
/* Calculate the bitmap size in bytes */ /* Is this an uncompressed format? */
cjBits = cjWidth * cy; if (iFormat <= BMF_32BPP)
{
/* Calculate the correct bitmap size in bytes */
if (!NT_SUCCESS(RtlULongMult(cjWidth, cy, &cjBits)))
{
DPRINT1("Overflow calculating size: cjWidth %lu, cy %lu\n",
cjWidth, cy);
return NULL;
}
/* Did we get a buffer and size? */
if ((pvBits != NULL) && (cjBufSize != 0))
{
/* Make sure the buffer is large enough */
if (cjBufSize < cjBits)
{
DPRINT1("Buffer is too small, required: %lu, got %lu\n",
cjBits, cjBufSize);
return NULL;
}
}
}
else
{
/* Compressed format, use the provided size */
NT_ASSERT(cjBufSize != 0);
cjBits = cjBufSize;
}
/* Check if we need an extra large object */ /* Check if we need an extra large object */
if ((iType == STYPE_BITMAP) && (pvBits == NULL) && if ((iType == STYPE_BITMAP) && (pvBits == NULL) &&
@ -168,9 +198,10 @@ SURFACE_AllocSurface(
} }
/* Check for arithmetic overflow */ /* Check for arithmetic overflow */
if ((cjBits < cjWidth) || (cjObject < sizeof(SURFACE))) if (cjObject < sizeof(SURFACE))
{ {
/* Fail! */ /* Fail! */
DPRINT1("Overflow calculating cjObject: cjBits %lu\n", cjBits);
return NULL; return NULL;
} }
@ -289,6 +320,7 @@ EngCreateBitmap(
iFormat, iFormat,
fl, fl,
lWidth, lWidth,
0,
pvBits); pvBits);
if (!psurf) if (!psurf)
{ {
@ -327,6 +359,7 @@ EngCreateDeviceBitmap(
iFormat, iFormat,
0, 0,
0, 0,
0,
NULL); NULL);
if (!psurf) if (!psurf)
{ {
@ -365,6 +398,7 @@ EngCreateDeviceSurface(
iFormat, iFormat,
0, 0,
0, 0,
0,
NULL); NULL);
if (!psurf) if (!psurf)
{ {

View file

@ -123,6 +123,7 @@ SURFACE_AllocSurface(
_In_ ULONG iFormat, _In_ ULONG iFormat,
_In_ ULONG fjBitmap, _In_ ULONG fjBitmap,
_In_opt_ ULONG cjWidth, _In_opt_ ULONG cjWidth,
_In_opt_ ULONG cjBits,
_In_opt_ PVOID pvBits); _In_opt_ PVOID pvBits);
FORCEINLINE FORCEINLINE

View file

@ -1453,6 +1453,7 @@ NtGdiGetPixel(
BMF_32BPP, BMF_32BPP,
0, 0,
0, 0,
0,
&ulRGBColor); &ulRGBColor);
if (psurfDest) if (psurfDest)
{ {

View file

@ -103,6 +103,7 @@ GreCreateBitmapEx(
pvCompressedBits = pvBits; pvCompressedBits = pvBits;
pvBits = NULL; pvBits = NULL;
iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP; iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
cjSizeImage = 0;
} }
/* Allocate a surface */ /* Allocate a surface */
@ -112,6 +113,7 @@ GreCreateBitmapEx(
iFormat, iFormat,
fjBitmap, fjBitmap,
cjWidthBytes, cjWidthBytes,
cjSizeImage,
pvBits); pvBits);
if (!psurf) if (!psurf)
{ {
@ -207,6 +209,7 @@ NtGdiCreateBitmap(
iFormat, iFormat,
0, 0,
0, 0,
0,
NULL); NULL);
if (!psurf) if (!psurf)
{ {

View file

@ -1090,7 +1090,7 @@ NtGdiGetDIBitsInternal(
_SEH2_TRY _SEH2_TRY
{ {
/* Copy the data back */ /* Copy the data back */
cjMaxInfo = min(cjMaxInfo, DIB_BitmapInfoSize(pbmi, (WORD)iUsage)); cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmi, (WORD)iUsage));
ProbeForWrite(pbmiUser, cjMaxInfo, 1); ProbeForWrite(pbmiUser, cjMaxInfo, 1);
RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo); RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo);
} }
@ -1228,7 +1228,7 @@ NtGdiStretchDIBitsInternal(
RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth, hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
pbmi->bmiHeader.biHeight, abs(pbmi->bmiHeader.biHeight),
0, 0,
BitmapFormat(pbmi->bmiHeader.biBitCount, BitmapFormat(pbmi->bmiHeader.biBitCount,
pbmi->bmiHeader.biCompression), pbmi->bmiHeader.biCompression),
@ -1652,7 +1652,7 @@ DIB_CreateDIBSection(
// Get storage location for DIB bits. Only use biSizeImage if it's valid and // Get storage location for DIB bits. Only use biSizeImage if it's valid and
// we're dealing with a compressed bitmap. Otherwise, use width * height. // we're dealing with a compressed bitmap. Otherwise, use width * height.
totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight); ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
if (section) if (section)
@ -1674,7 +1674,7 @@ DIB_CreateDIBSection(
} }
mapOffset = offset - (offset % Sbi.AllocationGranularity); mapOffset = offset - (offset % Sbi.AllocationGranularity);
mapSize = bi->biSizeImage + (offset - mapOffset); mapSize = totalSize + (offset - mapOffset);
SectionOffset.LowPart = mapOffset; SectionOffset.LowPart = mapOffset;
SectionOffset.HighPart = 0; SectionOffset.HighPart = 0;
@ -1724,7 +1724,7 @@ DIB_CreateDIBSection(
BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression), BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT | BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
((bi->biHeight < 0) ? BMF_TOPDOWN : 0), ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
bi->biSizeImage, totalSize,
bm.bmBits, bm.bmBits,
0); 0);
if (!res) if (!res)

View file

@ -3662,7 +3662,6 @@ GreExtTextOutW(
ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
MouseSafetyOnDrawEnd(dc->ppdev); MouseSafetyOnDrawEnd(dc->ppdev);
BackgroundLeft = DestRect.right; BackgroundLeft = DestRect.right;
} }
DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
@ -3675,72 +3674,76 @@ GreExtTextOutW(
MaskRect.right = realglyph->bitmap.width; MaskRect.right = realglyph->bitmap.width;
MaskRect.bottom = realglyph->bitmap.rows; MaskRect.bottom = realglyph->bitmap.rows;
/* /* Check if the bitmap has any pixels */
* We should create the bitmap out of the loop at the biggest possible if ((bitSize.cx != 0) && (bitSize.cy != 0))
* glyph size. Then use memset with 0 to clear it and sourcerect to {
* limit the work of the transbitblt. /*
*/ * We should create the bitmap out of the loop at the biggest possible
* glyph size. Then use memset with 0 to clear it and sourcerect to
* limit the work of the transbitblt.
*/
HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
BMF_8BPP, BMF_TOPDOWN, BMF_8BPP, BMF_TOPDOWN,
realglyph->bitmap.buffer); realglyph->bitmap.buffer);
if ( !HSourceGlyph ) if ( !HSourceGlyph )
{ {
DPRINT1("WARNING: EngLockSurface() failed!\n"); DPRINT1("WARNING: EngCreateBitmap() failed!\n");
// FT_Done_Glyph(realglyph); // FT_Done_Glyph(realglyph);
IntUnLockFreeType; IntUnLockFreeType;
DC_vFinishBlit(dc, NULL); DC_vFinishBlit(dc, NULL);
goto fail2; goto fail2;
} }
SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph); SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
if ( !SourceGlyphSurf ) if ( !SourceGlyphSurf )
{ {
EngDeleteSurface((HSURF)HSourceGlyph);
DPRINT1("WARNING: EngLockSurface() failed!\n");
IntUnLockFreeType;
DC_vFinishBlit(dc, NULL);
goto fail2;
}
/*
* Use the font data as a mask to paint onto the DCs surface using a
* brush.
*/
if (lprc && (fuOptions & ETO_CLIPPED) &&
DestRect.right >= lprc->right + dc->ptlDCOrig.x)
{
// We do the check '>=' instead of '>' to possibly save an iteration
// through this loop, since it's breaking after the drawing is done,
// and x is always incremented.
DestRect.right = lprc->right + dc->ptlDCOrig.x;
DoBreak = TRUE;
}
if (lprc && (fuOptions & ETO_CLIPPED) &&
DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
{
DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
}
MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
if (!IntEngMaskBlt(
SurfObj,
SourceGlyphSurf,
&dc->co.ClipObj,
&exloRGB2Dst.xlo,
&exloDst2RGB.xlo,
&DestRect,
(PPOINTL)&MaskRect,
&dc->eboText.BrushObject,
&BrushOrigin))
{
DPRINT1("Failed to MaskBlt a glyph!\n");
}
MouseSafetyOnDrawEnd(dc->ppdev) ;
EngUnlockSurface(SourceGlyphSurf);
EngDeleteSurface((HSURF)HSourceGlyph); EngDeleteSurface((HSURF)HSourceGlyph);
DPRINT1("WARNING: EngLockSurface() failed!\n");
IntUnLockFreeType;
DC_vFinishBlit(dc, NULL);
goto fail2;
} }
/*
* Use the font data as a mask to paint onto the DCs surface using a
* brush.
*/
if (lprc && (fuOptions & ETO_CLIPPED) &&
DestRect.right >= lprc->right + dc->ptlDCOrig.x)
{
// We do the check '>=' instead of '>' to possibly save an iteration
// through this loop, since it's breaking after the drawing is done,
// and x is always incremented.
DestRect.right = lprc->right + dc->ptlDCOrig.x;
DoBreak = TRUE;
}
if (lprc && (fuOptions & ETO_CLIPPED) &&
DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
{
DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
}
MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
if (!IntEngMaskBlt(
SurfObj,
SourceGlyphSurf,
&dc->co.ClipObj,
&exloRGB2Dst.xlo,
&exloDst2RGB.xlo,
&DestRect,
(PPOINTL)&MaskRect,
&dc->eboText.BrushObject,
&BrushOrigin))
{
DPRINT1("Failed to MaskBlt a glyph!\n");
}
MouseSafetyOnDrawEnd(dc->ppdev) ;
EngUnlockSurface(SourceGlyphSurf);
EngDeleteSurface((HSURF)HSourceGlyph);
if (DoBreak) if (DoBreak)
{ {
break; break;

View file

@ -26,6 +26,7 @@
#include <ndk/psfuncs.h> #include <ndk/psfuncs.h>
#include <ndk/rtlfuncs.h> #include <ndk/rtlfuncs.h>
#include <ntstrsafe.h> #include <ntstrsafe.h>
#include <ntintsafe.h>
#include <ntddkbd.h> #include <ntddkbd.h>
/* Win32 headers */ /* Win32 headers */