[NTOS:PNP] Avoid a fixed-length stack buffer in IopActionConfigureChildServices....
[reactos.git] / ntoskrnl / lpc / reply.c
index 3c3334c..8454754 100644 (file)
@@ -48,7 +48,7 @@ LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
             /* Unlink and free it */
             RemoveEntryList(&Message->Entry);
             InitializeListHead(&Message->Entry);
-            LpcpFreeToPortZone(Message, 1);
+            LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);
             break;
         }
 
@@ -61,8 +61,10 @@ VOID
 NTAPI
 LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
                         IN PLPCP_MESSAGE Message,
-                        IN ULONG LockHeld)
+                        IN ULONG LockFlags)
 {
+    BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
+
     PAGED_CODE();
 
     /* Acquire the lock */
@@ -88,6 +90,50 @@ LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
     if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
 }
 
+PLPCP_MESSAGE
+NTAPI
+LpcpFindDataInfoMessage(
+    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;
+}
+
 VOID
 NTAPI
 LpcpMoveMessage(IN PPORT_MESSAGE Destination,
@@ -96,13 +142,14 @@ LpcpMoveMessage(IN PPORT_MESSAGE Destination,
                 IN ULONG MessageType,
                 IN PCLIENT_ID ClientId)
 {
-    /* Set the Message size */
     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 */
@@ -130,7 +177,7 @@ LpcpMoveMessage(IN PPORT_MESSAGE Destination,
     /* Copy the Message Data */
     RtlCopyMemory(Destination + 1,
                   Data,
-                  ((Destination->u1.Length & 0xFFFF) + 3) &~3);
+                  ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG)));
 }
 
 /* PUBLIC FUNCTIONS **********************************************************/
