mirror of
https://github.com/reactos/reactos.git
synced 2025-07-05 23:41:22 +00:00
[CSRSRV] Improve validation of CSR API Message's capture buffers.
- Improve capture buffer validation in CsrCaptureArguments(), by implementing the checks done by Windows 2003 (NT 5.2) described in section "Server-Side Validation and Capture" of the article https://www.geoffchappell.com/studies/windows/win32/csrsrv/api/apireqst/capture_header.htm - In CsrReleaseCapturedArguments(), protect the data copy back into the client buffer within a SEH block.
This commit is contained in:
parent
358dd50d61
commit
7e2db77338
1 changed files with 116 additions and 24 deletions
|
@ -1120,34 +1120,68 @@ NTAPI
|
||||||
CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
IN PCSR_API_MESSAGE ApiMessage)
|
IN PCSR_API_MESSAGE ApiMessage)
|
||||||
{
|
{
|
||||||
PCSR_CAPTURE_BUFFER ClientCaptureBuffer = NULL, ServerCaptureBuffer = NULL;
|
PCSR_PROCESS CsrProcess = CsrThread->Process;
|
||||||
|
PCSR_CAPTURE_BUFFER ClientCaptureBuffer, ServerCaptureBuffer = NULL;
|
||||||
|
ULONG_PTR EndOfClientBuffer;
|
||||||
|
SIZE_T SizeOfBufferThroughOffsetsArray;
|
||||||
SIZE_T BufferDistance;
|
SIZE_T BufferDistance;
|
||||||
ULONG Length = 0;
|
ULONG Length;
|
||||||
ULONG PointerCount;
|
ULONG PointerCount;
|
||||||
PULONG_PTR OffsetPointer;
|
PULONG_PTR OffsetPointer;
|
||||||
ULONG_PTR CurrentOffset;
|
ULONG_PTR CurrentOffset;
|
||||||
|
|
||||||
/* Use SEH to make sure this is valid */
|
/* Get the buffer we got from whoever called NTDLL */
|
||||||
|
ClientCaptureBuffer = ApiMessage->CsrCaptureData;
|
||||||
|
|
||||||
|
/* Use SEH to validate and capture the client buffer */
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
/* Get the buffer we got from whoever called NTDLL */
|
/* Check whether at least the buffer's header is inside our mapped section */
|
||||||
ClientCaptureBuffer = ApiMessage->CsrCaptureData;
|
if ( ((ULONG_PTR)ClientCaptureBuffer < CsrProcess->ClientViewBase) ||
|
||||||
Length = ClientCaptureBuffer->Size;
|
(((ULONG_PTR)ClientCaptureBuffer + FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray))
|
||||||
|
>= CsrProcess->ClientViewBounds) )
|
||||||
/* Now check if the buffer is inside our mapped section */
|
|
||||||
if (((ULONG_PTR)ClientCaptureBuffer < CsrThread->Process->ClientViewBase) ||
|
|
||||||
(((ULONG_PTR)ClientCaptureBuffer + Length) >= CsrThread->Process->ClientViewBounds))
|
|
||||||
{
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 1\n");
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
/* Return failure */
|
/* Return failure */
|
||||||
DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
|
|
||||||
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
_SEH2_YIELD(return FALSE);
|
_SEH2_YIELD(return FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the Length is valid */
|
/* Capture the buffer length */
|
||||||
if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
|
Length = ClientCaptureBuffer->Size;
|
||||||
(ClientCaptureBuffer->PointerCount * sizeof(PVOID)) > Length) ||
|
|
||||||
(ClientCaptureBuffer->PointerCount > MAXUSHORT))
|
/*
|
||||||
|
* Now check if the remaining of the buffer is inside our mapped section.
|
||||||
|
* Take also care for any possible wrap-around of the buffer end-address.
|
||||||
|
*/
|
||||||
|
EndOfClientBuffer = (ULONG_PTR)ClientCaptureBuffer + Length;
|
||||||
|
if ( (EndOfClientBuffer < (ULONG_PTR)ClientCaptureBuffer) ||
|
||||||
|
(EndOfClientBuffer >= CsrProcess->ClientViewBounds) )
|
||||||
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 2\n");
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
|
/* Return failure */
|
||||||
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
|
_SEH2_YIELD(return FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capture the pointer count */
|
||||||
|
PointerCount = ClientCaptureBuffer->PointerCount;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the total buffer size and the pointer count are consistent
|
||||||
|
* -- the array of offsets must be contained inside the buffer.
|
||||||
|
*/
|
||||||
|
SizeOfBufferThroughOffsetsArray =
|
||||||
|
FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
|
||||||
|
(PointerCount * sizeof(PVOID));
|
||||||
|
if ( (PointerCount > MAXUSHORT) ||
|
||||||
|
(SizeOfBufferThroughOffsetsArray > Length) )
|
||||||
{
|
{
|
||||||
#ifdef CSR_DBG
|
#ifdef CSR_DBG
|
||||||
DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", ClientCaptureBuffer);
|
DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", ClientCaptureBuffer);
|
||||||
|
@ -1160,10 +1194,15 @@ CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
}
|
}
|
||||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
/* Return failure */
|
/* Return failure */
|
||||||
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
_SEH2_YIELD(return FALSE);
|
_SEH2_YIELD(return FALSE);
|
||||||
} _SEH2_END;
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
/* We validated the client buffer, now allocate the server buffer */
|
/* We validated the client buffer, now allocate the server buffer */
|
||||||
ServerCaptureBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
|
ServerCaptureBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
|
||||||
|
@ -1174,8 +1213,29 @@ CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the client's buffer */
|
/*
|
||||||
RtlMoveMemory(ServerCaptureBuffer, ClientCaptureBuffer, Length);
|
* Copy the client's buffer and ensure we use the correct buffer length
|
||||||
|
* and pointer count we captured and used for validation earlier on.
|
||||||
|
*/
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
RtlMoveMemory(ServerCaptureBuffer, ClientCaptureBuffer, Length);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
|
/* Failure, free the buffer and return */
|
||||||
|
RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
|
||||||
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
|
_SEH2_YIELD(return FALSE);
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
ServerCaptureBuffer->Size = Length;
|
||||||
|
ServerCaptureBuffer->PointerCount = PointerCount;
|
||||||
|
|
||||||
/* Calculate the difference between our buffer and the client's */
|
/* Calculate the difference between our buffer and the client's */
|
||||||
BufferDistance = (ULONG_PTR)ServerCaptureBuffer - (ULONG_PTR)ClientCaptureBuffer;
|
BufferDistance = (ULONG_PTR)ServerCaptureBuffer - (ULONG_PTR)ClientCaptureBuffer;
|
||||||
|
@ -1184,7 +1244,7 @@ CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
* All the pointer offsets correspond to pointers which point
|
* All the pointer offsets correspond to pointers which point
|
||||||
* to the server data buffer instead of the client one.
|
* to the server data buffer instead of the client one.
|
||||||
*/
|
*/
|
||||||
PointerCount = ServerCaptureBuffer->PointerCount;
|
// PointerCount = ServerCaptureBuffer->PointerCount;
|
||||||
OffsetPointer = ServerCaptureBuffer->PointerOffsetsArray;
|
OffsetPointer = ServerCaptureBuffer->PointerOffsetsArray;
|
||||||
while (PointerCount--)
|
while (PointerCount--)
|
||||||
{
|
{
|
||||||
|
@ -1192,12 +1252,30 @@ CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
|
|
||||||
if (CurrentOffset != 0)
|
if (CurrentOffset != 0)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Check whether the offset is pointer-aligned and whether
|
||||||
|
* it points inside CSR_API_MESSAGE::Data.ApiMessageData.
|
||||||
|
*/
|
||||||
|
if ( ((CurrentOffset & (sizeof(PVOID)-1)) != 0) ||
|
||||||
|
(CurrentOffset < FIELD_OFFSET(CSR_API_MESSAGE, Data.ApiMessageData)) ||
|
||||||
|
(CurrentOffset >= sizeof(CSR_API_MESSAGE)) )
|
||||||
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of message\n");
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
|
/* Invalid pointer, fail */
|
||||||
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the pointer corresponding to the offset */
|
/* Get the pointer corresponding to the offset */
|
||||||
CurrentOffset += (ULONG_PTR)ApiMessage;
|
CurrentOffset += (ULONG_PTR)ApiMessage;
|
||||||
|
|
||||||
/* Validate the bounds of the current pointed pointer */
|
/* Validate the bounds of the current pointed pointer */
|
||||||
if ((*(PULONG_PTR)CurrentOffset >= CsrThread->Process->ClientViewBase) &&
|
if ( (*(PULONG_PTR)CurrentOffset >= ((ULONG_PTR)ClientCaptureBuffer +
|
||||||
(*(PULONG_PTR)CurrentOffset < CsrThread->Process->ClientViewBounds))
|
SizeOfBufferThroughOffsetsArray)) &&
|
||||||
|
(*(PULONG_PTR)CurrentOffset <= (EndOfClientBuffer - sizeof(PVOID))) )
|
||||||
{
|
{
|
||||||
/* Modify the pointed pointer to take into account its new position */
|
/* Modify the pointed pointer to take into account its new position */
|
||||||
*(PULONG_PTR)CurrentOffset += BufferDistance;
|
*(PULONG_PTR)CurrentOffset += BufferDistance;
|
||||||
|
@ -1210,6 +1288,7 @@ CsrCaptureArguments(IN PCSR_THREAD CsrThread,
|
||||||
#endif
|
#endif
|
||||||
/* Invalid pointer, fail */
|
/* Invalid pointer, fail */
|
||||||
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
ApiMessage->Status = STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1278,7 +1357,7 @@ CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All the pointer offsets correspond to pointers which point
|
* All the pointer offsets correspond to pointers which point
|
||||||
* to the client data buffer instead of the server one (revert
|
* to the client data buffer instead of the server one (reverse
|
||||||
* the logic of CsrCaptureArguments()).
|
* the logic of CsrCaptureArguments()).
|
||||||
*/
|
*/
|
||||||
PointerCount = ServerCaptureBuffer->PointerCount;
|
PointerCount = ServerCaptureBuffer->PointerCount;
|
||||||
|
@ -1299,8 +1378,21 @@ CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
|
||||||
++OffsetPointer;
|
++OffsetPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the data back */
|
/* Copy the data back into the client buffer */
|
||||||
RtlMoveMemory(ClientCaptureBuffer, ServerCaptureBuffer, ServerCaptureBuffer->Size);
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
RtlMoveMemory(ClientCaptureBuffer, ServerCaptureBuffer, ServerCaptureBuffer->Size);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
#ifdef CSR_DBG
|
||||||
|
DPRINT1("*** CSRSS: Took exception during release %x\n", _SEH2_GetExceptionCode());
|
||||||
|
if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
|
||||||
|
#endif
|
||||||
|
/* Return failure */
|
||||||
|
ApiMessage->Status = _SEH2_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
/* Free our allocated buffer */
|
/* Free our allocated buffer */
|
||||||
RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
|
RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue