From 54babc294b8842a0c7d1c57aebcc3fbba4a3993c Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sun, 30 Sep 2012 20:30:23 +0000 Subject: [PATCH] [WIN32K] - Seperate GreGetDIBitsInternal from NtGdiGetDIBitsInternal - Rewrite IntSynthesizeDib - Fixes heap corruption when doing screen shots or copying from paint CORE-6674 CORE-6093 #resolve svn path=/trunk/; revision=57443 --- reactos/win32ss/gdi/ntgdi/dib.h | 13 ++ reactos/win32ss/gdi/ntgdi/dibobj.c | 158 +++++++++++++++++------- reactos/win32ss/user/ntuser/clipboard.c | 99 ++++++++++----- 3 files changed, 192 insertions(+), 78 deletions(-) diff --git a/reactos/win32ss/gdi/ntgdi/dib.h b/reactos/win32ss/gdi/ntgdi/dib.h index 4e4cb2d1f96..7eabbdf397c 100644 --- a/reactos/win32ss/gdi/ntgdi/dib.h +++ b/reactos/win32ss/gdi/ntgdi/dib.h @@ -10,4 +10,17 @@ HPALETTE FASTCALL BuildDIBPalette (CONST BITMAPINFO *bmi); BITMAPINFO* FASTCALL DIB_ConvertBitmapInfo(CONST BITMAPINFO* bmi, DWORD Usage); VOID FASTCALL DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig); +INT +APIENTRY +GreGetDIBitsInternal( + HDC hDC, + HBITMAP hBitmap, + UINT StartScan, + UINT ScanLines, + LPBYTE Bits, + LPBITMAPINFO Info, + UINT Usage, + UINT MaxBits, + UINT MaxInfo); + #define DIB_PAL_BRUSHHACK 3 diff --git a/reactos/win32ss/gdi/ntgdi/dibobj.c b/reactos/win32ss/gdi/ntgdi/dibobj.c index a8e26cf3ce4..bd64148fbe5 100644 --- a/reactos/win32ss/gdi/ntgdi/dibobj.c +++ b/reactos/win32ss/gdi/ntgdi/dibobj.c @@ -465,7 +465,7 @@ NtGdiSetDIBitsToDeviceInternal( SourceSize.cx = bmi->bmiHeader.biWidth; SourceSize.cy = ScanLines; - + //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount); hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, @@ -500,7 +500,7 @@ NtGdiSetDIBitsToDeviceInternal( Status = STATUS_NO_MEMORY; goto Exit; } - + /* This is actually a blit */ DC_vPrepareDCsForBlit(pDC, rcDest, NULL, rcDest); pSurf = pDC->dclevel.pSurface; @@ -510,7 +510,7 @@ NtGdiSetDIBitsToDeviceInternal( ret = ScanLines; goto Exit; } - + ASSERT(pSurf->ppal); /* Initialize EXLATEOBJ */ @@ -520,7 +520,7 @@ NtGdiSetDIBitsToDeviceInternal( RGB(0xff, 0xff, 0xff), pDC->pdcattr->crBackgroundClr, pDC->pdcattr->crForegroundClr); - + pDestSurf = &pSurf->SurfObj; /* Copy the bits */ @@ -541,7 +541,7 @@ NtGdiSetDIBitsToDeviceInternal( /* Cleanup EXLATEOBJ */ EXLATEOBJ_vCleanup(&exlo); - + /* We're done */ DC_vFinishBlit(pDC, NULL); @@ -565,7 +565,7 @@ Exit2: /* Converts a device-dependent bitmap to a DIB */ INT APIENTRY -NtGdiGetDIBitsInternal( +GreGetDIBitsInternal( HDC hDC, HBITMAP hBitmap, UINT StartScan, @@ -587,31 +587,12 @@ NtGdiGetDIBitsInternal( RGBTRIPLE* rgbTriples; RGBQUAD* rgbQuads; VOID* colorPtr; - NTSTATUS Status = STATUS_SUCCESS; DPRINT("Entered NtGdiGetDIBitsInternal()\n"); if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap) return 0; - _SEH2_TRY - { - /* Probe for read and write */ - ProbeForRead(Info, MaxInfo, 1); - ProbeForWrite(Info, MaxInfo, 1); - if (Bits) ProbeForWrite(Bits, MaxBits, 1); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (!NT_SUCCESS(Status)) - { - return 0; - } - colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize; rgbTriples = colorPtr; rgbQuads = colorPtr; @@ -834,7 +815,6 @@ NtGdiGetDIBitsInternal( colorTriple->rgbtRed = (r * 0xff) / 5; colorTriple->rgbtGreen = (g * 0xff) / 5; colorTriple->rgbtBlue = (b * 0xff) / 5; - color++; } } } @@ -994,22 +974,7 @@ NtGdiGetDIBitsInternal( ScanLines = 0; else { - Status = STATUS_SUCCESS; - _SEH2_TRY - { - RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp)); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if(!NT_SUCCESS(Status)) - { - DPRINT1("Unable to copy bits to the user provided pointer\n"); - ScanLines = 0; - } + RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp)); } GreDeleteObject(hBmpDest); @@ -1026,6 +991,109 @@ done: return ScanLines; } +INT +APIENTRY +NtGdiGetDIBitsInternal( + _In_ HDC hdc, + _In_ HBITMAP hbm, + _In_ UINT iStartScan, + _In_ UINT cScans, + _Out_opt_ LPBYTE pjBits, + _Inout_ LPBITMAPINFO pbmiUser, + _In_ UINT iUsage, + _In_ UINT cjMaxBits, + _In_ UINT cjMaxInfo) +{ + PBITMAPINFO pbmi; + HANDLE hSecure = NULL; + INT iResult = 0; + + /* Check for bad iUsage */ + if (iUsage > 2) return 0; + + /* Check if the size of the bitmap info is large enough */ + if (cjMaxInfo < sizeof(BITMAPINFOHEADER)) + { + return 0; + } + + /* Use maximum size */ + cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); + + /* Allocate a buffer the bitmapinfo */ + pbmi = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'imBG'); + if (!pbmi) + { + /* Fail */ + return 0; + } + + /* Use SEH */ + _SEH2_TRY + { + /* Probe and copy the BITMAPINFO */ + ProbeForWrite(pbmiUser, cjMaxInfo, 1); + RtlCopyMemory(pbmi, pbmiUser, cjMaxInfo); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(goto cleanup;) + } + _SEH2_END; + + /* Check if the header size is large enough */ + if ((pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER)) || + (pbmi->bmiHeader.biSize > cjMaxInfo)) + { + goto cleanup; + } + + /* Check if the caller provided bitmap bits */ + if (pjBits) + { + /* Secure the user mode memory */ + hSecure = EngSecureMem(pjBits, cjMaxBits); + if (!hSecure) + { + goto cleanup; + } + } + + /* Now call the internal function */ + iResult = GreGetDIBitsInternal(hdc, + hbm, + iStartScan, + cScans, + pjBits, + pbmi, + iUsage, + cjMaxBits, + cjMaxInfo); + + /* Check for success */ + if (iResult) + { + /* Use SEH to copy back to user mode */ + _SEH2_TRY + { + /* Buffer is already probed, copy the data back */ + RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Ignore */ + } + _SEH2_END; + } + +cleanup: + if (hSecure) EngUnsecureMem(hSecure); + ExFreePoolWithTag(pbmi, 'imBG'); + + return iResult; +} + + #define ROP_TO_ROP4(Rop) ((Rop) >> 16) W32KAPI @@ -1129,7 +1197,7 @@ NtGdiStretchDIBitsInternal( rcDst.bottom = rcDst.top + cyDst; IntLPtoDP(pdc, (POINTL*)&rcDst, 2); RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); - + hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, 0, @@ -1163,7 +1231,7 @@ NtGdiStretchDIBitsInternal( /* Prepare DC for blit */ DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcSrc); - + psurfDst = pdc->dclevel.pSurface; if (!psurfDst) { @@ -1172,7 +1240,7 @@ NtGdiStretchDIBitsInternal( bResult = TRUE; goto cleanup; } - + /* Initialize XLATEOBJ */ EXLATEOBJ_vInitialize(&exlo, ppalDIB, diff --git a/reactos/win32ss/user/ntuser/clipboard.c b/reactos/win32ss/user/ntuser/clipboard.c index 821b9c4079f..cfe6fd8626a 100644 --- a/reactos/win32ss/user/ntuser/clipboard.c +++ b/reactos/win32ss/user/ntuser/clipboard.c @@ -135,48 +135,81 @@ IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta) } VOID static NTAPI -IntSynthesizeDib(PWINSTATION_OBJECT pWinStaObj, HBITMAP hBm) +IntSynthesizeDib( + PWINSTATION_OBJECT pWinStaObj, + HBITMAP hbm) { HDC hdc; - BITMAP bm; - BITMAPINFO bi; - SURFACE *psurf; - PCLIPBOARDDATA pMemObj; + ULONG cjInfoSize, cjDataSize; + PCLIPBOARDDATA pClipboardData; HANDLE hMem; + INT iResult; + struct + { + BITMAPINFOHEADER bmih; + RGBQUAD rgbColors[256]; + } bmiBuffer; + PBITMAPINFO pbmi = (PBITMAPINFO)&bmiBuffer; + /* Get the display DC */ hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE); if (!hdc) - return; - - psurf = SURFACE_ShareLockSurface(hBm); - if (!psurf) - goto cleanup; - BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm); - SURFACE_ShareUnlockSurface(psurf); - - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = bm.bmWidth; - bi.bmiHeader.biHeight = bm.bmHeight; - bi.bmiHeader.biPlanes = bm.bmPlanes; - bi.bmiHeader.biBitCount = bm.bmBitsPixel; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = 0; - bi.bmiHeader.biXPelsPerMeter = 0; - bi.bmiHeader.biYPelsPerMeter = 0; - bi.bmiHeader.biClrUsed = 0; - - NtGdiGetDIBitsInternal(hdc, hBm, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0); - - pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, &hMem, otClipBoardData, - sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage); - if(pMemObj) { - pMemObj->cbData = sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage; - memcpy(pMemObj->Data, &bi, sizeof(BITMAPINFOHEADER)); - NtGdiGetDIBitsInternal(hdc, hBm, 0, bm.bmHeight, (LPBYTE)pMemObj->Data + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0); - IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE); + return; } + /* Get information about the bitmap format */ + iResult = GreGetDIBitsInternal(hdc, + hbm, + 0, + 0, + NULL, + pbmi, + DIB_RGB_COLORS, + 0, + sizeof(bmiBuffer)); + if (iResult == 0) + { + goto cleanup; + } + + /* Get the size for a full BITMAPINFO */ + cjInfoSize = DIB_BitmapInfoSize(pbmi, DIB_RGB_COLORS); + + /* Calculate the size of the clipboard data, which is a packed DIB */ + cjDataSize = cjInfoSize + pbmi->bmiHeader.biSizeImage; + + /* Create the clipboard data */ + pClipboardData = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, + NULL, + &hMem, + otClipBoardData, + cjDataSize); + if (!pClipboardData) + { + goto cleanup; + } + + /* Set the data size */ + pClipboardData->cbData = cjDataSize; + + /* Copy the BITMAPINFOHEADER */ + memcpy(pClipboardData->Data, pbmi, sizeof(BITMAPINFOHEADER)); + + /* Get the bitmap bits and the color table */ + iResult = GreGetDIBitsInternal(hdc, + hbm, + 0, + abs(pbmi->bmiHeader.biHeight), + (LPBYTE)pClipboardData->Data + cjInfoSize, + (LPBITMAPINFO)pClipboardData->Data, + DIB_RGB_COLORS, + pbmi->bmiHeader.biSizeImage, + cjInfoSize); + + /* Add the clipboard data */ + IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE); + cleanup: UserReleaseDC(NULL, hdc, FALSE); }