From 402bc38ba7cabda46e816b9cfa35773922b56d60 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 4 Sep 2024 21:14:31 +0300 Subject: [PATCH] [NTGDI] Rewrite NtGdiPolyDraw It is now a wrapper around GdiPolyDraw, which implements the main body of the function, while the Nt function only probes and captures the user mode data into safe kernel mode buffers. Previously some people thought it was a great idea to just wrap the entire implementation in SEH, so when something throws an exception somewhere for whatever reason, we can just catch it here... and LEAK ALL RESOURCES IN THE PROCESS! TODO: Rewrite all of this. It's broken everywhere. --- win32ss/gdi/ntgdi/line.c | 97 +++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/win32ss/gdi/ntgdi/line.c b/win32ss/gdi/ntgdi/line.c index 9e3ff20c824..9c4bee2bd13 100644 --- a/win32ss/gdi/ntgdi/line.c +++ b/win32ss/gdi/ntgdi/line.c @@ -11,6 +11,8 @@ #define NDEBUG #include +DBG_DEFAULT_CHANNEL(GdiLine); + // Some code from the WINE project source (www.winehq.com) VOID FASTCALL @@ -531,9 +533,9 @@ NtGdiLineTo(HDC hDC, } // FIXME: This function is completely broken +static BOOL -APIENTRY -NtGdiPolyDraw( +GdiPolyDraw( IN HDC hdc, IN LPPOINT lppt, IN LPBYTE lpbTypes, @@ -567,15 +569,11 @@ NtGdiPolyDraw( line_pts_old = NULL; bzr_pts = NULL; - _SEH2_TRY { - ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG)); - ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE)); - if (PATH_IsPathOpen(dc->dclevel)) { result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount); - _SEH2_LEAVE; + goto Cleanup; } /* Check for valid point types */ @@ -595,7 +593,7 @@ NtGdiPolyDraw( break; } default: - _SEH2_LEAVE; + goto Cleanup; } } @@ -604,7 +602,7 @@ NtGdiPolyDraw( if (line_pts == NULL) { result = FALSE; - _SEH2_LEAVE; + goto Cleanup; } num_pts = 1; @@ -639,7 +637,7 @@ NtGdiPolyDraw( space = size * 2; line_pts_old = line_pts; line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE); - if (!line_pts) _SEH2_LEAVE; + if (!line_pts) goto Cleanup; RtlCopyMemory(line_pts, line_pts_old, space_old * sizeof(POINT)); ExFreePoolWithTag(line_pts_old, TAG_SHAPE); line_pts_old = NULL; @@ -659,11 +657,8 @@ NtGdiPolyDraw( IntGdiMoveToEx( dc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL ); result = TRUE; } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - SetLastNtError(_SEH2_GetExceptionCode()); - } - _SEH2_END; + +Cleanup: if (line_pts != NULL) { @@ -685,6 +680,78 @@ NtGdiPolyDraw( return result; } +__kernel_entry +W32KAPI +BOOL +APIENTRY +NtGdiPolyDraw( + _In_ HDC hdc, + _In_reads_(cpt) LPPOINT ppt, + _In_reads_(cpt) LPBYTE pjAttr, + _In_ ULONG cpt) +{ + PBYTE pjBuffer; + PPOINT pptSafe; + PBYTE pjSafe; + SIZE_T cjSizePt; + BOOL bResult; + + if (cpt == 0) + { + ERR("cpt is 0\n"); + return FALSE; + } + + /* Validate that cpt isn't too large */ + if (cpt > ((MAXULONG - cpt) / sizeof(*ppt))) + { + ERR("cpt is too large\n", cpt); + return FALSE; + } + + /* Calculate size for a buffer */ + cjSizePt = cpt * sizeof(*ppt); + ASSERT(cjSizePt + cpt > cjSizePt); + + /* Allocate a buffer for all data */ + pjBuffer = ExAllocatePoolWithTag(PagedPool, cjSizePt + cpt, TAG_SHAPE); + if (pjBuffer == NULL) + { + ERR("Failed to allocate buffer\n"); + return FALSE; + } + + pptSafe = (PPOINT)pjBuffer; + pjSafe = pjBuffer + cjSizePt; + + _SEH2_TRY + { + ProbeArrayForRead(ppt, sizeof(*ppt), cpt, sizeof(ULONG)); + ProbeArrayForRead(pjAttr, sizeof(*pjAttr), cpt, sizeof(BYTE)); + + /* Copy the arrays */ + RtlCopyMemory(pptSafe, ppt, cjSizePt); + RtlCopyMemory(pjSafe, pjAttr, cpt); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + SetLastNtError(_SEH2_GetExceptionCode()); + bResult = FALSE; + goto Cleanup; + } + _SEH2_END; + + /* Call the internal function */ + bResult = GdiPolyDraw(hdc, pptSafe, pjSafe, cpt); + +Cleanup: + + /* Free the buffer */ + ExFreePoolWithTag(pjBuffer, TAG_SHAPE); + + return bResult; +} + /* * @implemented */