@@ -143,46 +190,48 @@ NTAPI
 NtReplyPort(IN HANDLE PortHandle,
             IN PPORT_MESSAGE ReplyMessage)
 {
-    PLPCP_PORT_OBJECT Port, ConnectionPort = NULL;
-    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
     NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    PORT_MESSAGE CapturedReplyMessage;
+    PLPCP_PORT_OBJECT Port;
     PLPCP_MESSAGE Message;
     PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
-    //PORT_MESSAGE CapturedReplyMessage;
 
     PAGED_CODE();
     LPCTRACE(LPC_REPLY_DEBUG,
-             "Handle: %lx. Message: %p.\n",
+             "Handle: %p. Message: %p.\n",
              PortHandle,
              ReplyMessage);
 
-    if (KeGetPreviousMode() == UserMode)
+    /* Check if the call comes from user mode */
+    if (PreviousMode != KernelMode)
     {
         _SEH2_TRY
         {
-            ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
-            /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
-            ReplyMessage = &CapturedReplyMessage;*/
+            ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
+            CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
         }
-        _SEH2_EXCEPT(ExSystemExceptionFilter())
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            DPRINT1("SEH crash [1]\n");
-            DbgBreakPoint();
             _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
         _SEH2_END;
     }
+    else
+    {
+        CapturedReplyMessage = *ReplyMessage;
+    }
 
     /* Validate its length */
-    if (((ULONG)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
-        (ULONG)ReplyMessage->u1.s1.TotalLength)
+    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 (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
+    if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
 
     /* Get the Port object */
     Status = ObReferenceObjectByHandle(PortHandle,
@@ -194,9 +243,9 @@ NtReplyPort(IN HANDLE PortHandle,
     if (!NT_SUCCESS(Status)) return Status;
 
     /* Validate its length in respect to the port object */
-    if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
-        ((ULONG)ReplyMessage->u1.s1.TotalLength <=
-        (ULONG)ReplyMessage->u1.s1.DataLength))
+    if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
+        ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
+         (ULONG)CapturedReplyMessage.u1.s1.DataLength))
     {
         /* Too large, fail */
         ObDereferenceObject(Port);
@@ -204,14 +253,13 @@ NtReplyPort(IN HANDLE PortHandle,
     }
 
     /* Get the ETHREAD corresponding to it */
-    Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+    Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
                                         NULL,
                                         &WakeupThread);
     if (!NT_SUCCESS(Status))
     {
         /* No thread found, fail */
         ObDereferenceObject(Port);
-        if (ConnectionPort) ObDereferenceObject(ConnectionPort);
         return Status;
     }
 
@@ -220,7 +268,6 @@ NtReplyPort(IN HANDLE PortHandle,
     if (!Message)
     {
         /* Fail if we couldn't allocate a message */
-        if (ConnectionPort) ObDereferenceObject(ConnectionPort);
         ObDereferenceObject(WakeupThread);
         ObDereferenceObject(Port);
         return STATUS_NO_MEMORY;
@@ -230,14 +277,13 @@ NtReplyPort(IN HANDLE PortHandle,
     KeAcquireGuardedMutex(&LpcpLock);
 
     /* Make sure this is the reply the thread is waiting for */
-    if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
+    if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
         ((LpcpGetMessageFromThread(WakeupThread)) &&
-        (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
-        Request) != LPC_REQUEST)))
+        (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request)
+            != LPC_REQUEST)))
     {
         /* It isn't, fail */
-        LpcpFreeToPortZone(Message, 3);
-        if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+        LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
         ObDereferenceObject(WakeupThread);
         ObDereferenceObject(Port);
         return STATUS_REPLY_MESSAGE_MISMATCH;
@@ -247,15 +293,15 @@ NtReplyPort(IN HANDLE PortHandle,
     _SEH2_TRY
     {
         LpcpMoveMessage(&Message->Request,
-                        ReplyMessage,
+                        &CapturedReplyMessage,
                         ReplyMessage + 1,
                         LPC_REPLY,
                         NULL);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        /* Fail */
-        LpcpFreeToPortZone(Message, 3);
+        /* Cleanup and return the exception code */
+        LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
         ObDereferenceObject(WakeupThread);
         ObDereferenceObject(Port);
         _SEH2_YIELD(return _SEH2_GetExceptionCode());
@@ -281,7 +327,7 @@ NtReplyPort(IN HANDLE PortHandle,
 
     /* Check if this is the message the thread had received */
     if ((Thread->LpcReceivedMsgIdValid) &&
-        (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
+        (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
     {
         /* Clear this data */
         Thread->LpcReceivedMessageId = 0;
@@ -290,9 +336,9 @@ NtReplyPort(IN HANDLE PortHandle,
 
     /* Free any data information */
     LpcpFreeDataInfoMessage(Port,
-                            ReplyMessage->MessageId,
-                            ReplyMessage->CallbackId,
-                            ReplyMessage->ClientId);
+                            CapturedReplyMessage.MessageId,
+                            CapturedReplyMessage.CallbackId,
+                            CapturedReplyMessage.ClientId);
 
     /* Release the lock and release the LPC semaphore to wake up waiters */
     KeReleaseGuardedMutex(&LpcpLock);
@@ -317,49 +363,47 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
                          OUT PPORT_MESSAGE ReceiveMessage,
                          IN PLARGE_INTEGER Timeout OPTIONAL)
 {
-    PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
-    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
     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;
-    //PORT_MESSAGE CapturedReplyMessage;
-    LARGE_INTEGER CapturedTimeout;
 
     PAGED_CODE();
     LPCTRACE(LPC_REPLY_DEBUG,
-             "Handle: %lx. Messages: %p/%p. Context: %p\n",
+             "Handle: %p. Messages: %p/%p. Context: %p\n",
              PortHandle,
              ReplyMessage,
              ReceiveMessage,
              PortContext);
 
-    if (KeGetPreviousMode() == UserMode)
+    /* Check if the call comes from user mode */
+    if (PreviousMode != KernelMode)
     {
         _SEH2_TRY
         {
+            if (PortContext != NULL)
+                ProbeForWritePointer(PortContext);
+
             if (ReplyMessage != NULL)
             {
-                ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
-                /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
-                ReplyMessage = &CapturedReplyMessage;*/
+                ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
+                CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
             }
 
             if (Timeout != NULL)
             {
                 ProbeForReadLargeInteger(Timeout);
-                RtlCopyMemory(&CapturedTimeout, Timeout, sizeof(LARGE_INTEGER));
+                CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout;
                 Timeout = &CapturedTimeout;
             }
-
-            if (PortContext != NULL)
-                ProbeForWritePointer(PortContext);
         }
-        _SEH2_EXCEPT(ExSystemExceptionFilter())
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            DPRINT1("SEH crash [1]\n");
-            DbgBreakPoint();
             _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
         _SEH2_END;
@@ -368,21 +412,24 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
     {
         /* 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)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
-            (ULONG)ReplyMessage->u1.s1.TotalLength)
+        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 (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
+        if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
     }
 
     /* Get the Port object */
@@ -398,9 +445,9 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
     if (ReplyMessage)
     {
         /* Validate its length in respect to the port object */
-        if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
-            ((ULONG)ReplyMessage->u1.s1.TotalLength <=
-             (ULONG)ReplyMessage->u1.s1.DataLength))
+        if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
+            ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
+             (ULONG)CapturedReplyMessage.u1.s1.DataLength))
         {
             /* Too large, fail */
             ObDereferenceObject(Port);
@@ -448,7 +495,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
     if (ReplyMessage)
     {
         /* Get the ETHREAD corresponding to it */
-        Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+        Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
                                             NULL,
                                             &WakeupThread);
         if (!NT_SUCCESS(Status))
@@ -474,13 +521,13 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
         KeAcquireGuardedMutex(&LpcpLock);
 
         /* Make sure this is the reply the thread is waiting for */
-        if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
+        if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
             ((LpcpGetMessageFromThread(WakeupThread)) &&
-             (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
-                                 Request) != LPC_REQUEST)))
+             (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request)
+                != LPC_REQUEST)))
         {
             /* It isn't, fail */
-            LpcpFreeToPortZone(Message, 3);
+            LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
             if (ConnectionPort) ObDereferenceObject(ConnectionPort);
             ObDereferenceObject(WakeupThread);
             ObDereferenceObject(Port);
@@ -488,11 +535,24 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
         }
 
         /* Copy the message */
-        LpcpMoveMessage(&Message->Request,
-                        ReplyMessage,
-                        ReplyMessage + 1,
-                        LPC_REPLY,
-                        NULL);
+        _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);
@@ -513,7 +573,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
 
         /* Check if this is the message the thread had received */
         if ((Thread->LpcReceivedMsgIdValid) &&
-            (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
+            (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
         {
             /* Clear this data */
             Thread->LpcReceivedMessageId = 0;
@@ -522,9 +582,9 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
 
         /* Free any data information */
         LpcpFreeDataInfoMessage(Port,
-                                ReplyMessage->MessageId,
-                                ReplyMessage->CallbackId,
-                                ReplyMessage->ClientId);
+                                CapturedReplyMessage.MessageId,
+                                CapturedReplyMessage.CallbackId,
+                                CapturedReplyMessage.ClientId);
 
         /* Release the lock and release the LPC semaphore to wake up waiters */
         KeReleaseGuardedMutex(&LpcpLock);
@@ -548,7 +608,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
         if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
         {
             /* Reset its event */
-            KeResetEvent(&ReceivePort->WaitEvent);
+            KeClearEvent(&ReceivePort->WaitEvent);
         }
 
         /* Release the lock and fail */
@@ -559,8 +619,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
     }
 
     /* Get the message on the queue */
-    Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->
-                                               MsgQueue.ReceiveHead),
+    Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead),
                                 LPCP_MESSAGE,
                                 Entry);
 
@@ -571,7 +630,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
         if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
         {
             /* Reset its event */
-            KeResetEvent(&ReceivePort->WaitEvent);
+            KeClearEvent(&ReceivePort->WaitEvent);
         }
     }
 
@@ -637,7 +696,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
             if (Message->Request.u2.s2.DataInfoOffset)
             {
                 /* It does, save it, and don't free the message below */
-                LpcpSaveDataInfoMessage(Port, Message, 1);
+                LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD);
                 Message = NULL;
             }
         }
