Leaked source code of windows server 2003
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.

879 lines
30 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. initnt.cxx
  5. Abstract:
  6. This module contains the code used to initialize the RPC runtime. One
  7. routine gets called when a process attaches to the dll. Another routine
  8. gets called the first time an RPC API is called.
  9. Author:
  10. Michael Montague (mikemon) 03-May-1991
  11. Revision History:
  12. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  13. --*/
  14. #include <precomp.hxx>
  15. #include <hndlsvr.hxx>
  16. #include <thrdctx.hxx>
  17. #include <rpccfg.h>
  18. #include <rc4.h>
  19. #include <randlib.h>
  20. #include <epmap.h>
  21. #include <CellHeap.hxx>
  22. #include <lpcpack.hxx>
  23. #include <dispatch.h>
  24. #include <avrf.h>
  25. int RpcHasBeenInitialized = 0;
  26. RTL_CRITICAL_SECTION GlobalMutex;
  27. RPC_SERVER * GlobalRpcServer = NULL;
  28. BOOL g_fClientSideDebugInfoEnabled = FALSE;
  29. BOOL g_fServerSideDebugInfoEnabled = FALSE;
  30. BOOL g_fSendEEInfo = FALSE;
  31. BOOL g_fIgnoreDelegationFailure = FALSE;
  32. LRPC_SERVER *GlobalLrpcServer = NULL;
  33. HINSTANCE hInstanceDLL ;
  34. EXTERN_C HINSTANCE g_hRpcrt4;
  35. DWORD gPageSize;
  36. DWORD gThreadTimeout;
  37. UINT gNumberOfProcessors;
  38. DWORD gAllocationGranularity;
  39. BOOL gfServerPlatform;
  40. ULONGLONG gPhysicalMemorySize; // in megabytes
  41. DWORD gProcessStartTime;
  42. // The local machine's name.
  43. RPC_CHAR *gLocalComputerName;
  44. // The length of the name in TCHAR's including the terminating NULL.
  45. DWORD gLocalComputerNameLength;
  46. UNICODE_STRING *pBaseNameUnicodeString;
  47. //
  48. // RPC Verifier settings
  49. //
  50. BOOL gfAppVerifierEnabled = false;
  51. BOOL gfPagedHeapEnabled = false;
  52. BOOL gfRPCVerifierEnabled = false;
  53. BOOL gfRpcVerifierCorruptionExpected = false;
  54. // The basic rules for the RPC verifier settings are as follows:
  55. //
  56. // - If the app verifier is enabled RPC will do some basic checks.
  57. // gfAppVerifierEnabled == true
  58. // gfRPCVerifierEnabled == false
  59. //
  60. // - If the /rpc switch is enabled for the app verifier the RPC verifier
  61. // will do extensive checks and will query for corruption injection settings.
  62. // gfAppVerifierEnabled == true
  63. // gfRPCVerifierEnabled == true
  64. //
  65. // - If paged heap is enabled the RPC verifier will be enabled and will do
  66. // extensive checks silently. No breaks will occur, by default. We will also
  67. // query for the corruption injection settings.
  68. // gfPagedHeapEnabled == true;
  69. // gfRPCVerifierEnabled == true;
  70. // gfAppVerifierEnabled == false;
  71. //
  72. // In the other cases the RPC verifier code is inactive.
  73. // The contents of the RpcVerifierFlags key of the image file options.
  74. DWORD RpcVerifierFlags = 0x00000000;
  75. // RPC verifier flag constants.
  76. //
  77. // These are written to RpcVerifierFlags key in the image file execution options
  78. // in the registry. We query the flags on RPC initialization and set the global
  79. // variables accordingly.
  80. #define FLAG_FAULT_INJECT_IMPERSONATE_CLIENT 0x00000001
  81. #define FLAG_CORRUPTION_INJECT_SERVER_RECEIVES 0x00000010
  82. #define FLAG_CORRUPTION_INJECT_CLIENT_RECEIVES 0x00000020
  83. #define FLAG_FAULT_INJECT_TRANSPORTS 0x00000100
  84. #define FLAG_PAUSE_INJECT_EXTERNAL_APIS 0x00001000
  85. #define FLAG_SUPRESS_APP_VERIFIER_BREAKS 0x00010000
  86. #define FLAG_BCACHE_MODE_DIRECT 0x00020000
  87. // The structure will be allocated and initialised with the RPC
  88. // verifier settings whenever the RPC verifier is enabled.
  89. tRpcVerifierSettings *pRpcVerifierSettings = NULL;
  90. //
  91. // By default the non pipe arguments cannot be more than 4 Megs
  92. //
  93. DWORD gMaxRpcSize = 0x400000;
  94. DWORD gProrateStart = 0;
  95. DWORD gProrateMax = 0;
  96. DWORD gProrateFactor = 0;
  97. void *g_rc4SafeCtx = 0;
  98. BOOL gfRpcDisableVerifyOrUnsealAssert = FALSE;
  99. extern "C" {
  100. BOOLEAN
  101. InitializeDLL (
  102. IN HINSTANCE DllHandle,
  103. IN ULONG Reason,
  104. IN PCONTEXT Context OPTIONAL
  105. )
  106. /*++
  107. Routine Description:
  108. This routine will get called: when a process attaches to this dll, and
  109. when a process detaches from this dll.
  110. Return Value:
  111. TRUE - Initialization successfully occurred.
  112. FALSE - Insufficient memory is available for the process to attach to
  113. this dll.
  114. --*/
  115. {
  116. NTSTATUS NtStatus;
  117. UNUSED(Context);
  118. switch (Reason)
  119. {
  120. case DLL_PROCESS_ATTACH:
  121. hInstanceDLL = DllHandle ;
  122. g_hRpcrt4 = DllHandle;
  123. GlobalMutex.DebugInfo = NULL;
  124. NtStatus = RtlInitializeCriticalSectionAndSpinCount(&GlobalMutex, PREALLOCATE_EVENT_MASK);
  125. if (NT_SUCCESS(NtStatus) == 0)
  126. {
  127. return(FALSE);
  128. }
  129. // initialize safe rc4 operations.
  130. if(!rc4_safe_startup( &g_rc4SafeCtx ))
  131. {
  132. (void) RtlDeleteCriticalSection(&GlobalMutex);
  133. return FALSE;
  134. }
  135. break;
  136. case DLL_PROCESS_DETACH:
  137. //
  138. // If shutting down because of a FreeLibrary call, cleanup
  139. //
  140. if (Context == NULL)
  141. {
  142. ShutdownLrpcClient();
  143. }
  144. if (GlobalMutex.DebugInfo != NULL)
  145. {
  146. NtStatus = RtlDeleteCriticalSection(&GlobalMutex);
  147. ASSERT(NT_SUCCESS(NtStatus));
  148. }
  149. if (g_rc4SafeCtx)
  150. rc4_safe_shutdown( g_rc4SafeCtx ); // free safe rc4 resources.
  151. break;
  152. case DLL_THREAD_DETACH:
  153. THREAD * Thread = RpcpGetThreadPointer();
  154. #ifdef RPC_OLD_IO_PROTECTION
  155. if (Thread)
  156. {
  157. Thread->UnprotectThread();
  158. }
  159. #else
  160. delete Thread;
  161. #endif
  162. break;
  163. }
  164. return(TRUE);
  165. }
  166. } //extern "C" end
  167. #ifdef NO_RECURSIVE_MUTEXES
  168. unsigned int RecursionCount = 0;
  169. #endif // NO_RECURSIVE_MUTEXES
  170. extern int InitializeRpcAllocator(void);
  171. extern RPC_STATUS ReadPolicySettings(void);
  172. const ULONG MEGABYTE = 0x100000;
  173. typedef struct tagBasicSystemInfo
  174. {
  175. DWORD m_dwPageSize;
  176. ULONGLONG m_dwPhysicalMemorySize;
  177. DWORD m_dwNumberOfProcessors;
  178. ULONG AllocationGranularity;
  179. BOOL m_fServerPlatform;
  180. } BasicSystemInfo;
  181. BOOL
  182. GetBasicSystemInfo (
  183. IN OUT BasicSystemInfo *basicSystemInfo
  184. )
  185. /*++
  186. Routine Description:
  187. Gets basic system information. We don't use the Win32 GetSystemInfo, because
  188. under NT it accesses the image header, which may not be available if the image
  189. was loaded from the network, and the network failed. Therefore, we need a function
  190. that accesses just what we need, and nothing else.
  191. Arguments:
  192. The basic system info structure.
  193. Return Value:
  194. 0 - failure
  195. non-0 - success.
  196. --*/
  197. {
  198. //
  199. // Query system info (for # of processors) and product type
  200. //
  201. SYSTEM_BASIC_INFORMATION BasicInfo;
  202. NTSTATUS Status;
  203. BOOL b;
  204. Status = NtQuerySystemInformation(
  205. SystemBasicInformation,
  206. &BasicInfo,
  207. sizeof(BasicInfo),
  208. NULL
  209. );
  210. if ( !NT_SUCCESS(Status) )
  211. {
  212. DbgPrintEx(DPFLTR_RPCPROXY_ID,
  213. DPFLTR_ERROR_LEVEL,
  214. "RPCTRANS: NtQuerySystemInformation failed: %x\n",
  215. Status);
  216. return 0;
  217. }
  218. basicSystemInfo->m_dwPageSize = BasicInfo.PageSize;
  219. basicSystemInfo->m_dwNumberOfProcessors = BasicInfo.NumberOfProcessors;
  220. basicSystemInfo->m_dwPhysicalMemorySize = ((BasicInfo.NumberOfPhysicalPages * (ULONGLONG) basicSystemInfo->m_dwPageSize) / MEGABYTE);
  221. basicSystemInfo->AllocationGranularity = BasicInfo.AllocationGranularity;
  222. NT_PRODUCT_TYPE type;
  223. b = RtlGetNtProductType(&type);
  224. if (b)
  225. {
  226. basicSystemInfo->m_fServerPlatform = (type != NtProductWinNt);
  227. return 1;
  228. }
  229. else
  230. {
  231. DbgPrintEx(DPFLTR_RPCPROXY_ID,
  232. DPFLTR_ERROR_LEVEL,
  233. "RpcGetNtProductType failed, usign default\n");
  234. return 0;
  235. }
  236. }
  237. // Used in InitializeRpcVerifier
  238. // The macro requires pBaseNameUnicodeString to be declared in order to function.
  239. #define READ_DWORD_FROM_EXECUTION_OPTIONS(Key, Variable) \
  240. { \
  241. LdrQueryImageFileExecutionOptions (pBaseNameUnicodeString, \
  242. Key, \
  243. REG_DWORD, \
  244. &Variable, \
  245. sizeof(Variable), \
  246. NULL); \
  247. }
  248. // This is the global RPC heap where all allocations go to.
  249. // If we are running with read-only RPC page heap then this
  250. // will be a special heap created for us by Avrf rather then
  251. // the process heap.
  252. extern HANDLE hRpcHeap;
  253. void
  254. InitializeRpcVerifier (
  255. void
  256. )
  257. /*++
  258. Routine Description:
  259. Performs initialization of the RPC verifier. Sets everything necessary for the basic
  260. checks and extensive checks. Queries the image file options for custom
  261. checks and enbales the selected ones
  262. Arguments:
  263. None
  264. Return Value:
  265. None - The only failure paths are registry IOs. We will just skip some checks on failures.
  266. --*/
  267. {
  268. HMODULE hDll;
  269. VERIFIER_QUERY_RUNTIME_FLAGS_FUNCTION VerifierQueryRuntimeFlags;
  270. VERIFIER_CREATE_RPC_PAGE_HEAP_FUNCTION VerifierCreateRpcPageHeap;
  271. DWORD dwTmp;
  272. // Allocate the RPC verifier settings.
  273. pRpcVerifierSettings = new tRpcVerifierSettings;
  274. // If we could not allocate them, ignore the failure and return.
  275. // We chose not to run with the RPC verifier rather then prevent the process
  276. // from initializing.
  277. if (pRpcVerifierSettings == NULL)
  278. {
  279. return;
  280. }
  281. //
  282. // Set the RPC verifier settings to defaults.
  283. //
  284. // Fault injecting ImpersonateClient calls
  285. pRpcVerifierSettings->fFaultInjectImpersonateClient = false;
  286. pRpcVerifierSettings->ProbFaultInjectImpersonateClient = 100; // Default is 0.01
  287. pRpcVerifierSettings->DelayFaultInjectImpersonateClient = 0; // Delay before fault injection starts is 0 sec.
  288. // Corruption injecting the received data
  289. pRpcVerifierSettings->fCorruptionInjectServerReceives = false;
  290. pRpcVerifierSettings->fCorruptionInjectClientReceives = false;
  291. pRpcVerifierSettings->ProbRpcHeaderCorruption = 100; // Default is 0.01
  292. pRpcVerifierSettings->ProbDataCorruption = 100; // Default is 0.01
  293. pRpcVerifierSettings->ProbSecureDataCorruption = 10; // Default is 0.001
  294. pRpcVerifierSettings->CorruptionPattern = Randomize;
  295. pRpcVerifierSettings->CorruptionSizeType = RandomSize;
  296. pRpcVerifierSettings->CorruptionSize = 2;
  297. pRpcVerifierSettings->CorruptionDistributionType = LocalizedDistribution;
  298. pRpcVerifierSettings->ProbBufferTruncation = 0;
  299. pRpcVerifierSettings->MaxBufferTruncationSize = 0x10;
  300. // Fault injecting calls to transport routines
  301. pRpcVerifierSettings->fFaultInjectTransports = false;
  302. pRpcVerifierSettings->ProbFaultInjectTransports = 10; // Default is 0.001
  303. // Inserting pauses after calls to external APIs
  304. pRpcVerifierSettings->fPauseInjectExternalAPIs = false;
  305. pRpcVerifierSettings->ProbPauseInjectExternalAPIs = 100; // Default is 0.01
  306. pRpcVerifierSettings->PauseInjectExternalAPIsMaxWait = 10; // Default average delay is 10 milliseconds.
  307. // By default all verifier breaks are active.
  308. pRpcVerifierSettings->fSupressAppVerifierBreaks = false;
  309. pRpcVerifierSettings->fReadonlyPagedHeap = false;
  310. //
  311. // Enable the basic checks.
  312. //
  313. // Catch orphaned critical sections on return from the server managed routines.
  314. DispatchToStubInC = DispatchToStubInCAvrf;
  315. //
  316. // Check if the RPC verifier is enabled.
  317. //
  318. // When running under the app verifier we query it
  319. // to see whether the RPC verifier is enabled.
  320. if (gfAppVerifierEnabled)
  321. {
  322. // Try to load the app verifier dll.
  323. hDll = LoadLibrary(RPC_CONST_SSTRING("verifier.dll"));
  324. if (hDll != NULL)
  325. {
  326. // Try to import the function to query the app verifier flags.
  327. VerifierQueryRuntimeFlags = (VERIFIER_QUERY_RUNTIME_FLAGS_FUNCTION)GetProcAddress(hDll, "VerifierQueryRuntimeFlags");
  328. if (VerifierQueryRuntimeFlags != NULL)
  329. {
  330. LOGICAL fEnabled = FALSE;
  331. ULONG Flags = 0;
  332. // Query the app veirfier flags and see if the rpc switch is set.
  333. NTSTATUS Status = VerifierQueryRuntimeFlags(&fEnabled, &Flags);
  334. if ((Status == STATUS_SUCCESS) &&
  335. (fEnabled) &&
  336. (Flags & RTL_VRF_FLG_RPC_CHECKS))
  337. {
  338. gfRPCVerifierEnabled = true;
  339. }
  340. }
  341. // Try to import the function to create a read-only paged heap.
  342. VerifierCreateRpcPageHeap = (VERIFIER_CREATE_RPC_PAGE_HEAP_FUNCTION)GetProcAddress(hDll, "VerifierCreateRpcPageHeap");
  343. FreeLibrary(hDll);
  344. }
  345. }
  346. // If app verifier is not enabled we must be initializing because of paged heap.
  347. else
  348. {
  349. ASSERT(gfPagedHeapEnabled);
  350. gfRPCVerifierEnabled = true;
  351. // When initializing under paged heap - disable verifier breaks.
  352. pRpcVerifierSettings->fSupressAppVerifierBreaks = true;
  353. }
  354. //
  355. // If the RPC Verifier is enabled load the settings from the image file options.
  356. //
  357. if (gfRPCVerifierEnabled)
  358. {
  359. DWORD PageHeapFaultProbability = 0;
  360. //
  361. // Enable the extensive checks.
  362. //
  363. // Use read-only paged heap if the app verifier and the RPC verifier are enabled.
  364. // The trigger to use the read-only "RPC" paged heap is a reg key or
  365. // the use of process-wide paged heap.
  366. if (gfAppVerifierEnabled &&
  367. gfPagedHeapEnabled)
  368. {
  369. // Try to create the read-only RPC heap.
  370. if (VerifierCreateRpcPageHeap != NULL)
  371. {
  372. VERIFIER_DBG_PRINT_0("Creating RPC pahe heap with VerifierCreateRpcPageHeap\n");
  373. PVOID pRpcPageHeap = VerifierCreateRpcPageHeap (
  374. HEAP_GROWABLE
  375. | HEAP_TAIL_CHECKING_ENABLED
  376. | HEAP_FREE_CHECKING_ENABLED, // Flags
  377. NULL, // HeapBase
  378. 16 * 1024 - 512, // ReserveSize
  379. NULL, // CommitSize
  380. NULL, // Lock
  381. NULL); // PRTL_HEAP_PARAMETERS Parameters
  382. VERIFIER_DBG_PRINT_1("VerifierCreateRpcPageHeap returned 0x%x\n", pRpcPageHeap);
  383. if (pRpcPageHeap != NULL)
  384. {
  385. hRpcHeap = pRpcPageHeap;
  386. pRpcVerifierSettings->fReadonlyPagedHeap = true;
  387. // Set BCache to direct mode. Allocations will be done on the heap
  388. // and will skip caching.
  389. gBCacheMode = BCacheModeDirect;
  390. }
  391. }
  392. }
  393. // Extend the RPC log size.
  394. // At this point the RPC allocator has been initialized and this resulted in the creation
  395. // of the event log and the addition of some events. We will just re-allocate for simplicity.
  396. // There are no threads in the RPC runtime and we are holding the global lock, so there
  397. // are no races.
  398. struct RPC_EVENT * TmpRpcEvents;
  399. TmpRpcEvents = (struct RPC_EVENT *) HeapReAlloc(GetProcessHeap(),
  400. 0,
  401. RpcEvents,
  402. 2*EventArrayLength*sizeof(RPC_EVENT));
  403. // If reallocation has failed we will just keep the old log.
  404. if (TmpRpcEvents != NULL)
  405. {
  406. RpcEvents = TmpRpcEvents;
  407. EventArrayLength *= 2;
  408. }
  409. //
  410. // Query and enable the custom checks.
  411. //
  412. // Query the image file execution options for the custom checks and their options.
  413. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierFlags",
  414. RpcVerifierFlags);
  415. // Set the global flags in accordance with the enabled checks.
  416. if (RpcVerifierFlags & FLAG_FAULT_INJECT_IMPERSONATE_CLIENT)
  417. pRpcVerifierSettings->fFaultInjectImpersonateClient = true;
  418. if (RpcVerifierFlags & FLAG_CORRUPTION_INJECT_SERVER_RECEIVES)
  419. {
  420. pRpcVerifierSettings->fCorruptionInjectServerReceives = true;
  421. // if we are corrupting receives, then corruption asserts
  422. // are expected
  423. gfRpcVerifierCorruptionExpected = true;
  424. }
  425. if (RpcVerifierFlags & FLAG_CORRUPTION_INJECT_CLIENT_RECEIVES)
  426. {
  427. pRpcVerifierSettings->fCorruptionInjectClientReceives = true;
  428. // if we are corrupting receives, then corruption asserts
  429. // are expected
  430. gfRpcVerifierCorruptionExpected = true;
  431. }
  432. if (RpcVerifierFlags & FLAG_FAULT_INJECT_TRANSPORTS)
  433. pRpcVerifierSettings->fFaultInjectTransports = true;
  434. if (RpcVerifierFlags & FLAG_PAUSE_INJECT_EXTERNAL_APIS)
  435. pRpcVerifierSettings->fPauseInjectExternalAPIs = true;
  436. if (RpcVerifierFlags & FLAG_SUPRESS_APP_VERIFIER_BREAKS)
  437. pRpcVerifierSettings->fSupressAppVerifierBreaks = true;
  438. if (RpcVerifierFlags & FLAG_BCACHE_MODE_DIRECT)
  439. gBCacheMode = BCacheModeDirect;
  440. // Check if we should fault-inject ImpersonateClient calls.
  441. // If paged heap is enabled with fault injection
  442. // we should set ImpersonateClient to fail and use the paged heap settings
  443. READ_DWORD_FROM_EXECUTION_OPTIONS (L"PageHeapFaultProbability",
  444. PageHeapFaultProbability);
  445. if (PageHeapFaultProbability)
  446. {
  447. pRpcVerifierSettings->fFaultInjectImpersonateClient = true;
  448. pRpcVerifierSettings->ProbFaultInjectImpersonateClient = PageHeapFaultProbability;
  449. READ_DWORD_FROM_EXECUTION_OPTIONS (L"PageHeapFaultTimeOut",
  450. pRpcVerifierSettings->DelayFaultInjectImpersonateClient);
  451. }
  452. // Check to see if explicit setting are given in the registry.
  453. // We will overwrite the paged heap settings with the explicit ones.
  454. if (pRpcVerifierSettings->fFaultInjectImpersonateClient)
  455. {
  456. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierProbFaultInjectImpersonateClient",
  457. pRpcVerifierSettings->ProbFaultInjectImpersonateClient);
  458. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierDelayFaultInjectImpersonateClient",
  459. pRpcVerifierSettings->DelayFaultInjectImpersonateClient);
  460. }
  461. // Check if we should corruption-inject server receives.
  462. if (pRpcVerifierSettings->fCorruptionInjectServerReceives)
  463. {
  464. // If yes, then whack the server receive IOEventDispatchTable entries to point to
  465. // Avrf routines for the server receives.
  466. IOEventDispatchTable[ConnectionServerReceive] = ProcessConnectionServerReceivedEventAvrf;
  467. IOEventDispatchTable[DatagramServerReceive] = ProcessDatagramServerReceiveEventAvrf;
  468. IOEventDispatchTable[COMPLEX_T | CONNECTION | RECEIVE | SERVER] = ProcessComplexTReceiveAvrf;
  469. }
  470. // Check if we should corruption-inject client receives.
  471. if (pRpcVerifierSettings->fCorruptionInjectClientReceives)
  472. {
  473. // If yes, then whack the client receive IOEventDispatchTable entries to point to
  474. // Avrf routines for the client receives.
  475. IOEventDispatchTable[ConnectionClientReceive] = ProcessConnectionClientReceiveEventAvrf;
  476. IOEventDispatchTable[DatagramClientReceive] = ProcessDatagramClientReceiveEventAvrf;
  477. IOEventDispatchTable[COMPLEX_T | CONNECTION | RECEIVE | CLIENT] = ProcessComplexTReceiveAvrf;
  478. // The SyncSendRecv and SyncRecv members of the transport interfaces will
  479. // be overwritten on transport load:
  480. //
  481. // TCP_TransportInterface: WS_SyncRecv->WS_SyncRecv_Avrf
  482. // NMP_TransportInterface: NMP_SyncSendRecv->NMP_SyncSendRecv_Avrf, CO_SyncRecv->CO_SyncRecv_Avrf
  483. // UDP_TransportInterface: DG_ReceivePacket->DG_ReceivePacket_Avrf;
  484. // CDP_TransportInterface: DG_ReceivePacket->DG_ReceivePacket_Avrf;
  485. //
  486. // This will allow the corruption of sync client receives.
  487. }
  488. // If we are corruption-injecting, read the corruption settings from the registry.
  489. if (pRpcVerifierSettings->fCorruptionInjectServerReceives ||
  490. pRpcVerifierSettings->fCorruptionInjectClientReceives)
  491. {
  492. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierProbRpcHeaderCorruption",
  493. pRpcVerifierSettings->ProbRpcHeaderCorruption);
  494. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierProbDataCorruption",
  495. pRpcVerifierSettings->ProbDataCorruption);
  496. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierProbSecureDataCorruption",
  497. pRpcVerifierSettings->ProbSecureDataCorruption);
  498. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierCorruptionPattern",
  499. pRpcVerifierSettings->CorruptionPattern);
  500. ASSERT(pRpcVerifierSettings->CorruptionPattern == ZeroOut ||
  501. pRpcVerifierSettings->CorruptionPattern == Negate ||
  502. pRpcVerifierSettings->CorruptionPattern == BitFlip ||
  503. pRpcVerifierSettings->CorruptionPattern == IncDec ||
  504. pRpcVerifierSettings->CorruptionPattern == Randomize ||
  505. pRpcVerifierSettings->CorruptionPattern == AllPatterns);
  506. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierCorruptionSizeType",
  507. pRpcVerifierSettings->CorruptionSizeType);
  508. ASSERT (pRpcVerifierSettings->CorruptionDistributionType == FixedSize ||
  509. pRpcVerifierSettings->CorruptionDistributionType == RandomSize);
  510. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierCorruptionSize",
  511. pRpcVerifierSettings->CorruptionSize);
  512. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierCorruptionDistributionType",
  513. pRpcVerifierSettings->CorruptionDistributionType);
  514. ASSERT(pRpcVerifierSettings->CorruptionDistributionType == LocalizedDistribution ||
  515. pRpcVerifierSettings->CorruptionDistributionType == RandomizedDistribution);
  516. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierProbBufferTruncation",
  517. pRpcVerifierSettings->ProbBufferTruncation);
  518. READ_DWORD_FROM_EXECUTION_OPTIONS (L"RpcVerifierMaxBufferTruncationSize",
  519. pRpcVerifierSettings->MaxBufferTruncationSize);
  520. }
  521. }
  522. }
  523. RPC_STATUS
  524. PerformRpcInitialization (
  525. void
  526. )
  527. /*++
  528. Routine Description:
  529. This routine will get called the first time that an RPC runtime API is
  530. called. There is actually a race condition, which we prevent by grabbing
  531. a mutex and then performing the initialization. We only want to
  532. initialize once.
  533. Return Value:
  534. RPC_S_OK - This status code indicates that the runtime has been correctly
  535. initialized and is ready to go.
  536. RPC_S_OUT_OF_MEMORY - If initialization failed, it is most likely due to
  537. insufficient memory being available.
  538. --*/
  539. {
  540. RPC_STATUS Status = RPC_S_OK;
  541. #if DBG
  542. // Catch cases when this function is called recursively.
  543. // This can lead to stack overflow in low-memory conditions.
  544. static BOOL fInPerformRpcInitialization; // Initialized to FALSE.
  545. #endif
  546. if ( RpcHasBeenInitialized == 0 )
  547. {
  548. RequestGlobalMutex();
  549. #if DBG
  550. ASSERT(fInPerformRpcInitialization == FALSE);
  551. fInPerformRpcInitialization = TRUE;
  552. #endif
  553. if ( RpcHasBeenInitialized == 0 )
  554. {
  555. BasicSystemInfo SystemInfo;
  556. BOOL b;
  557. // We need to make sure that from this point on RPC will not be
  558. // unloaded. This requires a load library call to "lock" rpcrt4.dll in
  559. // memory. If the dll is not locked then it may be unloaded as a dependency with
  560. // active critical sections, etc.
  561. if (LoadLibrary(RPC_CONST_SSTRING("rpcrt4.dll")) == 0)
  562. {
  563. Status = RPC_S_OUT_OF_MEMORY;
  564. goto Cleanup;
  565. }
  566. b = GetBasicSystemInfo(&SystemInfo);
  567. if (!b)
  568. {
  569. Status = RPC_S_OUT_OF_MEMORY;
  570. goto Cleanup;
  571. }
  572. gNumberOfProcessors = SystemInfo.m_dwNumberOfProcessors;
  573. gPageSize = SystemInfo.m_dwPageSize;
  574. gAllocationGranularity = SystemInfo.AllocationGranularity;
  575. gfServerPlatform = SystemInfo.m_fServerPlatform;
  576. gPhysicalMemorySize = SystemInfo.m_dwPhysicalMemorySize;
  577. gProcessStartTime = GetTickCount();
  578. //
  579. // We need to init the RPC allocator before doing any memory allocations.
  580. //
  581. // Should be something like 64kb / 4kb.
  582. ASSERT(gAllocationGranularity % gPageSize == 0);
  583. if (( InitializeRpcAllocator() != 0)
  584. || ( InitializeServerDLL() != 0 ))
  585. {
  586. Status = RPC_S_OUT_OF_MEMORY;
  587. goto Cleanup;
  588. }
  589. // Allocate space for the computer name.
  590. gLocalComputerName = new RPC_CHAR[MAX_COMPUTERNAME_LENGTH+1];
  591. if (gLocalComputerName == NULL)
  592. {
  593. Status = RPC_S_OUT_OF_MEMORY;
  594. goto Cleanup;
  595. }
  596. gLocalComputerNameLength = MAX_COMPUTERNAME_LENGTH+1;
  597. b = GetComputerNameW(gLocalComputerName,
  598. &gLocalComputerNameLength);
  599. if (b != TRUE)
  600. {
  601. DWORD LastError = GetLastError();
  602. if (LastError == ERROR_NOT_ENOUGH_MEMORY)
  603. {
  604. Status = RPC_S_OUT_OF_MEMORY;
  605. }
  606. else if ((LastError == ERROR_NOT_ENOUGH_QUOTA)
  607. || (LastError == ERROR_NO_SYSTEM_RESOURCES))
  608. {
  609. Status = RPC_S_OUT_OF_RESOURCES;
  610. }
  611. else if (LastError == ERROR_WRITE_PROTECT)
  612. {
  613. Status = RPC_S_ACCESS_DENIED;
  614. }
  615. else
  616. {
  617. ASSERT(0);
  618. Status = RPC_S_OUT_OF_MEMORY;
  619. }
  620. goto Cleanup;
  621. }
  622. // GetComputerNameW returns in gLocalComputerNameLength the size of
  623. // the computer name in TCHARs NOT including the terminating NULL.
  624. // We define this length to include the NULL and need to increment it.
  625. gLocalComputerNameLength++;
  626. //
  627. // Check for the app verifier settings.
  628. //
  629. gfAppVerifierEnabled = (NtCurrentPeb()->NtGlobalFlag & FLG_APPLICATION_VERIFIER) != 0;
  630. gfPagedHeapEnabled = (NtCurrentPeb()->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS) != 0;
  631. // Initialize the image base name to be used when querying the execution options.
  632. pBaseNameUnicodeString = FastGetImageBaseNameUnicodeString();
  633. // Initialize the RPC verifier if app verifier is enabled or paged heap is enabled.
  634. if (gfAppVerifierEnabled
  635. || gfPagedHeapEnabled)
  636. {
  637. // The function does not fail.
  638. // The worst thing that happens is we don't get some checks.
  639. InitializeRpcVerifier();
  640. }
  641. Status = InitializeEPMapperClient();
  642. if (Status != RPC_S_OK)
  643. {
  644. goto Cleanup;
  645. }
  646. Status = ReadPolicySettings();
  647. if (Status != RPC_S_OK)
  648. {
  649. goto Cleanup;
  650. }
  651. if (gfServerPlatform)
  652. {
  653. gThreadTimeout = 90*1000;
  654. }
  655. else
  656. {
  657. gThreadTimeout = 30*1000;
  658. }
  659. Status = InitializeCellHeap();
  660. if (Status != RPC_S_OK)
  661. {
  662. goto Cleanup;
  663. }
  664. RpcHasBeenInitialized = 1;
  665. goto Cleanup;
  666. }
  667. else
  668. {
  669. goto Cleanup;
  670. }
  671. }
  672. return(RPC_S_OK);
  673. Cleanup:
  674. #if DBG
  675. ASSERT(fInPerformRpcInitialization == TRUE);
  676. fInPerformRpcInitialization = FALSE;
  677. #endif
  678. GlobalMutexVerifyOwned();
  679. ClearGlobalMutex();
  680. return Status;
  681. }
  682. #ifdef DBG
  683. long lGlobalMutexCount = 0;
  684. #endif
  685. void
  686. GlobalMutexRequestExternal (
  687. void
  688. )
  689. /*++
  690. Routine Description:
  691. Request the global mutex.
  692. --*/
  693. {
  694. GlobalMutexRequest();
  695. }
  696. void
  697. GlobalMutexClearExternal (
  698. void
  699. )
  700. /*++
  701. Routine Description:
  702. Clear the global mutex.
  703. --*/
  704. {
  705. GlobalMutexClear();
  706. }