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.

762 lines
23 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lpcreply.c
  5. Abstract:
  6. Local Inter-Process Communication (LPC) reply system services.
  7. Author:
  8. Steve Wood (stevewo) 15-May-1989
  9. Revision History:
  10. --*/
  11. #include "lpcp.h"
  12. NTSTATUS
  13. LpcpCopyRequestData(
  14. IN BOOLEAN WriteToMessageData,
  15. IN HANDLE PortHandle,
  16. IN PPORT_MESSAGE Message,
  17. IN ULONG DataEntryIndex,
  18. IN PVOID Buffer,
  19. IN ULONG BufferSize,
  20. OUT PULONG NumberOfBytesCopied OPTIONAL
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE,NtReplyPort)
  24. #pragma alloc_text(PAGE,NtReplyWaitReplyPort)
  25. #pragma alloc_text(PAGE,NtReadRequestData)
  26. #pragma alloc_text(PAGE,NtWriteRequestData)
  27. #pragma alloc_text(PAGE,LpcpCopyRequestData)
  28. #endif
  29. NTSTATUS
  30. NtReplyPort(
  31. IN HANDLE PortHandle,
  32. IN PPORT_MESSAGE ReplyMessage
  33. )
  34. {
  35. KPROCESSOR_MODE PreviousMode;
  36. PLPCP_PORT_OBJECT PortObject;
  37. PORT_MESSAGE CapturedReplyMessage;
  38. NTSTATUS Status;
  39. PLPCP_MESSAGE Msg;
  40. PETHREAD CurrentThread;
  41. PETHREAD WakeupThread;
  42. PAGED_CODE();
  43. CurrentThread = PsGetCurrentThread();
  44. //
  45. // Get previous processor mode and probe output arguments if necessary.
  46. //
  47. PreviousMode = KeGetPreviousMode();
  48. if (PreviousMode != KernelMode) {
  49. try {
  50. ProbeForRead( ReplyMessage,
  51. sizeof( *ReplyMessage ),
  52. sizeof( ULONG )
  53. );
  54. CapturedReplyMessage = *ReplyMessage;
  55. }
  56. except( EXCEPTION_EXECUTE_HANDLER ) {
  57. return( GetExceptionCode() );
  58. }
  59. }
  60. else {
  61. CapturedReplyMessage = *ReplyMessage;
  62. }
  63. //
  64. // Reference the port object by handle
  65. //
  66. Status = LpcpReferencePortObject( PortHandle,
  67. 0,
  68. PreviousMode,
  69. &PortObject
  70. );
  71. if (!NT_SUCCESS( Status )) {
  72. return( Status );
  73. }
  74. //
  75. // Translate the ClientId from the connection request into a
  76. // thread pointer. This is a referenced pointer to keep the thread
  77. // from evaporating out from under us.
  78. //
  79. Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
  80. NULL,
  81. &WakeupThread
  82. );
  83. if (!NT_SUCCESS( Status )) {
  84. ObDereferenceObject( PortObject );
  85. return( Status );
  86. }
  87. //
  88. // Acquire the mutex that gaurds the LpcReplyMessage field of
  89. // the thread and get the pointer to the message that the thread
  90. // is waiting for a reply to.
  91. //
  92. ExAcquireFastMutex( &LpcpLock );
  93. Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
  94. if (Msg == NULL) {
  95. ExReleaseFastMutex( &LpcpLock );
  96. ObDereferenceObject( WakeupThread );
  97. ObDereferenceObject( PortObject );
  98. return( STATUS_NO_MEMORY );
  99. }
  100. //
  101. // See if the thread is waiting for a reply to the message
  102. // specified on this call. If not then a bogus message
  103. // has been specified, so release the mutex, dereference the thread
  104. // and return failure.
  105. //
  106. if (WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) {
  107. LpcpPrint(( "%s Attempted reply to Thread %lx (%s)\n",
  108. PsGetCurrentProcess()->ImageFileName,
  109. WakeupThread,
  110. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  111. ));
  112. LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n",
  113. CapturedReplyMessage.MessageId,
  114. CapturedReplyMessage.ClientId.UniqueProcess,
  115. CapturedReplyMessage.ClientId.UniqueThread
  116. ));
  117. LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n",
  118. WakeupThread->LpcReplyMessageId,
  119. WakeupThread->Cid.UniqueProcess,
  120. WakeupThread->Cid.UniqueThread
  121. ));
  122. #if DBG
  123. if (LpcpStopOnReplyMismatch) {
  124. DbgBreakPoint();
  125. }
  126. #endif
  127. LpcpFreeToPortZone( Msg, TRUE );
  128. ExReleaseFastMutex( &LpcpLock );
  129. ObDereferenceObject( WakeupThread );
  130. ObDereferenceObject( PortObject );
  131. return( STATUS_REPLY_MESSAGE_MISMATCH );
  132. }
  133. LpcpTrace(( "%s Sending Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
  134. PsGetCurrentProcess()->ImageFileName,
  135. Msg,
  136. CapturedReplyMessage.MessageId,
  137. CapturedReplyMessage.u2.s2.DataInfoOffset,
  138. *((PULONG)(Msg+1)+0),
  139. *((PULONG)(Msg+1)+1),
  140. *((PULONG)(Msg+1)+2),
  141. *((PULONG)(Msg+1)+3),
  142. WakeupThread,
  143. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  144. ));
  145. if (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) {
  146. LpcpFreeDataInfoMessage( PortObject,
  147. CapturedReplyMessage.MessageId,
  148. CapturedReplyMessage.CallbackId
  149. );
  150. }
  151. //
  152. // Release the mutex that guards the LpcReplyMessage field
  153. // after marking message as being replied to.
  154. //
  155. Msg->RepliedToThread = WakeupThread;
  156. WakeupThread->LpcReplyMessageId = 0;
  157. WakeupThread->LpcReplyMessage = (PVOID)Msg;
  158. //
  159. // Remove the thread from the reply rundown list as we are sending the reply.
  160. //
  161. if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
  162. RemoveEntryList( &WakeupThread->LpcReplyChain );
  163. InitializeListHead( &WakeupThread->LpcReplyChain );
  164. }
  165. if (CurrentThread->LpcReceivedMsgIdValid &&
  166. CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId
  167. ) {
  168. CurrentThread->LpcReceivedMessageId = 0;
  169. CurrentThread->LpcReceivedMsgIdValid = FALSE;
  170. }
  171. ExReleaseFastMutex( &LpcpLock );
  172. //
  173. // Copy the reply message to the request message buffer
  174. //
  175. try {
  176. LpcpMoveMessage( &Msg->Request,
  177. &CapturedReplyMessage,
  178. (ReplyMessage + 1),
  179. LPC_REPLY,
  180. NULL
  181. );
  182. }
  183. except( EXCEPTION_EXECUTE_HANDLER ) {
  184. Status = GetExceptionCode();
  185. }
  186. //
  187. // Wake up the thread that is waiting for an answer to its request
  188. // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That
  189. // will dereference itself when it wakes up.
  190. //
  191. KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore,
  192. 0,
  193. 1L,
  194. FALSE
  195. );
  196. //
  197. // Dereference port object and return the system service status.
  198. //
  199. ObDereferenceObject( PortObject );
  200. return( Status );
  201. }
  202. NTSTATUS
  203. NtReplyWaitReplyPort(
  204. IN HANDLE PortHandle,
  205. IN OUT PPORT_MESSAGE ReplyMessage
  206. )
  207. {
  208. KPROCESSOR_MODE PreviousMode;
  209. NTSTATUS Status;
  210. PLPCP_PORT_OBJECT PortObject;
  211. PORT_MESSAGE CapturedReplyMessage;
  212. PLPCP_MESSAGE Msg;
  213. PETHREAD CurrentThread;
  214. PETHREAD WakeupThread;
  215. PAGED_CODE();
  216. CurrentThread = PsGetCurrentThread();
  217. //
  218. // Get previous processor mode and probe output arguments if necessary.
  219. //
  220. PreviousMode = KeGetPreviousMode();
  221. if (PreviousMode != KernelMode) {
  222. try {
  223. ProbeForRead( ReplyMessage,
  224. sizeof( *ReplyMessage ),
  225. sizeof( ULONG )
  226. );
  227. CapturedReplyMessage = *ReplyMessage;
  228. }
  229. except( EXCEPTION_EXECUTE_HANDLER ) {
  230. return( GetExceptionCode() );
  231. }
  232. }
  233. else {
  234. CapturedReplyMessage = *ReplyMessage;
  235. }
  236. //
  237. // Reference the communication port object by handle. Return status if
  238. // unsuccessful.
  239. //
  240. Status = LpcpReferencePortObject( PortHandle,
  241. 0,
  242. PreviousMode,
  243. &PortObject
  244. );
  245. if (!NT_SUCCESS( Status )) {
  246. return( Status );
  247. }
  248. //
  249. // Translate the ClientId from the connection request into a
  250. // thread pointer. This is a referenced pointer to keep the thread
  251. // from evaporating out from under us.
  252. //
  253. Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
  254. NULL,
  255. &WakeupThread
  256. );
  257. if (!NT_SUCCESS( Status )) {
  258. ObDereferenceObject( PortObject );
  259. return( Status );
  260. }
  261. //
  262. // Acquire the mutex that gaurds the LpcReplyMessage field of
  263. // the thread and get the pointer to the message that the thread
  264. // is waiting for a reply to.
  265. //
  266. ExAcquireFastMutex( &LpcpLock );
  267. Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
  268. if (Msg == NULL) {
  269. ExReleaseFastMutex( &LpcpLock );
  270. ObDereferenceObject( WakeupThread );
  271. ObDereferenceObject( PortObject );
  272. return( STATUS_NO_MEMORY );
  273. }
  274. //
  275. // See if the thread is waiting for a reply to the message
  276. // specified on this call. If not then a bogus message
  277. // has been specified, so release the mutex, dereference the thread
  278. // and return failure.
  279. //
  280. if (WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) {
  281. LpcpPrint(( "%s Attempted reply wait reply to Thread %lx (%s)\n",
  282. PsGetCurrentProcess()->ImageFileName,
  283. WakeupThread,
  284. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  285. ));
  286. LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n",
  287. CapturedReplyMessage.MessageId,
  288. CapturedReplyMessage.ClientId.UniqueProcess,
  289. CapturedReplyMessage.ClientId.UniqueThread
  290. ));
  291. LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n",
  292. WakeupThread->LpcReplyMessageId,
  293. WakeupThread->Cid.UniqueProcess,
  294. WakeupThread->Cid.UniqueThread
  295. ));
  296. #if DBG
  297. if (LpcpStopOnReplyMismatch) {
  298. DbgBreakPoint();
  299. }
  300. #endif
  301. LpcpFreeToPortZone( Msg, TRUE );
  302. ExReleaseFastMutex( &LpcpLock );
  303. ObDereferenceObject( WakeupThread );
  304. ObDereferenceObject( PortObject );
  305. return( STATUS_REPLY_MESSAGE_MISMATCH );
  306. }
  307. LpcpTrace(( "%s Sending Reply Wait Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
  308. PsGetCurrentProcess()->ImageFileName,
  309. Msg,
  310. CapturedReplyMessage.MessageId,
  311. CapturedReplyMessage.u2.s2.DataInfoOffset,
  312. *((PULONG)(Msg+1)+0),
  313. *((PULONG)(Msg+1)+1),
  314. *((PULONG)(Msg+1)+2),
  315. *((PULONG)(Msg+1)+3),
  316. WakeupThread,
  317. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  318. ));
  319. if (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) {
  320. LpcpFreeDataInfoMessage( PortObject,
  321. CapturedReplyMessage.MessageId,
  322. CapturedReplyMessage.CallbackId
  323. );
  324. }
  325. //
  326. // Release the mutex that guards the LpcReplyMessage field
  327. // after marking message as being replied to.
  328. //
  329. Msg->RepliedToThread = WakeupThread;
  330. WakeupThread->LpcReplyMessageId = 0;
  331. WakeupThread->LpcReplyMessage = (PVOID)Msg;
  332. //
  333. // Remove the thread from the reply rundown list as we are sending the reply.
  334. //
  335. if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
  336. RemoveEntryList( &WakeupThread->LpcReplyChain );
  337. InitializeListHead( &WakeupThread->LpcReplyChain );
  338. }
  339. CurrentThread->LpcReplyMessageId = CapturedReplyMessage.MessageId;
  340. CurrentThread->LpcReplyMessage = NULL;
  341. if (CurrentThread->LpcReceivedMsgIdValid &&
  342. CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId
  343. ) {
  344. CurrentThread->LpcReceivedMessageId = 0;
  345. CurrentThread->LpcReceivedMsgIdValid = FALSE;
  346. }
  347. ExReleaseFastMutex( &LpcpLock );
  348. //
  349. // Copy the reply message to the request message buffer
  350. //
  351. try {
  352. LpcpMoveMessage( &Msg->Request,
  353. &CapturedReplyMessage,
  354. (ReplyMessage + 1),
  355. LPC_REPLY,
  356. NULL
  357. );
  358. }
  359. except( EXCEPTION_EXECUTE_HANDLER ) {
  360. Status = GetExceptionCode();
  361. ObDereferenceObject( WakeupThread );
  362. ObDereferenceObject( PortObject );
  363. return Status;
  364. }
  365. //
  366. // Wake up the thread that is waiting for an answer to its request
  367. // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That
  368. // will dereference itself when it wakes up.
  369. //
  370. Status = KeReleaseWaitForSemaphore( &WakeupThread->LpcReplySemaphore,
  371. &CurrentThread->LpcReplySemaphore,
  372. Executive,
  373. PreviousMode
  374. );
  375. if (Status == STATUS_USER_APC) {
  376. //
  377. // if the semaphore is signaled, then clear it
  378. //
  379. if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) {
  380. KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore,
  381. WrExecutive,
  382. KernelMode,
  383. FALSE,
  384. NULL
  385. );
  386. Status = STATUS_SUCCESS;
  387. }
  388. }
  389. //
  390. // If the wait succeeded, copy the reply to the reply buffer.
  391. //
  392. if (Status == STATUS_SUCCESS ) {
  393. //
  394. // Acquire the mutex that gaurds the request message
  395. // queue. Remove the request message from the list of
  396. // messages being processed and free the message back to the queue's zone.
  397. // If the zone's free list was zero before freeing this message then
  398. // pulse the free event after free the message so that threads waiting
  399. // to allocate a request message buffer will wake up. Finally,
  400. // release the mutex and return the system service status.
  401. //
  402. ExAcquireFastMutex( &LpcpLock );
  403. Msg = CurrentThread->LpcReplyMessage;
  404. CurrentThread->LpcReplyMessage = NULL;
  405. #if DBG
  406. if (Msg != NULL) {
  407. LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n",
  408. PsGetCurrentProcess()->ImageFileName,
  409. Msg,
  410. Msg->Request.MessageId,
  411. *((PULONG)(Msg+1)+0),
  412. *((PULONG)(Msg+1)+1),
  413. *((PULONG)(Msg+1)+2),
  414. *((PULONG)(Msg+1)+3),
  415. CurrentThread,
  416. THREAD_TO_PROCESS( CurrentThread )->ImageFileName
  417. ));
  418. if (!IsListEmpty( &Msg->Entry )) {
  419. LpcpTrace(( "Reply Msg %lx has non-empty list entry\n", Msg ));
  420. }
  421. }
  422. #endif
  423. ExReleaseFastMutex( &LpcpLock );
  424. if (Msg != NULL) {
  425. try {
  426. LpcpMoveMessage( ReplyMessage,
  427. &Msg->Request,
  428. (&Msg->Request) + 1,
  429. 0,
  430. NULL
  431. );
  432. }
  433. except( EXCEPTION_EXECUTE_HANDLER ) {
  434. Status = GetExceptionCode();
  435. }
  436. //
  437. // Acquire the LPC mutex and decrement the reference count for the
  438. // message. If the reference count goes to zero the message will be
  439. // deleted.
  440. //
  441. ExAcquireFastMutex( &LpcpLock );
  442. if (Msg->RepliedToThread != NULL) {
  443. ObDereferenceObject( Msg->RepliedToThread );
  444. Msg->RepliedToThread = NULL;
  445. }
  446. LpcpFreeToPortZone( Msg, TRUE );
  447. ExReleaseFastMutex( &LpcpLock );
  448. }
  449. }
  450. ObDereferenceObject( PortObject );
  451. return( Status );
  452. }
  453. NTSTATUS
  454. NtReadRequestData(
  455. IN HANDLE PortHandle,
  456. IN PPORT_MESSAGE Message,
  457. IN ULONG DataEntryIndex,
  458. OUT PVOID Buffer,
  459. IN ULONG BufferSize,
  460. OUT PULONG NumberOfBytesRead OPTIONAL
  461. )
  462. {
  463. PAGED_CODE();
  464. return LpcpCopyRequestData( FALSE,
  465. PortHandle,
  466. Message,
  467. DataEntryIndex,
  468. Buffer,
  469. BufferSize,
  470. NumberOfBytesRead
  471. );
  472. }
  473. NTSTATUS
  474. NtWriteRequestData(
  475. IN HANDLE PortHandle,
  476. IN PPORT_MESSAGE Message,
  477. IN ULONG DataEntryIndex,
  478. IN PVOID Buffer,
  479. IN ULONG BufferSize,
  480. OUT PULONG NumberOfBytesWritten OPTIONAL
  481. )
  482. {
  483. PAGED_CODE();
  484. return LpcpCopyRequestData( TRUE,
  485. PortHandle,
  486. Message,
  487. DataEntryIndex,
  488. Buffer,
  489. BufferSize,
  490. NumberOfBytesWritten
  491. );
  492. }
  493. NTSTATUS
  494. LpcpCopyRequestData(
  495. IN BOOLEAN WriteToMessageData,
  496. IN HANDLE PortHandle,
  497. IN PPORT_MESSAGE Message,
  498. IN ULONG DataEntryIndex,
  499. IN PVOID Buffer,
  500. IN ULONG BufferSize,
  501. OUT PULONG NumberOfBytesCopied OPTIONAL
  502. )
  503. {
  504. KPROCESSOR_MODE PreviousMode;
  505. PLPCP_PORT_OBJECT PortObject;
  506. PLPCP_MESSAGE Msg;
  507. PLIST_ENTRY Head, Next;
  508. NTSTATUS Status;
  509. PETHREAD ClientThread;
  510. PPORT_DATA_INFORMATION DataInfo;
  511. PPORT_DATA_ENTRY DataEntry;
  512. PORT_MESSAGE CapturedMessage;
  513. PORT_DATA_INFORMATION CapturedDataInfo;
  514. PORT_DATA_ENTRY CapturedDataEntry;
  515. ULONG BytesCopied;
  516. PAGED_CODE();
  517. //
  518. // Get previous processor mode and probe output arguments if necessary.
  519. //
  520. PreviousMode = KeGetPreviousMode();
  521. if (PreviousMode != KernelMode) {
  522. try {
  523. if (WriteToMessageData) {
  524. ProbeForRead( Buffer,
  525. BufferSize,
  526. 1
  527. );
  528. }
  529. else {
  530. ProbeForWrite( Buffer,
  531. BufferSize,
  532. 1
  533. );
  534. }
  535. ProbeForRead( Message,
  536. sizeof( *Message ),
  537. sizeof( ULONG )
  538. );
  539. CapturedMessage = *Message;
  540. if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
  541. ProbeForWriteUlong( NumberOfBytesCopied );
  542. }
  543. }
  544. except( EXCEPTION_EXECUTE_HANDLER ) {
  545. return( GetExceptionCode() );
  546. }
  547. }
  548. else {
  549. CapturedMessage = *Message;
  550. }
  551. if (CapturedMessage.u2.s2.DataInfoOffset == 0) {
  552. return( STATUS_INVALID_PARAMETER );
  553. }
  554. //
  555. // Reference the port object by handle
  556. //
  557. Status = LpcpReferencePortObject( PortHandle,
  558. 0,
  559. PreviousMode,
  560. &PortObject
  561. );
  562. if (!NT_SUCCESS( Status )) {
  563. return( Status );
  564. }
  565. //
  566. // Translate the ClientId from the connection request into a
  567. // thread pointer. This is a referenced pointer to keep the thread
  568. // from evaporating out from under us.
  569. //
  570. Status = PsLookupProcessThreadByCid( &CapturedMessage.ClientId,
  571. NULL,
  572. &ClientThread
  573. );
  574. if (!NT_SUCCESS( Status )) {
  575. ObDereferenceObject( PortObject );
  576. return( Status );
  577. }
  578. //
  579. // Acquire the mutex that gaurds the LpcReplyMessage field of
  580. // the thread and get the pointer to the message that the thread
  581. // is waiting for a reply to.
  582. //
  583. ExAcquireFastMutex( &LpcpLock );
  584. //
  585. // See if the thread is waiting for a reply to the message
  586. // specified on this call. If not then a bogus message
  587. // has been specified, so release the mutex, dereference the thread
  588. // and return failure.
  589. //
  590. if (ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) {
  591. Status = STATUS_REPLY_MESSAGE_MISMATCH;
  592. }
  593. else {
  594. Status = STATUS_INVALID_PARAMETER;
  595. Msg = LpcpFindDataInfoMessage( PortObject,
  596. CapturedMessage.MessageId,
  597. CapturedMessage.CallbackId
  598. );
  599. if (Msg != NULL) {
  600. DataInfo = (PPORT_DATA_INFORMATION)((PUCHAR)&Msg->Request +
  601. Msg->Request.u2.s2.DataInfoOffset
  602. );
  603. if (DataInfo->CountDataEntries > DataEntryIndex) {
  604. DataEntry = &DataInfo->DataEntries[ DataEntryIndex ];
  605. CapturedDataEntry = *DataEntry;
  606. if (CapturedDataEntry.Size >= BufferSize) {
  607. Status = STATUS_SUCCESS;
  608. }
  609. }
  610. }
  611. }
  612. if (!NT_SUCCESS( Status )) {
  613. ExReleaseFastMutex( &LpcpLock );
  614. ObDereferenceObject( ClientThread );
  615. ObDereferenceObject( PortObject );
  616. return( Status );
  617. }
  618. //
  619. // Release the mutex that guards the LpcReplyMessage field
  620. //
  621. ExReleaseFastMutex( &LpcpLock );
  622. //
  623. // Copy the message data
  624. //
  625. if (WriteToMessageData) {
  626. Status = MmCopyVirtualMemory( PsGetCurrentProcess(),
  627. Buffer,
  628. THREAD_TO_PROCESS( ClientThread ),
  629. CapturedDataEntry.Base,
  630. BufferSize,
  631. PreviousMode,
  632. &BytesCopied
  633. );
  634. }
  635. else {
  636. Status = MmCopyVirtualMemory( THREAD_TO_PROCESS( ClientThread ),
  637. CapturedDataEntry.Base,
  638. PsGetCurrentProcess(),
  639. Buffer,
  640. BufferSize,
  641. PreviousMode,
  642. &BytesCopied
  643. );
  644. }
  645. if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
  646. try {
  647. *NumberOfBytesCopied = BytesCopied;
  648. }
  649. except( EXCEPTION_EXECUTE_HANDLER ) {
  650. NOTHING;
  651. }
  652. }
  653. //
  654. // Dereference client thread and return the system service status.
  655. //
  656. ObDereferenceObject( ClientThread );
  657. ObDereferenceObject( PortObject );
  658. return( Status );
  659. }