@@ -647,10 +706,8 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
             ASSERT(FALSE);
         }
     }
-    _SEH2_EXCEPT(ExSystemExceptionFilter())
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        DPRINT1("SEH crash [2]\n");
-        DbgBreakPoint();
         Status = _SEH2_GetExceptionCode();
     }
     _SEH2_END;
@@ -659,7 +716,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
     if (Message)
     {
         /* Free it and release the lock */
-        LpcpFreeToPortZone(Message, 3);
+        LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
     }
     else
     {
@@ -670,7 +727,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
 Cleanup:
     /* All done, dereference the port and return the status */
     LPCTRACE(LPC_REPLY_DEBUG,
-             "Port: %p. Status: %p\n",
+             "Port: %p. Status: %d\n",
              Port,
              Status);
     if (ConnectionPort) ObDereferenceObject(ConnectionPort);
@@ -708,8 +765,200 @@ NtReplyWaitReplyPort(IN HANDLE PortHandle,
     return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+NTAPI
+LpcpCopyRequestData(
+    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;
+}
+
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -718,14 +967,20 @@ NtReadRequestData(IN HANDLE PortHandle,
                   IN ULONG Index,
                   IN PVOID Buffer,
                   IN ULONG BufferLength,
-                  OUT PULONG Returnlength)
+                  OUT PULONG ReturnLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* Call the internal function */
+    return LpcpCopyRequestData(FALSE,
+                               PortHandle,
+                               Message,
+                               Index,
+                               Buffer,
+                               BufferLength,
+                               ReturnLength);
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -736,8 +991,14 @@ NtWriteRequestData(IN HANDLE PortHandle,
                    IN ULONG BufferLength,
                    OUT PULONG ReturnLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* Call the internal function */
+    return LpcpCopyRequestData(TRUE,
+                               PortHandle,
+                               Message,
+                               Index,
+                               Buffer,
+                               BufferLength,
+                               ReturnLength);
 }
 
 /* EOF */