Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

386 lines
13 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
lpcrecv.c
Abstract:
Local Inter-Process Communication (LPC) receive system services.
Author:
Steve Wood (stevewo) 15-May-1989
Revision History:
--*/
#include "lpcp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,NtReplyWaitReceivePort)
#endif
NTSTATUS
NtReplyWaitReceivePort(
IN HANDLE PortHandle,
OUT PVOID *PortContext OPTIONAL,
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
OUT PPORT_MESSAGE ReceiveMessage
)
{
PLPCP_PORT_OBJECT PortObject;
PLPCP_PORT_OBJECT ReceivePort;
PORT_MESSAGE CapturedReplyMessage;
KPROCESSOR_MODE PreviousMode;
KPROCESSOR_MODE WaitMode;
NTSTATUS Status;
PLPCP_MESSAGE Msg;
PETHREAD CurrentThread;
PETHREAD WakeupThread;
PAGED_CODE();
CurrentThread = PsGetCurrentThread();
//
// Get previous processor mode
//
PreviousMode = KeGetPreviousMode();
WaitMode = PreviousMode;
if (PreviousMode != KernelMode) {
try {
if (ARGUMENT_PRESENT( PortContext )) {
ProbeForWriteUlong( (PULONG)PortContext );
}
if (ARGUMENT_PRESENT( ReplyMessage)) {
ProbeForRead( ReplyMessage,
sizeof( *ReplyMessage ),
sizeof( ULONG )
);
CapturedReplyMessage = *ReplyMessage;
}
ProbeForWrite( ReceiveMessage,
sizeof( *ReceiveMessage ),
sizeof( ULONG )
);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
return( GetExceptionCode() );
}
}
else {
//
// Kernel mode threads call with wait mode of user so that their kernel
// stacks are swappable. Main consumer of this is SepRmCommandThread
//
if ( IS_SYSTEM_THREAD(CurrentThread) ) {
WaitMode = UserMode;
}
if (ARGUMENT_PRESENT( ReplyMessage)) {
CapturedReplyMessage = *ReplyMessage;
}
}
//
// Reference the port object by handle
//
Status = LpcpReferencePortObject( PortHandle,
0,
PreviousMode,
&PortObject
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
if ((PortObject->Flags & PORT_TYPE) != CLIENT_COMMUNICATION_PORT) {
ReceivePort = PortObject->ConnectionPort;
}
else {
ReceivePort = PortObject;
}
//
// If ReplyMessage argument present, then send reply
//
if (ARGUMENT_PRESENT( ReplyMessage )) {
//
// 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 global Lpc 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 );
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 ReplyWaitReceive 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.%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
PsGetCurrentProcess()->ImageFileName,
Msg,
CapturedReplyMessage.MessageId,
CapturedReplyMessage.CallbackId,
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;
}
LpcpTrace(( "%s Waiting for message to Port %x (%s)\n",
PsGetCurrentProcess()->ImageFileName,
ReceivePort,
LpcpGetCreatorName( ReceivePort )
));
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(); // FIX, FIX
}
//
// Wake up the thread that is waiting for an answer to its request
// inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort
//
Status = KeReleaseWaitForSemaphore( &WakeupThread->LpcReplySemaphore,
ReceivePort->MsgQueue.Semaphore,
WrLpcReceive,
WaitMode
);
//
// Fall into receive code. Client thread reference will be
// returned by the client when it wakes up.
//
}
else {
//
// Wait for a message
//
LpcpTrace(( "%s Waiting for message to Port %x (%s)\n",
PsGetCurrentProcess()->ImageFileName,
ReceivePort,
LpcpGetCreatorName( ReceivePort )
));
Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore,
WrLpcReceive,
WaitMode,
FALSE,
NULL
);
}
if (Status == STATUS_SUCCESS) {
ExAcquireFastMutex( &LpcpLock );
if (IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead )) {
ExReleaseFastMutex( &LpcpLock );
ObDereferenceObject( PortObject );
return( STATUS_UNSUCCESSFUL );
}
Msg = (PLPCP_MESSAGE)RemoveHeadList( &ReceivePort->MsgQueue.ReceiveHead );
InitializeListHead( &Msg->Entry );
LpcpTrace(( "%s Receive Msg %lx (%u) from Port %lx (%s)\n",
PsGetCurrentProcess()->ImageFileName,
Msg,
Msg->Request.MessageId,
ReceivePort,
LpcpGetCreatorName( ReceivePort )
));
CurrentThread->LpcReceivedMessageId = Msg->Request.MessageId;
CurrentThread->LpcReceivedMsgIdValid = TRUE;
ExReleaseFastMutex( &LpcpLock );
try {
if (Msg->Request.u2.s2.Type == LPC_CONNECTION_REQUEST) {
PLPCP_CONNECTION_MESSAGE ConnectMsg;
ULONG ConnectionInfoLength;
ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
ConnectionInfoLength = Msg->Request.u1.s1.DataLength -
sizeof( *ConnectMsg );
*ReceiveMessage = Msg->Request;
ReceiveMessage->u1.s1.TotalLength = sizeof( *ReceiveMessage ) +
ConnectionInfoLength;
ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
RtlMoveMemory( ReceiveMessage+1,
ConnectMsg + 1,
ConnectionInfoLength
);
if (ARGUMENT_PRESENT( PortContext )) {
*PortContext = NULL;
}
//
// Dont free message until NtAcceptConnectPort called.
//
Msg = NULL;
}
else
if (Msg->Request.u2.s2.Type != LPC_REPLY) {
LpcpMoveMessage( ReceiveMessage,
&Msg->Request,
(&Msg->Request) + 1,
0,
NULL
);
if (ARGUMENT_PRESENT( PortContext )) {
*PortContext = Msg->PortContext;
}
//
// If message contains DataInfo for access via NtRead/WriteRequestData
// then put the message on a list in the communication port and dont
// free it. It will be freed when the server replies to the message.
//
if (Msg->Request.u2.s2.DataInfoOffset != 0) {
LpcpSaveDataInfoMessage( PortObject, Msg );
Msg = NULL;
}
}
else {
LpcpPrint(( "LPC: Bogus reply message (%08x) in receive queue of connection port %08x\n",
Msg, ReceivePort
));
KdBreakPoint();
}
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Status = GetExceptionCode(); // FIX, FIX
}
//
// Acquire the LPC mutex and decrement the reference count for the
// message. If the reference count goes to zero the message will be
// deleted.
//
if (Msg != NULL) {
LpcpFreeToPortZone( Msg, FALSE );
}
}
ObDereferenceObject( PortObject );
return( Status );
}