mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
762 lines
23 KiB
762 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
lpcreply.c
|
|
|
|
Abstract:
|
|
|
|
Local Inter-Process Communication (LPC) reply system services.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 15-May-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "lpcp.h"
|
|
|
|
NTSTATUS
|
|
LpcpCopyRequestData(
|
|
IN BOOLEAN WriteToMessageData,
|
|
IN HANDLE PortHandle,
|
|
IN PPORT_MESSAGE Message,
|
|
IN ULONG DataEntryIndex,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG NumberOfBytesCopied OPTIONAL
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,NtReplyPort)
|
|
#pragma alloc_text(PAGE,NtReplyWaitReplyPort)
|
|
#pragma alloc_text(PAGE,NtReadRequestData)
|
|
#pragma alloc_text(PAGE,NtWriteRequestData)
|
|
#pragma alloc_text(PAGE,LpcpCopyRequestData)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NtReplyPort(
|
|
IN HANDLE PortHandle,
|
|
IN PPORT_MESSAGE ReplyMessage
|
|
)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PLPCP_PORT_OBJECT PortObject;
|
|
PORT_MESSAGE CapturedReplyMessage;
|
|
NTSTATUS Status;
|
|
PLPCP_MESSAGE Msg;
|
|
PETHREAD CurrentThread;
|
|
PETHREAD WakeupThread;
|
|
|
|
PAGED_CODE();
|
|
CurrentThread = PsGetCurrentThread();
|
|
|
|
//
|
|
// Get previous processor mode and probe output arguments if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForRead( ReplyMessage,
|
|
sizeof( *ReplyMessage ),
|
|
sizeof( ULONG )
|
|
);
|
|
CapturedReplyMessage = *ReplyMessage;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
return( GetExceptionCode() );
|
|
}
|
|
}
|
|
else {
|
|
CapturedReplyMessage = *ReplyMessage;
|
|
}
|
|
|
|
//
|
|
// Reference the port object by handle
|
|
//
|
|
|
|
Status = LpcpReferencePortObject( PortHandle,
|
|
0,
|
|
PreviousMode,
|
|
&PortObject
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Translate the ClientId from the connection request into a
|
|
// thread pointer. This is a referenced pointer to keep the thread
|
|
// from evaporating out from under us.
|
|
//
|
|
|
|
Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
|
|
NULL,
|
|
&WakeupThread
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Acquire the mutex that gaurds the LpcReplyMessage field of
|
|
// the thread and get the pointer to the message that the thread
|
|
// is waiting for a reply to.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
|
|
if (Msg == NULL) {
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ObDereferenceObject( WakeupThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
//
|
|
// See if the thread is waiting for a reply to the message
|
|
// specified on this call. If not then a bogus message
|
|
// has been specified, so release the mutex, dereference the thread
|
|
// and return failure.
|
|
//
|
|
|
|
if (WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) {
|
|
LpcpPrint(( "%s Attempted reply to Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
WakeupThread,
|
|
THREAD_TO_PROCESS( WakeupThread )->ImageFileName
|
|
));
|
|
LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n",
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.ClientId.UniqueProcess,
|
|
CapturedReplyMessage.ClientId.UniqueThread
|
|
));
|
|
LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n",
|
|
WakeupThread->LpcReplyMessageId,
|
|
WakeupThread->Cid.UniqueProcess,
|
|
WakeupThread->Cid.UniqueThread
|
|
));
|
|
#if DBG
|
|
if (LpcpStopOnReplyMismatch) {
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
LpcpFreeToPortZone( Msg, TRUE );
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ObDereferenceObject( WakeupThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_REPLY_MESSAGE_MISMATCH );
|
|
}
|
|
|
|
LpcpTrace(( "%s Sending Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
Msg,
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.u2.s2.DataInfoOffset,
|
|
*((PULONG)(Msg+1)+0),
|
|
*((PULONG)(Msg+1)+1),
|
|
*((PULONG)(Msg+1)+2),
|
|
*((PULONG)(Msg+1)+3),
|
|
WakeupThread,
|
|
THREAD_TO_PROCESS( WakeupThread )->ImageFileName
|
|
));
|
|
|
|
if (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) {
|
|
LpcpFreeDataInfoMessage( PortObject,
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.CallbackId
|
|
);
|
|
}
|
|
|
|
//
|
|
// Release the mutex that guards the LpcReplyMessage field
|
|
// after marking message as being replied to.
|
|
//
|
|
|
|
Msg->RepliedToThread = WakeupThread;
|
|
WakeupThread->LpcReplyMessageId = 0;
|
|
WakeupThread->LpcReplyMessage = (PVOID)Msg;
|
|
|
|
//
|
|
// Remove the thread from the reply rundown list as we are sending the reply.
|
|
//
|
|
if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
|
|
RemoveEntryList( &WakeupThread->LpcReplyChain );
|
|
InitializeListHead( &WakeupThread->LpcReplyChain );
|
|
}
|
|
|
|
if (CurrentThread->LpcReceivedMsgIdValid &&
|
|
CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId
|
|
) {
|
|
CurrentThread->LpcReceivedMessageId = 0;
|
|
CurrentThread->LpcReceivedMsgIdValid = FALSE;
|
|
}
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
//
|
|
// Copy the reply message to the request message buffer
|
|
//
|
|
try {
|
|
LpcpMoveMessage( &Msg->Request,
|
|
&CapturedReplyMessage,
|
|
(ReplyMessage + 1),
|
|
LPC_REPLY,
|
|
NULL
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
//
|
|
// Wake up the thread that is waiting for an answer to its request
|
|
// inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That
|
|
// will dereference itself when it wakes up.
|
|
//
|
|
|
|
KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore,
|
|
0,
|
|
1L,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Dereference port object and return the system service status.
|
|
//
|
|
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtReplyWaitReplyPort(
|
|
IN HANDLE PortHandle,
|
|
IN OUT PPORT_MESSAGE ReplyMessage
|
|
)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
PLPCP_PORT_OBJECT PortObject;
|
|
PORT_MESSAGE CapturedReplyMessage;
|
|
PLPCP_MESSAGE Msg;
|
|
PETHREAD CurrentThread;
|
|
PETHREAD WakeupThread;
|
|
|
|
PAGED_CODE();
|
|
CurrentThread = PsGetCurrentThread();
|
|
|
|
//
|
|
// Get previous processor mode and probe output arguments if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForRead( ReplyMessage,
|
|
sizeof( *ReplyMessage ),
|
|
sizeof( ULONG )
|
|
);
|
|
CapturedReplyMessage = *ReplyMessage;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
return( GetExceptionCode() );
|
|
}
|
|
}
|
|
else {
|
|
CapturedReplyMessage = *ReplyMessage;
|
|
}
|
|
|
|
//
|
|
// Reference the communication port object by handle. Return status if
|
|
// unsuccessful.
|
|
//
|
|
|
|
Status = LpcpReferencePortObject( PortHandle,
|
|
0,
|
|
PreviousMode,
|
|
&PortObject
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
|
|
//
|
|
// Translate the ClientId from the connection request into a
|
|
// thread pointer. This is a referenced pointer to keep the thread
|
|
// from evaporating out from under us.
|
|
//
|
|
|
|
Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
|
|
NULL,
|
|
&WakeupThread
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Acquire the mutex that gaurds the LpcReplyMessage field of
|
|
// the thread and get the pointer to the message that the thread
|
|
// is waiting for a reply to.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
|
|
if (Msg == NULL) {
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ObDereferenceObject( WakeupThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
//
|
|
// See if the thread is waiting for a reply to the message
|
|
// specified on this call. If not then a bogus message
|
|
// has been specified, so release the mutex, dereference the thread
|
|
// and return failure.
|
|
//
|
|
|
|
if (WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) {
|
|
LpcpPrint(( "%s Attempted reply wait reply to Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
WakeupThread,
|
|
THREAD_TO_PROCESS( WakeupThread )->ImageFileName
|
|
));
|
|
LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n",
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.ClientId.UniqueProcess,
|
|
CapturedReplyMessage.ClientId.UniqueThread
|
|
));
|
|
LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n",
|
|
WakeupThread->LpcReplyMessageId,
|
|
WakeupThread->Cid.UniqueProcess,
|
|
WakeupThread->Cid.UniqueThread
|
|
));
|
|
#if DBG
|
|
if (LpcpStopOnReplyMismatch) {
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
LpcpFreeToPortZone( Msg, TRUE );
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ObDereferenceObject( WakeupThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_REPLY_MESSAGE_MISMATCH );
|
|
}
|
|
|
|
|
|
LpcpTrace(( "%s Sending Reply Wait Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
Msg,
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.u2.s2.DataInfoOffset,
|
|
*((PULONG)(Msg+1)+0),
|
|
*((PULONG)(Msg+1)+1),
|
|
*((PULONG)(Msg+1)+2),
|
|
*((PULONG)(Msg+1)+3),
|
|
WakeupThread,
|
|
THREAD_TO_PROCESS( WakeupThread )->ImageFileName
|
|
));
|
|
|
|
if (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) {
|
|
LpcpFreeDataInfoMessage( PortObject,
|
|
CapturedReplyMessage.MessageId,
|
|
CapturedReplyMessage.CallbackId
|
|
);
|
|
}
|
|
|
|
//
|
|
// Release the mutex that guards the LpcReplyMessage field
|
|
// after marking message as being replied to.
|
|
//
|
|
|
|
Msg->RepliedToThread = WakeupThread;
|
|
WakeupThread->LpcReplyMessageId = 0;
|
|
WakeupThread->LpcReplyMessage = (PVOID)Msg;
|
|
|
|
//
|
|
// Remove the thread from the reply rundown list as we are sending the reply.
|
|
//
|
|
if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
|
|
RemoveEntryList( &WakeupThread->LpcReplyChain );
|
|
InitializeListHead( &WakeupThread->LpcReplyChain );
|
|
}
|
|
|
|
CurrentThread->LpcReplyMessageId = CapturedReplyMessage.MessageId;
|
|
CurrentThread->LpcReplyMessage = NULL;
|
|
if (CurrentThread->LpcReceivedMsgIdValid &&
|
|
CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId
|
|
) {
|
|
CurrentThread->LpcReceivedMessageId = 0;
|
|
CurrentThread->LpcReceivedMsgIdValid = FALSE;
|
|
}
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
//
|
|
// Copy the reply message to the request message buffer
|
|
//
|
|
try {
|
|
LpcpMoveMessage( &Msg->Request,
|
|
&CapturedReplyMessage,
|
|
(ReplyMessage + 1),
|
|
LPC_REPLY,
|
|
NULL
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
ObDereferenceObject( WakeupThread );
|
|
ObDereferenceObject( PortObject );
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Wake up the thread that is waiting for an answer to its request
|
|
// inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That
|
|
// will dereference itself when it wakes up.
|
|
//
|
|
|
|
Status = KeReleaseWaitForSemaphore( &WakeupThread->LpcReplySemaphore,
|
|
&CurrentThread->LpcReplySemaphore,
|
|
Executive,
|
|
PreviousMode
|
|
);
|
|
if (Status == STATUS_USER_APC) {
|
|
//
|
|
// if the semaphore is signaled, then clear it
|
|
//
|
|
if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) {
|
|
KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore,
|
|
WrExecutive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the wait succeeded, copy the reply to the reply buffer.
|
|
//
|
|
|
|
if (Status == STATUS_SUCCESS ) {
|
|
|
|
//
|
|
// Acquire the mutex that gaurds the request message
|
|
// queue. Remove the request message from the list of
|
|
// messages being processed and free the message back to the queue's zone.
|
|
// If the zone's free list was zero before freeing this message then
|
|
// pulse the free event after free the message so that threads waiting
|
|
// to allocate a request message buffer will wake up. Finally,
|
|
// release the mutex and return the system service status.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
|
|
Msg = CurrentThread->LpcReplyMessage;
|
|
CurrentThread->LpcReplyMessage = NULL;
|
|
#if DBG
|
|
if (Msg != NULL) {
|
|
LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
Msg,
|
|
Msg->Request.MessageId,
|
|
*((PULONG)(Msg+1)+0),
|
|
*((PULONG)(Msg+1)+1),
|
|
*((PULONG)(Msg+1)+2),
|
|
*((PULONG)(Msg+1)+3),
|
|
CurrentThread,
|
|
THREAD_TO_PROCESS( CurrentThread )->ImageFileName
|
|
));
|
|
if (!IsListEmpty( &Msg->Entry )) {
|
|
LpcpTrace(( "Reply Msg %lx has non-empty list entry\n", Msg ));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
if (Msg != NULL) {
|
|
try {
|
|
LpcpMoveMessage( ReplyMessage,
|
|
&Msg->Request,
|
|
(&Msg->Request) + 1,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
//
|
|
// Acquire the LPC mutex and decrement the reference count for the
|
|
// message. If the reference count goes to zero the message will be
|
|
// deleted.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
|
|
if (Msg->RepliedToThread != NULL) {
|
|
ObDereferenceObject( Msg->RepliedToThread );
|
|
Msg->RepliedToThread = NULL;
|
|
}
|
|
|
|
LpcpFreeToPortZone( Msg, TRUE );
|
|
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
}
|
|
}
|
|
|
|
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtReadRequestData(
|
|
IN HANDLE PortHandle,
|
|
IN PPORT_MESSAGE Message,
|
|
IN ULONG DataEntryIndex,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG NumberOfBytesRead OPTIONAL
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return LpcpCopyRequestData( FALSE,
|
|
PortHandle,
|
|
Message,
|
|
DataEntryIndex,
|
|
Buffer,
|
|
BufferSize,
|
|
NumberOfBytesRead
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtWriteRequestData(
|
|
IN HANDLE PortHandle,
|
|
IN PPORT_MESSAGE Message,
|
|
IN ULONG DataEntryIndex,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG NumberOfBytesWritten OPTIONAL
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
return LpcpCopyRequestData( TRUE,
|
|
PortHandle,
|
|
Message,
|
|
DataEntryIndex,
|
|
Buffer,
|
|
BufferSize,
|
|
NumberOfBytesWritten
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LpcpCopyRequestData(
|
|
IN BOOLEAN WriteToMessageData,
|
|
IN HANDLE PortHandle,
|
|
IN PPORT_MESSAGE Message,
|
|
IN ULONG DataEntryIndex,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG NumberOfBytesCopied OPTIONAL
|
|
)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PLPCP_PORT_OBJECT PortObject;
|
|
PLPCP_MESSAGE Msg;
|
|
PLIST_ENTRY Head, Next;
|
|
NTSTATUS Status;
|
|
PETHREAD ClientThread;
|
|
PPORT_DATA_INFORMATION DataInfo;
|
|
PPORT_DATA_ENTRY DataEntry;
|
|
PORT_MESSAGE CapturedMessage;
|
|
PORT_DATA_INFORMATION CapturedDataInfo;
|
|
PORT_DATA_ENTRY CapturedDataEntry;
|
|
ULONG BytesCopied;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Get previous processor mode and probe output arguments if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
if (WriteToMessageData) {
|
|
ProbeForRead( Buffer,
|
|
BufferSize,
|
|
1
|
|
);
|
|
}
|
|
else {
|
|
ProbeForWrite( Buffer,
|
|
BufferSize,
|
|
1
|
|
);
|
|
}
|
|
|
|
ProbeForRead( Message,
|
|
sizeof( *Message ),
|
|
sizeof( ULONG )
|
|
);
|
|
CapturedMessage = *Message;
|
|
if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
|
|
ProbeForWriteUlong( NumberOfBytesCopied );
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
return( GetExceptionCode() );
|
|
}
|
|
}
|
|
else {
|
|
CapturedMessage = *Message;
|
|
}
|
|
|
|
if (CapturedMessage.u2.s2.DataInfoOffset == 0) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Reference the port object by handle
|
|
//
|
|
|
|
Status = LpcpReferencePortObject( PortHandle,
|
|
0,
|
|
PreviousMode,
|
|
&PortObject
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Translate the ClientId from the connection request into a
|
|
// thread pointer. This is a referenced pointer to keep the thread
|
|
// from evaporating out from under us.
|
|
//
|
|
|
|
Status = PsLookupProcessThreadByCid( &CapturedMessage.ClientId,
|
|
NULL,
|
|
&ClientThread
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Acquire the mutex that gaurds the LpcReplyMessage field of
|
|
// the thread and get the pointer to the message that the thread
|
|
// is waiting for a reply to.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
|
|
//
|
|
// See if the thread is waiting for a reply to the message
|
|
// specified on this call. If not then a bogus message
|
|
// has been specified, so release the mutex, dereference the thread
|
|
// and return failure.
|
|
//
|
|
|
|
if (ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) {
|
|
Status = STATUS_REPLY_MESSAGE_MISMATCH;
|
|
}
|
|
else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
Msg = LpcpFindDataInfoMessage( PortObject,
|
|
CapturedMessage.MessageId,
|
|
CapturedMessage.CallbackId
|
|
);
|
|
if (Msg != NULL) {
|
|
DataInfo = (PPORT_DATA_INFORMATION)((PUCHAR)&Msg->Request +
|
|
Msg->Request.u2.s2.DataInfoOffset
|
|
);
|
|
if (DataInfo->CountDataEntries > DataEntryIndex) {
|
|
DataEntry = &DataInfo->DataEntries[ DataEntryIndex ];
|
|
CapturedDataEntry = *DataEntry;
|
|
if (CapturedDataEntry.Size >= BufferSize) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ObDereferenceObject( ClientThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Release the mutex that guards the LpcReplyMessage field
|
|
//
|
|
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
|
|
//
|
|
// Copy the message data
|
|
//
|
|
|
|
if (WriteToMessageData) {
|
|
Status = MmCopyVirtualMemory( PsGetCurrentProcess(),
|
|
Buffer,
|
|
THREAD_TO_PROCESS( ClientThread ),
|
|
CapturedDataEntry.Base,
|
|
BufferSize,
|
|
PreviousMode,
|
|
&BytesCopied
|
|
);
|
|
}
|
|
else {
|
|
Status = MmCopyVirtualMemory( THREAD_TO_PROCESS( ClientThread ),
|
|
CapturedDataEntry.Base,
|
|
PsGetCurrentProcess(),
|
|
Buffer,
|
|
BufferSize,
|
|
PreviousMode,
|
|
&BytesCopied
|
|
);
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
|
|
try {
|
|
*NumberOfBytesCopied = BytesCopied;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
NOTHING;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dereference client thread and return the system service status.
|
|
//
|
|
|
|
ObDereferenceObject( ClientThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|