1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/lpc/reply.c 5 * PURPOSE: Local Procedure Call: Receive (Replies) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* PRIVATE FUNCTIONS *********************************************************/ 16 17 VOID 18 NTAPI 19 LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port, 20 IN ULONG MessageId, 21 IN ULONG CallbackId, 22 IN CLIENT_ID ClientId) 23 { 24 PLPCP_MESSAGE Message; 25 PLIST_ENTRY ListHead, NextEntry; 26 27 /* Check if the port we want is the connection port */ 28 if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) 29 { 30 /* Use it */ 31 Port = Port->ConnectionPort; 32 if (!Port) return; 33 } 34 35 /* Loop the list */ 36 ListHead = &Port->LpcDataInfoChainHead; 37 NextEntry = ListHead->Flink; 38 while (ListHead != NextEntry) 39 { 40 /* Get the message */ 41 Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry); 42 43 /* Make sure it matches */ 44 if ((Message->Request.MessageId == MessageId) && 45 (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread) && 46 (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess)) 47 { 48 /* Unlink and free it */ 49 RemoveEntryList(&Message->Entry); 50 InitializeListHead(&Message->Entry); 51 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); 52 break; 53 } 54 55 /* Go to the next entry */ 56 NextEntry = NextEntry->Flink; 57 } 58 } 59 60 VOID 61 NTAPI 62 LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port, 63 IN PLPCP_MESSAGE Message, 64 IN ULONG LockFlags) 65 { 66 BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD); 67 68 PAGED_CODE(); 69 70 /* Acquire the lock */ 71 if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock); 72 73 /* Check if the port we want is the connection port */ 74 if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) 75 { 76 /* Use it */ 77 Port = Port->ConnectionPort; 78 if (!Port) 79 { 80 /* Release the lock and return */ 81 if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock); 82 return; 83 } 84 } 85 86 /* Link the message */ 87 InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry); 88 89 /* Release the lock */ 90 if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock); 91 } 92 93 PLPCP_MESSAGE 94 NTAPI 95 LpcpFindDataInfoMessage( 96 IN PLPCP_PORT_OBJECT Port, 97 IN ULONG MessageId, 98 IN LPC_CLIENT_ID ClientId) 99 { 100 PLPCP_MESSAGE Message; 101 PLIST_ENTRY ListEntry; 102 103 PAGED_CODE(); 104 105 /* Check if the port we want is the connection port */ 106 if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) 107 { 108 /* Use it */ 109 Port = Port->ConnectionPort; 110 if (!Port) 111 { 112 /* Return NULL */ 113 return NULL; 114 } 115 } 116 117 /* Loop all entries in the list */ 118 for (ListEntry = Port->LpcDataInfoChainHead.Flink; 119 ListEntry != &Port->LpcDataInfoChainHead; 120 ListEntry = ListEntry->Flink) 121 { 122 Message = CONTAINING_RECORD(ListEntry, LPCP_MESSAGE, Entry); 123 124 /* Check if this is the desired message */ 125 if ((Message->Request.MessageId == MessageId) && 126 (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess) && 127 (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread)) 128 { 129 /* It is, return it */ 130 return Message; 131 } 132 } 133 134 return NULL; 135 } 136 137 VOID 138 NTAPI 139 LpcpMoveMessage(IN PPORT_MESSAGE Destination, 140 IN PPORT_MESSAGE Origin, 141 IN PVOID Data, 142 IN ULONG MessageType, 143 IN PCLIENT_ID ClientId) 144 { 145 LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG), 146 "Destination/Origin: %p/%p. Data: %p. Length: %lx\n", 147 Destination, 148 Origin, 149 Data, 150 Origin->u1.Length); 151 152 /* Set the Message size */ 153 Destination->u1.Length = Origin->u1.Length; 154 155 /* Set the Message Type */ 156 Destination->u2.s2.Type = !MessageType ? 157 Origin->u2.s2.Type : MessageType & 0xFFFF; 158 159 /* Check if we have a Client ID */ 160 if (ClientId) 161 { 162 /* Set the Client ID */ 163 Destination->ClientId.UniqueProcess = ClientId->UniqueProcess; 164 Destination->ClientId.UniqueThread = ClientId->UniqueThread; 165 } 166 else 167 { 168 /* Otherwise, copy it */ 169 Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess; 170 Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread; 171 } 172 173 /* Copy the MessageId and ClientViewSize */ 174 Destination->MessageId = Origin->MessageId; 175 Destination->ClientViewSize = Origin->ClientViewSize; 176 177 /* Copy the Message Data */ 178 RtlCopyMemory(Destination + 1, 179 Data, 180 ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG))); 181 } 182 183 /* PUBLIC FUNCTIONS **********************************************************/ 184 185 /* 186 * @implemented 187 */ 188 NTSTATUS 189 NTAPI 190 NtReplyPort(IN HANDLE PortHandle, 191 IN PPORT_MESSAGE ReplyMessage) 192 { 193 NTSTATUS Status; 194 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 195 PORT_MESSAGE CapturedReplyMessage; 196 PLPCP_PORT_OBJECT Port; 197 PLPCP_MESSAGE Message; 198 PETHREAD Thread = PsGetCurrentThread(), WakeupThread; 199 200 PAGED_CODE(); 201 LPCTRACE(LPC_REPLY_DEBUG, 202 "Handle: %p. Message: %p.\n", 203 PortHandle, 204 ReplyMessage); 205 206 /* Check if the call comes from user mode */ 207 if (PreviousMode != KernelMode) 208 { 209 _SEH2_TRY 210 { 211 ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG)); 212 CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage; 213 } 214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 215 { 216 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 217 } 218 _SEH2_END; 219 } 220 else 221 { 222 CapturedReplyMessage = *ReplyMessage; 223 } 224 225 /* Validate its length */ 226 if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) > 227 (ULONG)CapturedReplyMessage.u1.s1.TotalLength) 228 { 229 /* Fail */ 230 return STATUS_INVALID_PARAMETER; 231 } 232 233 /* Make sure it has a valid ID */ 234 if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER; 235 236 /* Get the Port object */ 237 Status = ObReferenceObjectByHandle(PortHandle, 238 0, 239 LpcPortObjectType, 240 PreviousMode, 241 (PVOID*)&Port, 242 NULL); 243 if (!NT_SUCCESS(Status)) return Status; 244 245 /* Validate its length in respect to the port object */ 246 if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) || 247 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= 248 (ULONG)CapturedReplyMessage.u1.s1.DataLength)) 249 { 250 /* Too large, fail */ 251 ObDereferenceObject(Port); 252 return STATUS_PORT_MESSAGE_TOO_LONG; 253 } 254 255 /* Get the ETHREAD corresponding to it */ 256 Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId, 257 NULL, 258 &WakeupThread); 259 if (!NT_SUCCESS(Status)) 260 { 261 /* No thread found, fail */ 262 ObDereferenceObject(Port); 263 return Status; 264 } 265 266 /* Allocate a message from the port zone */ 267 Message = LpcpAllocateFromPortZone(); 268 if (!Message) 269 { 270 /* Fail if we couldn't allocate a message */ 271 ObDereferenceObject(WakeupThread); 272 ObDereferenceObject(Port); 273 return STATUS_NO_MEMORY; 274 } 275 276 /* Keep the lock acquired */ 277 KeAcquireGuardedMutex(&LpcpLock); 278 279 /* Make sure this is the reply the thread is waiting for */ 280 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) || 281 ((LpcpGetMessageFromThread(WakeupThread)) && 282 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request) 283 != LPC_REQUEST))) 284 { 285 /* It isn't, fail */ 286 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); 287 ObDereferenceObject(WakeupThread); 288 ObDereferenceObject(Port); 289 return STATUS_REPLY_MESSAGE_MISMATCH; 290 } 291 292 /* Copy the message */ 293 _SEH2_TRY 294 { 295 LpcpMoveMessage(&Message->Request, 296 &CapturedReplyMessage, 297 ReplyMessage + 1, 298 LPC_REPLY, 299 NULL); 300 } 301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 302 { 303 /* Cleanup and return the exception code */ 304 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); 305 ObDereferenceObject(WakeupThread); 306 ObDereferenceObject(Port); 307 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 308 } 309 _SEH2_END; 310 311 /* Reference the thread while we use it */ 312 ObReferenceObject(WakeupThread); 313 Message->RepliedToThread = WakeupThread; 314 315 /* Set this as the reply message */ 316 WakeupThread->LpcReplyMessageId = 0; 317 WakeupThread->LpcReplyMessage = (PVOID)Message; 318 319 /* Check if we have messages on the reply chain */ 320 if (!(WakeupThread->LpcExitThreadCalled) && 321 !(IsListEmpty(&WakeupThread->LpcReplyChain))) 322 { 323 /* Remove us from it and reinitialize it */ 324 RemoveEntryList(&WakeupThread->LpcReplyChain); 325 InitializeListHead(&WakeupThread->LpcReplyChain); 326 } 327 328 /* Check if this is the message the thread had received */ 329 if ((Thread->LpcReceivedMsgIdValid) && 330 (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) 331 { 332 /* Clear this data */ 333 Thread->LpcReceivedMessageId = 0; 334 Thread->LpcReceivedMsgIdValid = FALSE; 335 } 336 337 /* Free any data information */ 338 LpcpFreeDataInfoMessage(Port, 339 CapturedReplyMessage.MessageId, 340 CapturedReplyMessage.CallbackId, 341 CapturedReplyMessage.ClientId); 342 343 /* Release the lock and release the LPC semaphore to wake up waiters */ 344 KeReleaseGuardedMutex(&LpcpLock); 345 LpcpCompleteWait(&WakeupThread->LpcReplySemaphore); 346 347 /* Now we can let go of the thread */ 348 ObDereferenceObject(WakeupThread); 349 350 /* Dereference port object */ 351 ObDereferenceObject(Port); 352 return Status; 353 } 354 355 /* 356 * @implemented 357 */ 358 NTSTATUS 359 NTAPI 360 NtReplyWaitReceivePortEx(IN HANDLE PortHandle, 361 OUT PVOID *PortContext OPTIONAL, 362 IN PPORT_MESSAGE ReplyMessage OPTIONAL, 363 OUT PPORT_MESSAGE ReceiveMessage, 364 IN PLARGE_INTEGER Timeout OPTIONAL) 365 { 366 NTSTATUS Status; 367 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode; 368 PORT_MESSAGE CapturedReplyMessage; 369 LARGE_INTEGER CapturedTimeout; 370 PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL; 371 PLPCP_MESSAGE Message; 372 PETHREAD Thread = PsGetCurrentThread(), WakeupThread; 373 PLPCP_CONNECTION_MESSAGE ConnectMessage; 374 ULONG ConnectionInfoLength; 375 376 PAGED_CODE(); 377 LPCTRACE(LPC_REPLY_DEBUG, 378 "Handle: %p. Messages: %p/%p. Context: %p\n", 379 PortHandle, 380 ReplyMessage, 381 ReceiveMessage, 382 PortContext); 383 384 /* Check if the call comes from user mode */ 385 if (PreviousMode != KernelMode) 386 { 387 _SEH2_TRY 388 { 389 if (PortContext != NULL) 390 ProbeForWritePointer(PortContext); 391 392 if (ReplyMessage != NULL) 393 { 394 ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG)); 395 CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage; 396 } 397 398 if (Timeout != NULL) 399 { 400 ProbeForReadLargeInteger(Timeout); 401 CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout; 402 Timeout = &CapturedTimeout; 403 } 404 } 405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 406 { 407 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 408 } 409 _SEH2_END; 410 } 411 else 412 { 413 /* If this is a system thread, then let it page out its stack */ 414 if (Thread->SystemThread) WaitMode = UserMode; 415 416 if (ReplyMessage != NULL) 417 CapturedReplyMessage = *ReplyMessage; 418 } 419 420 /* Check if caller has a reply message */ 421 if (ReplyMessage) 422 { 423 /* Validate its length */ 424 if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) > 425 (ULONG)CapturedReplyMessage.u1.s1.TotalLength) 426 { 427 /* Fail */ 428 return STATUS_INVALID_PARAMETER; 429 } 430 431 /* Make sure it has a valid ID */ 432 if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER; 433 } 434 435 /* Get the Port object */ 436 Status = ObReferenceObjectByHandle(PortHandle, 437 0, 438 LpcPortObjectType, 439 PreviousMode, 440 (PVOID*)&Port, 441 NULL); 442 if (!NT_SUCCESS(Status)) return Status; 443 444 /* Check if the caller has a reply message */ 445 if (ReplyMessage) 446 { 447 /* Validate its length in respect to the port object */ 448 if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) || 449 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= 450 (ULONG)CapturedReplyMessage.u1.s1.DataLength)) 451 { 452 /* Too large, fail */ 453 ObDereferenceObject(Port); 454 return STATUS_PORT_MESSAGE_TOO_LONG; 455 } 456 } 457 458 /* Check if this is anything but a client port */ 459 if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT) 460 { 461 /* Check if this is the connection port */ 462 if (Port->ConnectionPort == Port) 463 { 464 /* Use this port */ 465 ConnectionPort = ReceivePort = Port; 466 ObReferenceObject(ConnectionPort); 467 } 468 else 469 { 470 /* Acquire the lock */ 471 KeAcquireGuardedMutex(&LpcpLock); 472 473 /* Get the port */ 474 ConnectionPort = ReceivePort = Port->ConnectionPort; 475 if (!ConnectionPort) 476 { 477 /* Fail */ 478 KeReleaseGuardedMutex(&LpcpLock); 479 ObDereferenceObject(Port); 480 return STATUS_PORT_DISCONNECTED; 481 } 482 483 /* Release lock and reference */ 484 ObReferenceObject(ConnectionPort); 485 KeReleaseGuardedMutex(&LpcpLock); 486 } 487 } 488 else 489 { 490 /* Otherwise, use the port itself */ 491 ReceivePort = Port; 492 } 493 494 /* Check if the caller gave a reply message */ 495 if (ReplyMessage) 496 { 497 /* Get the ETHREAD corresponding to it */ 498 Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId, 499 NULL, 500 &WakeupThread); 501 if (!NT_SUCCESS(Status)) 502 { 503 /* No thread found, fail */ 504 ObDereferenceObject(Port); 505 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 506 return Status; 507 } 508 509 /* Allocate a message from the port zone */ 510 Message = LpcpAllocateFromPortZone(); 511 if (!Message) 512 { 513 /* Fail if we couldn't allocate a message */ 514 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 515 ObDereferenceObject(WakeupThread); 516 ObDereferenceObject(Port); 517 return STATUS_NO_MEMORY; 518 } 519 520 /* Keep the lock acquired */ 521 KeAcquireGuardedMutex(&LpcpLock); 522 523 /* Make sure this is the reply the thread is waiting for */ 524 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) || 525 ((LpcpGetMessageFromThread(WakeupThread)) && 526 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request) 527 != LPC_REQUEST))) 528 { 529 /* It isn't, fail */ 530 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); 531 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 532 ObDereferenceObject(WakeupThread); 533 ObDereferenceObject(Port); 534 return STATUS_REPLY_MESSAGE_MISMATCH; 535 } 536 537 /* Copy the message */ 538 _SEH2_TRY 539 { 540 LpcpMoveMessage(&Message->Request, 541 &CapturedReplyMessage, 542 ReplyMessage + 1, 543 LPC_REPLY, 544 NULL); 545 } 546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 547 { 548 /* Cleanup and return the exception code */ 549 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); 550 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 551 ObDereferenceObject(WakeupThread); 552 ObDereferenceObject(Port); 553 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 554 } 555 _SEH2_END; 556 557 /* Reference the thread while we use it */ 558 ObReferenceObject(WakeupThread); 559 Message->RepliedToThread = WakeupThread; 560 561 /* Set this as the reply message */ 562 WakeupThread->LpcReplyMessageId = 0; 563 WakeupThread->LpcReplyMessage = (PVOID)Message; 564 565 /* Check if we have messages on the reply chain */ 566 if (!(WakeupThread->LpcExitThreadCalled) && 567 !(IsListEmpty(&WakeupThread->LpcReplyChain))) 568 { 569 /* Remove us from it and reinitialize it */ 570 RemoveEntryList(&WakeupThread->LpcReplyChain); 571 InitializeListHead(&WakeupThread->LpcReplyChain); 572 } 573 574 /* Check if this is the message the thread had received */ 575 if ((Thread->LpcReceivedMsgIdValid) && 576 (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) 577 { 578 /* Clear this data */ 579 Thread->LpcReceivedMessageId = 0; 580 Thread->LpcReceivedMsgIdValid = FALSE; 581 } 582 583 /* Free any data information */ 584 LpcpFreeDataInfoMessage(Port, 585 CapturedReplyMessage.MessageId, 586 CapturedReplyMessage.CallbackId, 587 CapturedReplyMessage.ClientId); 588 589 /* Release the lock and release the LPC semaphore to wake up waiters */ 590 KeReleaseGuardedMutex(&LpcpLock); 591 LpcpCompleteWait(&WakeupThread->LpcReplySemaphore); 592 593 /* Now we can let go of the thread */ 594 ObDereferenceObject(WakeupThread); 595 } 596 597 /* Now wait for someone to reply to us */ 598 LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode); 599 if (Status != STATUS_SUCCESS) goto Cleanup; 600 601 /* Wait done, get the LPC lock */ 602 KeAcquireGuardedMutex(&LpcpLock); 603 604 /* Check if we've received nothing */ 605 if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead)) 606 { 607 /* Check if this was a waitable port and wake it */ 608 if (ReceivePort->Flags & LPCP_WAITABLE_PORT) 609 { 610 /* Reset its event */ 611 KeClearEvent(&ReceivePort->WaitEvent); 612 } 613 614 /* Release the lock and fail */ 615 KeReleaseGuardedMutex(&LpcpLock); 616 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 617 ObDereferenceObject(Port); 618 return STATUS_UNSUCCESSFUL; 619 } 620 621 /* Get the message on the queue */ 622 Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead), 623 LPCP_MESSAGE, 624 Entry); 625 626 /* Check if the queue is empty now */ 627 if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead)) 628 { 629 /* Check if this was a waitable port */ 630 if (ReceivePort->Flags & LPCP_WAITABLE_PORT) 631 { 632 /* Reset its event */ 633 KeClearEvent(&ReceivePort->WaitEvent); 634 } 635 } 636 637 /* Re-initialize the message's list entry */ 638 InitializeListHead(&Message->Entry); 639 640 /* Set this as the received message */ 641 Thread->LpcReceivedMessageId = Message->Request.MessageId; 642 Thread->LpcReceivedMsgIdValid = TRUE; 643 644 _SEH2_TRY 645 { 646 /* Check if this was a connection request */ 647 if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST) 648 { 649 /* Get the connection message */ 650 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); 651 LPCTRACE(LPC_REPLY_DEBUG, 652 "Request Messages: %p/%p\n", 653 Message, 654 ConnectMessage); 655 656 /* Get its length */ 657 ConnectionInfoLength = Message->Request.u1.s1.DataLength - 658 sizeof(LPCP_CONNECTION_MESSAGE); 659 660 /* Return it as the receive message */ 661 *ReceiveMessage = Message->Request; 662 663 /* Clear our stack variable so the message doesn't get freed */ 664 Message = NULL; 665 666 /* Setup the receive message */ 667 ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(PORT_MESSAGE) + 668 ConnectionInfoLength); 669 ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength; 670 RtlCopyMemory(ReceiveMessage + 1, 671 ConnectMessage + 1, 672 ConnectionInfoLength); 673 674 /* Clear the port context if the caller requested one */ 675 if (PortContext) *PortContext = NULL; 676 } 677 else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY) 678 { 679 /* Otherwise, this is a new message or event */ 680 LPCTRACE(LPC_REPLY_DEBUG, 681 "Non-Reply Messages: %p/%p\n", 682 &Message->Request, 683 (&Message->Request) + 1); 684 685 /* Copy it */ 686 LpcpMoveMessage(ReceiveMessage, 687 &Message->Request, 688 (&Message->Request) + 1, 689 0, 690 NULL); 691 692 /* Return its context */ 693 if (PortContext) *PortContext = Message->PortContext; 694 695 /* And check if it has data information */ 696 if (Message->Request.u2.s2.DataInfoOffset) 697 { 698 /* It does, save it, and don't free the message below */ 699 LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD); 700 Message = NULL; 701 } 702 } 703 else 704 { 705 /* This is a reply message, should never happen! */ 706 ASSERT(FALSE); 707 } 708 } 709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 710 { 711 Status = _SEH2_GetExceptionCode(); 712 } 713 _SEH2_END; 714 715 /* Check if we have a message pointer here */ 716 if (Message) 717 { 718 /* Free it and release the lock */ 719 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE); 720 } 721 else 722 { 723 /* Just release the lock */ 724 KeReleaseGuardedMutex(&LpcpLock); 725 } 726 727 Cleanup: 728 /* All done, dereference the port and return the status */ 729 LPCTRACE(LPC_REPLY_DEBUG, 730 "Port: %p. Status: %d\n", 731 Port, 732 Status); 733 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 734 ObDereferenceObject(Port); 735 return Status; 736 } 737 738 /* 739 * @implemented 740 */ 741 NTSTATUS 742 NTAPI 743 NtReplyWaitReceivePort(IN HANDLE PortHandle, 744 OUT PVOID *PortContext OPTIONAL, 745 IN PPORT_MESSAGE ReplyMessage OPTIONAL, 746 OUT PPORT_MESSAGE ReceiveMessage) 747 { 748 /* Call the newer API */ 749 return NtReplyWaitReceivePortEx(PortHandle, 750 PortContext, 751 ReplyMessage, 752 ReceiveMessage, 753 NULL); 754 } 755 756 /* 757 * @unimplemented 758 */ 759 NTSTATUS 760 NTAPI 761 NtReplyWaitReplyPort(IN HANDLE PortHandle, 762 IN PPORT_MESSAGE ReplyMessage) 763 { 764 UNIMPLEMENTED; 765 return STATUS_NOT_IMPLEMENTED; 766 } 767 768 NTSTATUS 769 NTAPI 770 LpcpCopyRequestData( 771 IN BOOLEAN Write, 772 IN HANDLE PortHandle, 773 IN PPORT_MESSAGE Message, 774 IN ULONG Index, 775 IN PVOID Buffer, 776 IN ULONG BufferLength, 777 OUT PULONG ReturnLength) 778 { 779 NTSTATUS Status; 780 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 781 PORT_MESSAGE CapturedMessage; 782 PLPCP_PORT_OBJECT Port = NULL; 783 PETHREAD ClientThread = NULL; 784 SIZE_T LocalReturnLength; 785 PLPCP_MESSAGE InfoMessage; 786 PLPCP_DATA_INFO DataInfo; 787 PVOID DataInfoBaseAddress; 788 789 PAGED_CODE(); 790 791 /* Check if the call comes from user mode */ 792 if (PreviousMode != KernelMode) 793 { 794 _SEH2_TRY 795 { 796 ProbeForRead(Message, sizeof(*Message), sizeof(PVOID)); 797 CapturedMessage = *(volatile PORT_MESSAGE*)Message; 798 } 799 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 800 { 801 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 802 } 803 _SEH2_END; 804 } 805 else 806 { 807 CapturedMessage = *Message; 808 } 809 810 /* Make sure there is any data to copy */ 811 if (CapturedMessage.u2.s2.DataInfoOffset == 0) 812 { 813 return STATUS_INVALID_PARAMETER; 814 } 815 816 /* Reference the port handle */ 817 Status = ObReferenceObjectByHandle(PortHandle, 818 PORT_ALL_ACCESS, 819 LpcPortObjectType, 820 PreviousMode, 821 (PVOID*)&Port, 822 NULL); 823 if (!NT_SUCCESS(Status)) 824 { 825 DPRINT1("Failed to reference port handle: 0x%ls\n", Status); 826 return Status; 827 } 828 829 /* Look up the client thread */ 830 Status = PsLookupProcessThreadByCid(&CapturedMessage.ClientId, 831 NULL, 832 &ClientThread); 833 if (!NT_SUCCESS(Status)) 834 { 835 DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n", 836 CapturedMessage.ClientId.UniqueProcess, 837 CapturedMessage.ClientId.UniqueThread, Status); 838 goto Cleanup; 839 } 840 841 /* Acquire the global LPC lock */ 842 KeAcquireGuardedMutex(&LpcpLock); 843 844 /* Check for message id mismatch */ 845 if ((ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) || 846 (CapturedMessage.MessageId == 0)) 847 { 848 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n", 849 ClientThread->LpcReplyMessageId, CapturedMessage.MessageId); 850 Status = STATUS_REPLY_MESSAGE_MISMATCH; 851 goto CleanupWithLock; 852 } 853 854 /* Validate the port */ 855 if (!LpcpValidateClientPort(ClientThread, Port)) 856 { 857 DPRINT1("LpcpValidateClientPort failed\n"); 858 Status = STATUS_REPLY_MESSAGE_MISMATCH; 859 goto CleanupWithLock; 860 } 861 862 /* Find the message with the data */ 863 InfoMessage = LpcpFindDataInfoMessage(Port, 864 CapturedMessage.MessageId, 865 CapturedMessage.ClientId); 866 if (InfoMessage == NULL) 867 { 868 DPRINT1("LpcpFindDataInfoMessage failed\n"); 869 Status = STATUS_INVALID_PARAMETER; 870 goto CleanupWithLock; 871 } 872 873 /* Get the data info */ 874 DataInfo = LpcpGetDataInfoFromMessage(&InfoMessage->Request); 875 876 /* Check if the index is within bounds */ 877 if (Index >= DataInfo->NumberOfEntries) 878 { 879 DPRINT1("Message data index %lu out of bounds (%lu in msg)\n", 880 Index, DataInfo->NumberOfEntries); 881 Status = STATUS_INVALID_PARAMETER; 882 goto CleanupWithLock; 883 } 884 885 /* Check if the caller wants to read/write more data than expected */ 886 if (BufferLength > DataInfo->Entries[Index].DataLength) 887 { 888 DPRINT1("Trying to read more data (%lu) than available (%lu)\n", 889 BufferLength, DataInfo->Entries[Index].DataLength); 890 Status = STATUS_INVALID_PARAMETER; 891 goto CleanupWithLock; 892 } 893 894 /* Get the data pointer */ 895 DataInfoBaseAddress = DataInfo->Entries[Index].BaseAddress; 896 897 /* Release the lock */ 898 KeReleaseGuardedMutex(&LpcpLock); 899 900 if (Write) 901 { 902 /* Copy data from the caller to the message sender */ 903 Status = MmCopyVirtualMemory(PsGetCurrentProcess(), 904 Buffer, 905 ClientThread->ThreadsProcess, 906 DataInfoBaseAddress, 907 BufferLength, 908 PreviousMode, 909 &LocalReturnLength); 910 } 911 else 912 { 913 /* Copy data from the message sender to the caller */ 914 Status = MmCopyVirtualMemory(ClientThread->ThreadsProcess, 915 DataInfoBaseAddress, 916 PsGetCurrentProcess(), 917 Buffer, 918 BufferLength, 919 PreviousMode, 920 &LocalReturnLength); 921 } 922 923 if (!NT_SUCCESS(Status)) 924 { 925 DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status); 926 goto Cleanup; 927 } 928 929 /* Check if the caller asked to return the copied length */ 930 if (ReturnLength != NULL) 931 { 932 _SEH2_TRY 933 { 934 *ReturnLength = LocalReturnLength; 935 } 936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 937 { 938 /* Ignore */ 939 DPRINT1("Exception writing ReturnLength, ignoring\n"); 940 } 941 _SEH2_END; 942 } 943 944 Cleanup: 945 946 if (ClientThread != NULL) 947 ObDereferenceObject(ClientThread); 948 949 ObDereferenceObject(Port); 950 951 return Status; 952 953 CleanupWithLock: 954 955 /* Release the lock */ 956 KeReleaseGuardedMutex(&LpcpLock); 957 goto Cleanup; 958 } 959 960 /* 961 * @implemented 962 */ 963 NTSTATUS 964 NTAPI 965 NtReadRequestData(IN HANDLE PortHandle, 966 IN PPORT_MESSAGE Message, 967 IN ULONG Index, 968 IN PVOID Buffer, 969 IN ULONG BufferLength, 970 OUT PULONG ReturnLength) 971 { 972 /* Call the internal function */ 973 return LpcpCopyRequestData(FALSE, 974 PortHandle, 975 Message, 976 Index, 977 Buffer, 978 BufferLength, 979 ReturnLength); 980 } 981 982 /* 983 * @implemented 984 */ 985 NTSTATUS 986 NTAPI 987 NtWriteRequestData(IN HANDLE PortHandle, 988 IN PPORT_MESSAGE Message, 989 IN ULONG Index, 990 IN PVOID Buffer, 991 IN ULONG BufferLength, 992 OUT PULONG ReturnLength) 993 { 994 /* Call the internal function */ 995 return LpcpCopyRequestData(TRUE, 996 PortHandle, 997 Message, 998 Index, 999 Buffer, 1000 BufferLength, 1001 ReturnLength); 1002 } 1003 1004 /* EOF */ 1005