Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/lpc/reply.c * PURPOSE: Local Procedure Call: Receive (Replies) * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* PRIVATE FUNCTIONS *********************************************************/
VOIDNTAPILpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port, IN ULONG MessageId, IN ULONG CallbackId, IN CLIENT_ID ClientId){ PLPCP_MESSAGE Message; PLIST_ENTRY ListHead, NextEntry;
/* Check if the port we want is the connection port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) { /* Use it */ Port = Port->ConnectionPort; if (!Port) return; }
/* Loop the list */ ListHead = &Port->LpcDataInfoChainHead; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the message */ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
/* Make sure it matches */ if ((Message->Request.MessageId == MessageId) && (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread) && (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess)) { /* Unlink and free it */ RemoveEntryList(&Message->Entry); InitializeListHead(&Message->Entry); LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); break; }
/* Go to the next entry */ NextEntry = NextEntry->Flink; }}
VOIDNTAPILpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port, IN PLPCP_MESSAGE Message, IN ULONG LockFlags){ BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
PAGED_CODE();
/* Acquire the lock */ if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
/* Check if the port we want is the connection port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) { /* Use it */ Port = Port->ConnectionPort; if (!Port) { /* Release the lock and return */ if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock); return; } }
/* Link the message */ InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
/* Release the lock */ if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);}
PLPCP_MESSAGENTAPILpcpFindDataInfoMessage( IN PLPCP_PORT_OBJECT Port, IN ULONG MessageId, IN LPC_CLIENT_ID ClientId){ PLPCP_MESSAGE Message; PLIST_ENTRY ListEntry;
PAGED_CODE();
/* Check if the port we want is the connection port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) { /* Use it */ Port = Port->ConnectionPort; if (!Port) { /* Return NULL */ return NULL; } }
/* Loop all entries in the list */ for (ListEntry = Port->LpcDataInfoChainHead.Flink; ListEntry != &Port->LpcDataInfoChainHead; ListEntry = ListEntry->Flink) { Message = CONTAINING_RECORD(ListEntry, LPCP_MESSAGE, Entry);
/* Check if this is the desired message */ if ((Message->Request.MessageId == MessageId) && (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess) && (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread)) { /* It is, return it */ return Message; } }
return NULL;}
VOIDNTAPILpcpMoveMessage(IN PPORT_MESSAGE Destination, IN PPORT_MESSAGE Origin, IN PVOID Data, IN ULONG MessageType, IN PCLIENT_ID ClientId){ LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG), "Destination/Origin: %p/%p. Data: %p. Length: %lx\n", Destination, Origin, Data, Origin->u1.Length);
/* Set the Message size */ Destination->u1.Length = Origin->u1.Length;
/* Set the Message Type */ Destination->u2.s2.Type = !MessageType ? Origin->u2.s2.Type : MessageType & 0xFFFF;
/* Check if we have a Client ID */ if (ClientId) { /* Set the Client ID */ Destination->ClientId.UniqueProcess = ClientId->UniqueProcess; Destination->ClientId.UniqueThread = ClientId->UniqueThread; } else { /* Otherwise, copy it */ Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess; Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread; }
/* Copy the MessageId and ClientViewSize */ Destination->MessageId = Origin->MessageId; Destination->ClientViewSize = Origin->ClientViewSize;
/* Copy the Message Data */ RtlCopyMemory(Destination + 1, Data, ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG)));}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPINtReplyPort(IN HANDLE PortHandle, IN PPORT_MESSAGE ReplyMessage){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); PORT_MESSAGE CapturedReplyMessage; PLPCP_PORT_OBJECT Port; PLPCP_MESSAGE Message; PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
PAGED_CODE(); LPCTRACE(LPC_REPLY_DEBUG, "Handle: %p. Message: %p.\n", PortHandle, ReplyMessage);
/* Check if the call comes from user mode */ if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG)); CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { CapturedReplyMessage = *ReplyMessage; }
/* Validate its length */ if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) > (ULONG)CapturedReplyMessage.u1.s1.TotalLength) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Make sure it has a valid ID */ if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
/* Get the Port object */ Status = ObReferenceObjectByHandle(PortHandle, 0, LpcPortObjectType, PreviousMode, (PVOID*)&Port, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Validate its length in respect to the port object */ if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) || ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) { /* Too large, fail */ ObDereferenceObject(Port); return STATUS_PORT_MESSAGE_TOO_LONG; }
/* Get the ETHREAD corresponding to it */ Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId, NULL, &WakeupThread); if (!NT_SUCCESS(Status)) { /* No thread found, fail */ ObDereferenceObject(Port); return Status; }
/* Allocate a message from the port zone */ Message = LpcpAllocateFromPortZone(); if (!Message) { /* Fail if we couldn't allocate a message */ ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); return STATUS_NO_MEMORY; }
/* Keep the lock acquired */ KeAcquireGuardedMutex(&LpcpLock);
/* Make sure this is the reply the thread is waiting for */ if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) || ((LpcpGetMessageFromThread(WakeupThread)) && (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request) != LPC_REQUEST))) { /* It isn't, fail */ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); return STATUS_REPLY_MESSAGE_MISMATCH; }
/* Copy the message */ _SEH2_TRY { LpcpMoveMessage(&Message->Request, &CapturedReplyMessage, ReplyMessage + 1, LPC_REPLY, NULL); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Cleanup and return the exception code */ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Reference the thread while we use it */ ObReferenceObject(WakeupThread); Message->RepliedToThread = WakeupThread;
/* Set this as the reply message */ WakeupThread->LpcReplyMessageId = 0; WakeupThread->LpcReplyMessage = (PVOID)Message;
/* Check if we have messages on the reply chain */ if (!(WakeupThread->LpcExitThreadCalled) && !(IsListEmpty(&WakeupThread->LpcReplyChain))) { /* Remove us from it and reinitialize it */ RemoveEntryList(&WakeupThread->LpcReplyChain); InitializeListHead(&WakeupThread->LpcReplyChain); }
/* Check if this is the message the thread had received */ if ((Thread->LpcReceivedMsgIdValid) && (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { /* Clear this data */ Thread->LpcReceivedMessageId = 0; Thread->LpcReceivedMsgIdValid = FALSE; }
/* Free any data information */ LpcpFreeDataInfoMessage(Port, CapturedReplyMessage.MessageId, CapturedReplyMessage.CallbackId, CapturedReplyMessage.ClientId);
/* Release the lock and release the LPC semaphore to wake up waiters */ KeReleaseGuardedMutex(&LpcpLock); LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
/* Now we can let go of the thread */ ObDereferenceObject(WakeupThread);
/* Dereference port object */ ObDereferenceObject(Port); return Status;}
/* * @implemented */NTSTATUSNTAPINtReplyWaitReceivePortEx(IN HANDLE PortHandle, OUT PVOID *PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage OPTIONAL, OUT PPORT_MESSAGE ReceiveMessage, IN PLARGE_INTEGER Timeout OPTIONAL){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode; PORT_MESSAGE CapturedReplyMessage; LARGE_INTEGER CapturedTimeout; PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL; PLPCP_MESSAGE Message; PETHREAD Thread = PsGetCurrentThread(), WakeupThread; PLPCP_CONNECTION_MESSAGE ConnectMessage; ULONG ConnectionInfoLength;
PAGED_CODE(); LPCTRACE(LPC_REPLY_DEBUG, "Handle: %p. Messages: %p/%p. Context: %p\n", PortHandle, ReplyMessage, ReceiveMessage, PortContext);
/* Check if the call comes from user mode */ if (PreviousMode != KernelMode) { _SEH2_TRY { if (PortContext != NULL) ProbeForWritePointer(PortContext);
if (ReplyMessage != NULL) { ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG)); CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage; }
if (Timeout != NULL) { ProbeForReadLargeInteger(Timeout); CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout; Timeout = &CapturedTimeout; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* If this is a system thread, then let it page out its stack */ if (Thread->SystemThread) WaitMode = UserMode;
if (ReplyMessage != NULL) CapturedReplyMessage = *ReplyMessage; }
/* Check if caller has a reply message */ if (ReplyMessage) { /* Validate its length */ if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) > (ULONG)CapturedReplyMessage.u1.s1.TotalLength) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Make sure it has a valid ID */ if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER; }
/* Get the Port object */ Status = ObReferenceObjectByHandle(PortHandle, 0, LpcPortObjectType, PreviousMode, (PVOID*)&Port, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Check if the caller has a reply message */ if (ReplyMessage) { /* Validate its length in respect to the port object */ if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) || ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) { /* Too large, fail */ ObDereferenceObject(Port); return STATUS_PORT_MESSAGE_TOO_LONG; } }
/* Check if this is anything but a client port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT) { /* Check if this is the connection port */ if (Port->ConnectionPort == Port) { /* Use this port */ ConnectionPort = ReceivePort = Port; ObReferenceObject(ConnectionPort); } else { /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock);
/* Get the port */ ConnectionPort = ReceivePort = Port->ConnectionPort; if (!ConnectionPort) { /* Fail */ KeReleaseGuardedMutex(&LpcpLock); ObDereferenceObject(Port); return STATUS_PORT_DISCONNECTED; }
/* Release lock and reference */ ObReferenceObject(ConnectionPort); KeReleaseGuardedMutex(&LpcpLock); } } else { /* Otherwise, use the port itself */ ReceivePort = Port; }
/* Check if the caller gave a reply message */ if (ReplyMessage) { /* Get the ETHREAD corresponding to it */ Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId, NULL, &WakeupThread); if (!NT_SUCCESS(Status)) { /* No thread found, fail */ ObDereferenceObject(Port); if (ConnectionPort) ObDereferenceObject(ConnectionPort); return Status; }
/* Allocate a message from the port zone */ Message = LpcpAllocateFromPortZone(); if (!Message) { /* Fail if we couldn't allocate a message */ if (ConnectionPort) ObDereferenceObject(ConnectionPort); ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); return STATUS_NO_MEMORY; }
/* Keep the lock acquired */ KeAcquireGuardedMutex(&LpcpLock);
/* Make sure this is the reply the thread is waiting for */ if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) || ((LpcpGetMessageFromThread(WakeupThread)) && (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request) != LPC_REQUEST))) { /* It isn't, fail */ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); if (ConnectionPort) ObDereferenceObject(ConnectionPort); ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); return STATUS_REPLY_MESSAGE_MISMATCH; }
/* Copy the message */ _SEH2_TRY { LpcpMoveMessage(&Message->Request, &CapturedReplyMessage, ReplyMessage + 1, LPC_REPLY, NULL); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Cleanup and return the exception code */ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); if (ConnectionPort) ObDereferenceObject(ConnectionPort); ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Reference the thread while we use it */ ObReferenceObject(WakeupThread); Message->RepliedToThread = WakeupThread;
/* Set this as the reply message */ WakeupThread->LpcReplyMessageId = 0; WakeupThread->LpcReplyMessage = (PVOID)Message;
/* Check if we have messages on the reply chain */ if (!(WakeupThread->LpcExitThreadCalled) && !(IsListEmpty(&WakeupThread->LpcReplyChain))) { /* Remove us from it and reinitialize it */ RemoveEntryList(&WakeupThread->LpcReplyChain); InitializeListHead(&WakeupThread->LpcReplyChain); }
/* Check if this is the message the thread had received */ if ((Thread->LpcReceivedMsgIdValid) && (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { /* Clear this data */ Thread->LpcReceivedMessageId = 0; Thread->LpcReceivedMsgIdValid = FALSE; }
/* Free any data information */ LpcpFreeDataInfoMessage(Port, CapturedReplyMessage.MessageId, CapturedReplyMessage.CallbackId, CapturedReplyMessage.ClientId);
/* Release the lock and release the LPC semaphore to wake up waiters */ KeReleaseGuardedMutex(&LpcpLock); LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
/* Now we can let go of the thread */ ObDereferenceObject(WakeupThread); }
/* Now wait for someone to reply to us */ LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode); if (Status != STATUS_SUCCESS) goto Cleanup;
/* Wait done, get the LPC lock */ KeAcquireGuardedMutex(&LpcpLock);
/* Check if we've received nothing */ if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead)) { /* Check if this was a waitable port and wake it */ if (ReceivePort->Flags & LPCP_WAITABLE_PORT) { /* Reset its event */ KeClearEvent(&ReceivePort->WaitEvent); }
/* Release the lock and fail */ KeReleaseGuardedMutex(&LpcpLock); if (ConnectionPort) ObDereferenceObject(ConnectionPort); ObDereferenceObject(Port); return STATUS_UNSUCCESSFUL; }
/* Get the message on the queue */ Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead), LPCP_MESSAGE, Entry);
/* Check if the queue is empty now */ if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead)) { /* Check if this was a waitable port */ if (ReceivePort->Flags & LPCP_WAITABLE_PORT) { /* Reset its event */ KeClearEvent(&ReceivePort->WaitEvent); } }
/* Re-initialize the message's list entry */ InitializeListHead(&Message->Entry);
/* Set this as the received message */ Thread->LpcReceivedMessageId = Message->Request.MessageId; Thread->LpcReceivedMsgIdValid = TRUE;
_SEH2_TRY { /* Check if this was a connection request */ if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST) { /* Get the connection message */ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); LPCTRACE(LPC_REPLY_DEBUG, "Request Messages: %p/%p\n", Message, ConnectMessage);
/* Get its length */ ConnectionInfoLength = Message->Request.u1.s1.DataLength - sizeof(LPCP_CONNECTION_MESSAGE);
/* Return it as the receive message */ *ReceiveMessage = Message->Request;
/* Clear our stack variable so the message doesn't get freed */ Message = NULL;
/* Setup the receive message */ ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(PORT_MESSAGE) + ConnectionInfoLength); ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength; RtlCopyMemory(ReceiveMessage + 1, ConnectMessage + 1, ConnectionInfoLength);
/* Clear the port context if the caller requested one */ if (PortContext) *PortContext = NULL; } else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY) { /* Otherwise, this is a new message or event */ LPCTRACE(LPC_REPLY_DEBUG, "Non-Reply Messages: %p/%p\n", &Message->Request, (&Message->Request) + 1);
/* Copy it */ LpcpMoveMessage(ReceiveMessage, &Message->Request, (&Message->Request) + 1, 0, NULL);
/* Return its context */ if (PortContext) *PortContext = Message->PortContext;
/* And check if it has data information */ if (Message->Request.u2.s2.DataInfoOffset) { /* It does, save it, and don't free the message below */ LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD); Message = NULL; } } else { /* This is a reply message, should never happen! */ ASSERT(FALSE); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* Check if we have a message pointer here */ if (Message) { /* Free it and release the lock */ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); } else { /* Just release the lock */ KeReleaseGuardedMutex(&LpcpLock); }
Cleanup: /* All done, dereference the port and return the status */ LPCTRACE(LPC_REPLY_DEBUG, "Port: %p. Status: %d\n", Port, Status); if (ConnectionPort) ObDereferenceObject(ConnectionPort); ObDereferenceObject(Port); return Status;}
/* * @implemented */NTSTATUSNTAPINtReplyWaitReceivePort(IN HANDLE PortHandle, OUT PVOID *PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage OPTIONAL, OUT PPORT_MESSAGE ReceiveMessage){ /* Call the newer API */ return NtReplyWaitReceivePortEx(PortHandle, PortContext, ReplyMessage, ReceiveMessage, NULL);}
/* * @unimplemented */NTSTATUSNTAPINtReplyWaitReplyPort(IN HANDLE PortHandle, IN PPORT_MESSAGE ReplyMessage){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPILpcpCopyRequestData( IN BOOLEAN Write, IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG Index, IN PVOID Buffer, IN ULONG BufferLength, OUT PULONG ReturnLength){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); PORT_MESSAGE CapturedMessage; PLPCP_PORT_OBJECT Port = NULL; PETHREAD ClientThread = NULL; SIZE_T LocalReturnLength; PLPCP_MESSAGE InfoMessage; PLPCP_DATA_INFO DataInfo; PVOID DataInfoBaseAddress;
PAGED_CODE();
/* Check if the call comes from user mode */ if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForRead(Message, sizeof(*Message), sizeof(PVOID)); CapturedMessage = *(volatile PORT_MESSAGE*)Message; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { CapturedMessage = *Message; }
/* Make sure there is any data to copy */ if (CapturedMessage.u2.s2.DataInfoOffset == 0) { return STATUS_INVALID_PARAMETER; }
/* Reference the port handle */ Status = ObReferenceObjectByHandle(PortHandle, PORT_ALL_ACCESS, LpcPortObjectType, PreviousMode, (PVOID*)&Port, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to reference port handle: 0x%ls\n", Status); return Status; }
/* Look up the client thread */ Status = PsLookupProcessThreadByCid(&CapturedMessage.ClientId, NULL, &ClientThread); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n", CapturedMessage.ClientId.UniqueProcess, CapturedMessage.ClientId.UniqueThread, Status); goto Cleanup; }
/* Acquire the global LPC lock */ KeAcquireGuardedMutex(&LpcpLock);
/* Check for message id mismatch */ if ((ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) || (CapturedMessage.MessageId == 0)) { DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n", ClientThread->LpcReplyMessageId, CapturedMessage.MessageId); Status = STATUS_REPLY_MESSAGE_MISMATCH; goto CleanupWithLock; }
/* Validate the port */ if (!LpcpValidateClientPort(ClientThread, Port)) { DPRINT1("LpcpValidateClientPort failed\n"); Status = STATUS_REPLY_MESSAGE_MISMATCH; goto CleanupWithLock; }
/* Find the message with the data */ InfoMessage = LpcpFindDataInfoMessage(Port, CapturedMessage.MessageId, CapturedMessage.ClientId); if (InfoMessage == NULL) { DPRINT1("LpcpFindDataInfoMessage failed\n"); Status = STATUS_INVALID_PARAMETER; goto CleanupWithLock; }
/* Get the data info */ DataInfo = LpcpGetDataInfoFromMessage(&InfoMessage->Request);
/* Check if the index is within bounds */ if (Index >= DataInfo->NumberOfEntries) { DPRINT1("Message data index %lu out of bounds (%lu in msg)\n", Index, DataInfo->NumberOfEntries); Status = STATUS_INVALID_PARAMETER; goto CleanupWithLock; }
/* Check if the caller wants to read/write more data than expected */ if (BufferLength > DataInfo->Entries[Index].DataLength) { DPRINT1("Trying to read more data (%lu) than available (%lu)\n", BufferLength, DataInfo->Entries[Index].DataLength); Status = STATUS_INVALID_PARAMETER; goto CleanupWithLock; }
/* Get the data pointer */ DataInfoBaseAddress = DataInfo->Entries[Index].BaseAddress;
/* Release the lock */ KeReleaseGuardedMutex(&LpcpLock);
if (Write) { /* Copy data from the caller to the message sender */ Status = MmCopyVirtualMemory(PsGetCurrentProcess(), Buffer, ClientThread->ThreadsProcess, DataInfoBaseAddress, BufferLength, PreviousMode, &LocalReturnLength); } else { /* Copy data from the message sender to the caller */ Status = MmCopyVirtualMemory(ClientThread->ThreadsProcess, DataInfoBaseAddress, PsGetCurrentProcess(), Buffer, BufferLength, PreviousMode, &LocalReturnLength); }
if (!NT_SUCCESS(Status)) { DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status); goto Cleanup; }
/* Check if the caller asked to return the copied length */ if (ReturnLength != NULL) { _SEH2_TRY { *ReturnLength = LocalReturnLength; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Ignore */ DPRINT1("Exception writing ReturnLength, ignoring\n"); } _SEH2_END; }
Cleanup:
if (ClientThread != NULL) ObDereferenceObject(ClientThread);
ObDereferenceObject(Port);
return Status;
CleanupWithLock:
/* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); goto Cleanup;}
/* * @implemented */NTSTATUSNTAPINtReadRequestData(IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG Index, IN PVOID Buffer, IN ULONG BufferLength, OUT PULONG ReturnLength){ /* Call the internal function */ return LpcpCopyRequestData(FALSE, PortHandle, Message, Index, Buffer, BufferLength, ReturnLength);}
/* * @implemented */NTSTATUSNTAPINtWriteRequestData(IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG Index, IN PVOID Buffer, IN ULONG BufferLength, OUT PULONG ReturnLength){ /* Call the internal function */ return LpcpCopyRequestData(TRUE, PortHandle, Message, Index, Buffer, BufferLength, ReturnLength);}
/* EOF */