Revert "[WIN32K] Fix probing and parameter validation in NtGdiPolyPolyDraw"

svn path=/trunk/; revision=75609
This commit is contained in:
Timo Kreuzer 2017-08-18 12:18:41 +00:00
parent dd172a4fce
commit 8dea5dc526

View file

@ -383,56 +383,56 @@ NtGdiPolyPolyDraw( IN HDC hDC,
PVOID pTemp; PVOID pTemp;
LPPOINT SafePoints; LPPOINT SafePoints;
PULONG SafeCounts; PULONG SafeCounts;
NTSTATUS Status; NTSTATUS Status = STATUS_SUCCESS;
BOOL Ret = TRUE; BOOL Ret = TRUE;
ULONG nPoints = 0, nMaxPoints = 0, i; ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
/* Validate parameters */ if (!UnsafePoints || !UnsafeCounts ||
if ((UnsafePoints == NULL) || Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
(UnsafeCounts == NULL) ||
(Count == 0) ||
(Count > ULONG_MAX / sizeof(ULONG)) ||
(iFunc == 0) ||
(iFunc > GdiPolyPolyRgn))
{ {
DPRINT1("NtGdiPolyPolyDraw - Invalid parameter!\n");
/* Windows doesn't set last error */ /* Windows doesn't set last error */
return FALSE; return FALSE;
} }
_SEH2_TRY _SEH2_TRY
{ {
/* Probe the buffer of counts for each polygon */ ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1); ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
/* Count points. Note: We are not copying the buffer, so it can be /* Count points and validate poligons */
changed by usermode. This is ok, since the content is validated
again later. */
for (i = 0; i < Count; i++) for (i = 0; i < Count; i++)
{ {
Status = RtlULongAdd(nMaxPoints, UnsafeCounts[i], &nMaxPoints); if (UnsafeCounts[i] < 2)
if (!NT_SUCCESS(Status))
{ {
DPRINT1("Overflow when counting points!\n"); nInvalid++;
return FALSE;
} }
nPoints += UnsafeCounts[i];
nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
} }
ProbeForRead(UnsafePoints, nMaxPoints * sizeof(POINT), 1);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
DPRINT1("Got exception!\n"); Status = _SEH2_GetExceptionCode();
/* Windows doesn't set last error */
return FALSE;
} }
_SEH2_END; _SEH2_END;
if (nMaxPoints == 0) if (!NT_SUCCESS(Status))
{ {
/* If all polygon counts are zero, return FALSE /* Windows doesn't set last error */
without setting a last error code. */ return FALSE;
DPRINT1("nMaxPoints == 0!\n"); }
if (nPoints == 0 || nPoints < nMaxPoints)
{
/* If all polygon counts are zero, or we have overflow,
return without setting a last error code. */
return FALSE;
}
if (nInvalid != 0)
{
/* If at least one poly count is 0 or 1, fail */
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
@ -442,16 +442,12 @@ NtGdiPolyPolyDraw( IN HDC hDC,
TAG_SHAPE); TAG_SHAPE);
if (!pTemp) if (!pTemp)
{ {
DPRINT1("Failed to allocate %lu bytes (Count = %lu, nPoints = %u).\n",
Count * sizeof(ULONG) + nPoints * sizeof(POINT),
Count,
nPoints);
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE; return FALSE;
} }
SafeCounts = pTemp; SafeCounts = pTemp;
SafePoints = (PPOINT)&SafeCounts[Count]; SafePoints = (PVOID)(SafeCounts + Count);
_SEH2_TRY _SEH2_TRY
{ {
@ -461,37 +457,12 @@ NtGdiPolyPolyDraw( IN HDC hDC,
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
DPRINT1("Got exception!\n"); Status = _SEH2_GetExceptionCode();
ExFreePoolWithTag(pTemp, TAG_SHAPE);
return FALSE;
} }
_SEH2_END; _SEH2_END;
/* Now that the buffers are copied, validate them again */ if (!NT_SUCCESS(Status))
for (i = 0; i < Count; i++)
{ {
/* If any poly count is 0 or 1, fail */
if (SafeCounts[i] < 2)
{
DPRINT1("Invalid: UnsafeCounts[%lu] == %lu\n", i, SafeCounts[i]);
ExFreePoolWithTag(pTemp, TAG_SHAPE);
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
Status = RtlULongAdd(nPoints, SafeCounts[i], &nPoints);
if (!NT_SUCCESS(Status))
{
DPRINT1("Overflow when counting points!\n");
return FALSE;
}
}
/* If the 2nd count does not match the 1st, someone changed the buffer
behind our back! */
if (nPoints != nMaxPoints)
{
DPRINT1("Polygon count mismatch: %lu != %lu\n", nPoints, nMaxPoints);
ExFreePoolWithTag(pTemp, TAG_SHAPE); ExFreePoolWithTag(pTemp, TAG_SHAPE);
return FALSE; return FALSE;
} }