Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
13 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lpcrecv.c
  5. Abstract:
  6. Local Inter-Process Communication (LPC) receive system services.
  7. Author:
  8. Steve Wood (stevewo) 15-May-1989
  9. Revision History:
  10. --*/
  11. #include "lpcp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE,NtReplyWaitReceivePort)
  14. #endif
  15. NTSTATUS
  16. NtReplyWaitReceivePort(
  17. IN HANDLE PortHandle,
  18. OUT PVOID *PortContext OPTIONAL,
  19. IN PPORT_MESSAGE ReplyMessage OPTIONAL,
  20. OUT PPORT_MESSAGE ReceiveMessage
  21. )
  22. {
  23. PLPCP_PORT_OBJECT PortObject;
  24. PLPCP_PORT_OBJECT ReceivePort;
  25. PORT_MESSAGE CapturedReplyMessage;
  26. KPROCESSOR_MODE PreviousMode;
  27. KPROCESSOR_MODE WaitMode;
  28. NTSTATUS Status;
  29. PLPCP_MESSAGE Msg;
  30. PETHREAD CurrentThread;
  31. PETHREAD WakeupThread;
  32. PAGED_CODE();
  33. CurrentThread = PsGetCurrentThread();
  34. //
  35. // Get previous processor mode
  36. //
  37. PreviousMode = KeGetPreviousMode();
  38. WaitMode = PreviousMode;
  39. if (PreviousMode != KernelMode) {
  40. try {
  41. if (ARGUMENT_PRESENT( PortContext )) {
  42. ProbeForWriteUlong( (PULONG)PortContext );
  43. }
  44. if (ARGUMENT_PRESENT( ReplyMessage)) {
  45. ProbeForRead( ReplyMessage,
  46. sizeof( *ReplyMessage ),
  47. sizeof( ULONG )
  48. );
  49. CapturedReplyMessage = *ReplyMessage;
  50. }
  51. ProbeForWrite( ReceiveMessage,
  52. sizeof( *ReceiveMessage ),
  53. sizeof( ULONG )
  54. );
  55. }
  56. except( EXCEPTION_EXECUTE_HANDLER ) {
  57. return( GetExceptionCode() );
  58. }
  59. }
  60. else {
  61. //
  62. // Kernel mode threads call with wait mode of user so that their kernel
  63. // stacks are swappable. Main consumer of this is SepRmCommandThread
  64. //
  65. if ( IS_SYSTEM_THREAD(CurrentThread) ) {
  66. WaitMode = UserMode;
  67. }
  68. if (ARGUMENT_PRESENT( ReplyMessage)) {
  69. CapturedReplyMessage = *ReplyMessage;
  70. }
  71. }
  72. //
  73. // Reference the port object by handle
  74. //
  75. Status = LpcpReferencePortObject( PortHandle,
  76. 0,
  77. PreviousMode,
  78. &PortObject
  79. );
  80. if (!NT_SUCCESS( Status )) {
  81. return( Status );
  82. }
  83. if ((PortObject->Flags & PORT_TYPE) != CLIENT_COMMUNICATION_PORT) {
  84. ReceivePort = PortObject->ConnectionPort;
  85. }
  86. else {
  87. ReceivePort = PortObject;
  88. }
  89. //
  90. // If ReplyMessage argument present, then send reply
  91. //
  92. if (ARGUMENT_PRESENT( ReplyMessage )) {
  93. //
  94. // Translate the ClientId from the connection request into a
  95. // thread pointer. This is a referenced pointer to keep the thread
  96. // from evaporating out from under us.
  97. //
  98. Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
  99. NULL,
  100. &WakeupThread
  101. );
  102. if (!NT_SUCCESS( Status )) {
  103. ObDereferenceObject( PortObject );
  104. return( Status );
  105. }
  106. //
  107. // Acquire the global Lpc mutex that gaurds the LpcReplyMessage
  108. // field of the thread and get the pointer to the message that
  109. // the thread is waiting for a reply to.
  110. //
  111. ExAcquireFastMutex( &LpcpLock );
  112. Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
  113. if (Msg == NULL) {
  114. ExReleaseFastMutex( &LpcpLock );
  115. ObDereferenceObject( WakeupThread );
  116. return( STATUS_NO_MEMORY );
  117. }
  118. //
  119. // See if the thread is waiting for a reply to the message
  120. // specified on this call. If not then a bogus message
  121. // has been specified, so release the mutex, dereference the thread
  122. // and return failure.
  123. //
  124. if (WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId
  125. ) {
  126. LpcpPrint(( "%s Attempted ReplyWaitReceive to Thread %lx (%s)\n",
  127. PsGetCurrentProcess()->ImageFileName,
  128. WakeupThread,
  129. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  130. ));
  131. LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n",
  132. CapturedReplyMessage.MessageId,
  133. CapturedReplyMessage.ClientId.UniqueProcess,
  134. CapturedReplyMessage.ClientId.UniqueThread
  135. ));
  136. LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n",
  137. WakeupThread->LpcReplyMessageId,
  138. WakeupThread->Cid.UniqueProcess,
  139. WakeupThread->Cid.UniqueThread
  140. ));
  141. #if DBG
  142. if (LpcpStopOnReplyMismatch) {
  143. DbgBreakPoint();
  144. }
  145. #endif
  146. LpcpFreeToPortZone( Msg, TRUE );
  147. ExReleaseFastMutex( &LpcpLock );
  148. ObDereferenceObject( WakeupThread );
  149. ObDereferenceObject( PortObject );
  150. return (STATUS_REPLY_MESSAGE_MISMATCH);
  151. }
  152. LpcpTrace(( "%s Sending Reply Msg %lx (%u.%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
  153. PsGetCurrentProcess()->ImageFileName,
  154. Msg,
  155. CapturedReplyMessage.MessageId,
  156. CapturedReplyMessage.CallbackId,
  157. CapturedReplyMessage.u2.s2.DataInfoOffset,
  158. *((PULONG)(Msg+1)+0),
  159. *((PULONG)(Msg+1)+1),
  160. *((PULONG)(Msg+1)+2),
  161. *((PULONG)(Msg+1)+3),
  162. WakeupThread,
  163. THREAD_TO_PROCESS( WakeupThread )->ImageFileName
  164. ));
  165. if (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) {
  166. LpcpFreeDataInfoMessage( PortObject,
  167. CapturedReplyMessage.MessageId,
  168. CapturedReplyMessage.CallbackId
  169. );
  170. }
  171. //
  172. // Release the mutex that guards the LpcReplyMessage field
  173. // after marking message as being replied to.
  174. //
  175. Msg->RepliedToThread = WakeupThread;
  176. WakeupThread->LpcReplyMessageId = 0;
  177. WakeupThread->LpcReplyMessage = (PVOID)Msg;
  178. //
  179. // Remove the thread from the reply rundown list as we are sending the reply.
  180. //
  181. if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
  182. RemoveEntryList( &WakeupThread->LpcReplyChain );
  183. InitializeListHead( &WakeupThread->LpcReplyChain );
  184. }
  185. if (CurrentThread->LpcReceivedMsgIdValid &&
  186. CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId
  187. ) {
  188. CurrentThread->LpcReceivedMessageId = 0;
  189. CurrentThread->LpcReceivedMsgIdValid = FALSE;
  190. }
  191. LpcpTrace(( "%s Waiting for message to Port %x (%s)\n",
  192. PsGetCurrentProcess()->ImageFileName,
  193. ReceivePort,
  194. LpcpGetCreatorName( ReceivePort )
  195. ));
  196. ExReleaseFastMutex( &LpcpLock );
  197. // Copy the reply message to the request message buffer
  198. //
  199. try {
  200. LpcpMoveMessage( &Msg->Request,
  201. &CapturedReplyMessage,
  202. (ReplyMessage + 1),
  203. LPC_REPLY,
  204. NULL
  205. );
  206. }
  207. except( EXCEPTION_EXECUTE_HANDLER ) {
  208. Status = GetExceptionCode(); // FIX, FIX
  209. }
  210. //
  211. // Wake up the thread that is waiting for an answer to its request
  212. // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort
  213. //
  214. Status = KeReleaseWaitForSemaphore( &WakeupThread->LpcReplySemaphore,
  215. ReceivePort->MsgQueue.Semaphore,
  216. WrLpcReceive,
  217. WaitMode
  218. );
  219. //
  220. // Fall into receive code. Client thread reference will be
  221. // returned by the client when it wakes up.
  222. //
  223. }
  224. else {
  225. //
  226. // Wait for a message
  227. //
  228. LpcpTrace(( "%s Waiting for message to Port %x (%s)\n",
  229. PsGetCurrentProcess()->ImageFileName,
  230. ReceivePort,
  231. LpcpGetCreatorName( ReceivePort )
  232. ));
  233. Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore,
  234. WrLpcReceive,
  235. WaitMode,
  236. FALSE,
  237. NULL
  238. );
  239. }
  240. if (Status == STATUS_SUCCESS) {
  241. ExAcquireFastMutex( &LpcpLock );
  242. if (IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead )) {
  243. ExReleaseFastMutex( &LpcpLock );
  244. ObDereferenceObject( PortObject );
  245. return( STATUS_UNSUCCESSFUL );
  246. }
  247. Msg = (PLPCP_MESSAGE)RemoveHeadList( &ReceivePort->MsgQueue.ReceiveHead );
  248. InitializeListHead( &Msg->Entry );
  249. LpcpTrace(( "%s Receive Msg %lx (%u) from Port %lx (%s)\n",
  250. PsGetCurrentProcess()->ImageFileName,
  251. Msg,
  252. Msg->Request.MessageId,
  253. ReceivePort,
  254. LpcpGetCreatorName( ReceivePort )
  255. ));
  256. CurrentThread->LpcReceivedMessageId = Msg->Request.MessageId;
  257. CurrentThread->LpcReceivedMsgIdValid = TRUE;
  258. ExReleaseFastMutex( &LpcpLock );
  259. try {
  260. if (Msg->Request.u2.s2.Type == LPC_CONNECTION_REQUEST) {
  261. PLPCP_CONNECTION_MESSAGE ConnectMsg;
  262. ULONG ConnectionInfoLength;
  263. ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
  264. ConnectionInfoLength = Msg->Request.u1.s1.DataLength -
  265. sizeof( *ConnectMsg );
  266. *ReceiveMessage = Msg->Request;
  267. ReceiveMessage->u1.s1.TotalLength = sizeof( *ReceiveMessage ) +
  268. ConnectionInfoLength;
  269. ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
  270. RtlMoveMemory( ReceiveMessage+1,
  271. ConnectMsg + 1,
  272. ConnectionInfoLength
  273. );
  274. if (ARGUMENT_PRESENT( PortContext )) {
  275. *PortContext = NULL;
  276. }
  277. //
  278. // Dont free message until NtAcceptConnectPort called.
  279. //
  280. Msg = NULL;
  281. }
  282. else
  283. if (Msg->Request.u2.s2.Type != LPC_REPLY) {
  284. LpcpMoveMessage( ReceiveMessage,
  285. &Msg->Request,
  286. (&Msg->Request) + 1,
  287. 0,
  288. NULL
  289. );
  290. if (ARGUMENT_PRESENT( PortContext )) {
  291. *PortContext = Msg->PortContext;
  292. }
  293. //
  294. // If message contains DataInfo for access via NtRead/WriteRequestData
  295. // then put the message on a list in the communication port and dont
  296. // free it. It will be freed when the server replies to the message.
  297. //
  298. if (Msg->Request.u2.s2.DataInfoOffset != 0) {
  299. LpcpSaveDataInfoMessage( PortObject, Msg );
  300. Msg = NULL;
  301. }
  302. }
  303. else {
  304. LpcpPrint(( "LPC: Bogus reply message (%08x) in receive queue of connection port %08x\n",
  305. Msg, ReceivePort
  306. ));
  307. KdBreakPoint();
  308. }
  309. }
  310. except( EXCEPTION_EXECUTE_HANDLER ) {
  311. Status = GetExceptionCode(); // FIX, FIX
  312. }
  313. //
  314. // Acquire the LPC mutex and decrement the reference count for the
  315. // message. If the reference count goes to zero the message will be
  316. // deleted.
  317. //
  318. if (Msg != NULL) {
  319. LpcpFreeToPortZone( Msg, FALSE );
  320. }
  321. }
  322. ObDereferenceObject( PortObject );
  323. return( Status );
  324. }