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.

609 lines
17 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxsmain.cpp
  5. Abstract:
  6. Author:
  7. Revision History:
  8. --*/
  9. #include "stdinc.h"
  10. #include <windows.h>
  11. #include "sxsp.h"
  12. #include "fusioneventlog.h"
  13. #include "fusiontrace.h"
  14. #include "fusionsha1.h"
  15. extern CRITICAL_SECTION g_csHashFile;
  16. //
  17. // This typedef of a function represents a dll-main startup function. These are
  18. // called during a DLL_PROCESS_ATTACH call to SxsDllMain in the order they're listed.
  19. //
  20. typedef BOOL (WINAPI *PFNStartupPointer)(
  21. HINSTANCE hDllInstnace,
  22. DWORD dwReason,
  23. PVOID pvReason
  24. );
  25. BOOL WINAPI DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  26. BOOL WINAPI FusionpEventLogMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  27. BOOL WINAPI DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  28. BOOL WINAPI DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  29. BOOL WINAPI FusionpCryptoContext_DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  30. BOOL WINAPI DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  31. BOOL WINAPI DllStartup_AlternateAssemblyStoreRoot(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
  32. BOOL WINAPI DllStartup_SetupLog(HINSTANCE Module, DWORD Reason, PVOID Reserved);
  33. BOOL WINAPI DllStartup_FileHashCriticalSectionInitialization(HINSTANCE Module, DWORD Reason, PVOID Reserved);
  34. BOOL WINAPI FusionpAreWeInOSSetupModeMain(HINSTANCE Module, DWORD Reason, PVOID Reserved);
  35. #define MAKE_STARTUP_RECORD(f) { &f, L#f }
  36. #define SXSP_DLLMAIN_ATTACHED 0x01
  37. const struct StartupFunctionRecord {
  38. PFNStartupPointer Handler;
  39. PCWSTR Name;
  40. } g_SxspDllMainStartupPointers[] = {
  41. MAKE_STARTUP_RECORD(DllStartup_CrtInit),
  42. MAKE_STARTUP_RECORD(DllStartup_HeapSetup),
  43. MAKE_STARTUP_RECORD(FusionpEventLogMain),
  44. MAKE_STARTUP_RECORD(DllStartup_AtExitList),
  45. MAKE_STARTUP_RECORD(DllStartup_AlternateAssemblyStoreRoot),
  46. MAKE_STARTUP_RECORD(DllStartup_ActCtxContributors),
  47. MAKE_STARTUP_RECORD(FusionpCryptoContext_DllMain),
  48. MAKE_STARTUP_RECORD(DllStartup_SetupLog),
  49. MAKE_STARTUP_RECORD(DllStartup_FileHashCriticalSectionInitialization),
  50. MAKE_STARTUP_RECORD(FusionpAreWeInOSSetupModeMain)
  51. };
  52. BYTE g_SxspDllMainStartupStatus[NUMBER_OF(g_SxspDllMainStartupPointers)];
  53. HINSTANCE g_hInstance;
  54. /*
  55. NTRAID#NTBUG9-591174-2002/03/31-JayKrell
  56. Replace all SLists with criticalsection and CDeque.
  57. */
  58. SLIST_HEADER sxspAtExitList;
  59. PCWSTR g_AlternateAssemblyStoreRoot;
  60. BOOL g_WriteRegistryAnyway;
  61. #if DBG
  62. PCSTR
  63. FusionpDllMainReasonToString(DWORD Reason)
  64. {
  65. PCSTR String;
  66. String =
  67. (Reason == DLL_THREAD_ATTACH) ? "DLL_THREAD_ATTACH" :
  68. (Reason == DLL_THREAD_DETACH) ? "DLL_THREAD_DETACH" :
  69. (Reason == DLL_PROCESS_ATTACH) ? "DLL_PROCESS_ATTACH" :
  70. (Reason == DLL_PROCESS_DETACH) ? "DLL_PROCESS_DETACH" :
  71. "";
  72. return String;
  73. }
  74. #endif
  75. extern "C"
  76. BOOL
  77. WINAPI
  78. SxsDllMain(
  79. HINSTANCE hInst,
  80. DWORD dwReason,
  81. PVOID pvReserved
  82. )
  83. //
  84. // We do not call DisableThreadLibraryCalls
  85. // because some/all versions of the CRT do work in the thread calls,
  86. // allocation and free of the per thread data.
  87. //
  88. {
  89. //
  90. // Several "oca" (online crash analysis) bugs show
  91. // Sxs.dll in various places in DllMain(process_detach) in hung apps.
  92. // We load in many processes for oleaut/typelibrary support.
  93. //
  94. // When ExitProcess is called, it is impossible to leak memory and kernel handles,
  95. // so it is sufficient and preferrable to do nothing quickly than to go through
  96. // and free each individual resource.
  97. //
  98. // The pvReserved parameter is actually documented as having a meaning.
  99. // Its NULLness indicates if we are in FreeLibrary or ExitProcess.
  100. //
  101. if (dwReason == DLL_PROCESS_DETACH && pvReserved != NULL)
  102. {
  103. // For ExitProcess, do nothing quickly.
  104. return TRUE;
  105. }
  106. BOOL fResult = FALSE;
  107. SIZE_T nCounter = 0;
  108. #if DBG
  109. ::FusionpDbgPrintEx(
  110. FUSION_DBG_LEVEL_VERBOSE,
  111. "SXS: 0x%lx.0x%lx, %s() %s\n",
  112. GetCurrentProcessId(),
  113. GetCurrentThreadId(),
  114. __FUNCTION__,
  115. FusionpDllMainReasonToString(dwReason));
  116. #endif
  117. switch (dwReason)
  118. {
  119. case DLL_THREAD_ATTACH:
  120. if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
  121. {
  122. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  123. ::FusionpDbgPrintEx(
  124. FUSION_DBG_LEVEL_ERROR,
  125. "SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
  126. __FUNCTION__,
  127. g_SxspDllMainStartupPointers[0].Name,
  128. dwLastError,
  129. dwLastError);
  130. ::SxsDllMain(hInst, DLL_THREAD_DETACH, pvReserved);
  131. ::FusionpSetLastWin32Error(dwLastError);
  132. goto Exit;
  133. }
  134. break;
  135. case DLL_THREAD_DETACH:
  136. if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
  137. {
  138. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  139. ::FusionpDbgPrintEx(
  140. FUSION_DBG_LEVEL_ERROR,
  141. "SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
  142. __FUNCTION__,
  143. g_SxspDllMainStartupPointers[0].Name,
  144. dwLastError,
  145. dwLastError);
  146. // Eat the error, the loader ignores it.
  147. }
  148. break;
  149. case DLL_PROCESS_ATTACH:
  150. ASSERT_NTC(hInst);
  151. g_hInstance = hInst;
  152. for (nCounter = 0; nCounter != NUMBER_OF(g_SxspDllMainStartupPointers) ; ++nCounter)
  153. {
  154. const SIZE_T nIndex = nCounter;
  155. if (g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
  156. {
  157. g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
  158. }
  159. else
  160. {
  161. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  162. //
  163. // It's a little iffy to set the bit even upon failure, but
  164. // we do this because we assume individual functions do not handle
  165. // rollback internally upon attach failure.
  166. //
  167. g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
  168. ::FusionpDbgPrintEx(
  169. FUSION_DBG_LEVEL_ERROR,
  170. "SXS: %s - %ls(DLL_PROCESS_ATTACH) failed. Last WinError 0x%08x (%d).\n",
  171. __FUNCTION__,
  172. g_SxspDllMainStartupPointers[nIndex].Name,
  173. dwLastError,
  174. dwLastError);
  175. // pvReserved has approximately the same defined meaning for attach and detach
  176. ::SxsDllMain(hInst, DLL_PROCESS_DETACH, pvReserved);
  177. ::FusionpSetLastWin32Error(dwLastError);
  178. goto Exit;
  179. }
  180. }
  181. break;
  182. case DLL_PROCESS_DETACH:
  183. //
  184. // We always succeed DLL_PROCESS_DETACH, and we do not
  185. // short circuit it upon failure. The loader in fact
  186. // ignores what we return.
  187. //
  188. for (nCounter = NUMBER_OF(g_SxspDllMainStartupPointers) ; nCounter != 0 ; --nCounter)
  189. {
  190. const SIZE_T nIndex = nCounter - 1;
  191. if ((g_SxspDllMainStartupStatus[nIndex] & SXSP_DLLMAIN_ATTACHED) != 0)
  192. {
  193. g_SxspDllMainStartupStatus[nIndex] &= ~SXSP_DLLMAIN_ATTACHED;
  194. if (!g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
  195. {
  196. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  197. ::FusionpDbgPrintEx(
  198. FUSION_DBG_LEVEL_ERROR,
  199. "SXS: %s - %ls(DLL_PROCESS_DETACH) failed. Last WinError 0x%08x (%d).\n",
  200. __FUNCTION__,
  201. g_SxspDllMainStartupPointers[nIndex].Name,
  202. dwLastError,
  203. dwLastError);
  204. }
  205. }
  206. }
  207. break;
  208. }
  209. fResult = TRUE;
  210. Exit:
  211. return fResult;
  212. }
  213. /*
  214. NTRAID#NTBUG9-591174-2002/03/31-JayKrell
  215. Replace all SLists with criticalsection and CDeque.
  216. */
  217. BOOL
  218. SxspAtExit(
  219. CCleanupBase* pCleanup
  220. )
  221. {
  222. if (!pCleanup->m_fInAtExitList)
  223. {
  224. SxspInterlockedPushEntrySList(&sxspAtExitList, pCleanup);
  225. pCleanup->m_fInAtExitList = true;
  226. }
  227. return TRUE;
  228. }
  229. /*
  230. NTRAID#NTBUG9-591174-2002/03/31-JayKrell
  231. Replace all SLists with criticalsection and CDeque.
  232. */
  233. BOOL
  234. SxspTryCancelAtExit(
  235. CCleanupBase* pCleanup
  236. )
  237. {
  238. if (!pCleanup->m_fInAtExitList)
  239. return FALSE;
  240. if (::SxspIsSListEmpty(&sxspAtExitList))
  241. {
  242. pCleanup->m_fInAtExitList = false;
  243. return FALSE;
  244. }
  245. PSLIST_ENTRY pTop = ::SxspInterlockedPopEntrySList(&sxspAtExitList);
  246. if (pTop == pCleanup)
  247. {
  248. pCleanup->m_fInAtExitList = false;
  249. return TRUE;
  250. }
  251. if (pTop != NULL)
  252. ::SxspInterlockedPushEntrySList(&sxspAtExitList, pTop);
  253. return FALSE;
  254. }
  255. #define COMMON_HANDLER_PROLOG(dwReason) \
  256. { \
  257. ASSERT_NTC(\
  258. (dwReason == DLL_PROCESS_ATTACH) || \
  259. (dwReason == DLL_PROCESS_DETACH) \
  260. ); \
  261. if (!(\
  262. (dwReason == DLL_PROCESS_ATTACH) || \
  263. (dwReason == DLL_PROCESS_DETACH) \
  264. )) goto Exit; \
  265. }
  266. BOOL WINAPI
  267. DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
  268. {
  269. BOOL fSuccess = FALSE;
  270. COMMON_HANDLER_PROLOG(dwReason);
  271. switch (dwReason)
  272. {
  273. case DLL_PROCESS_DETACH:
  274. {
  275. CCleanupBase *pCleanup = NULL;
  276. while (pCleanup = UNCHECKED_DOWNCAST<CCleanupBase*>(SxspPopEntrySList(&sxspAtExitList)))
  277. {
  278. pCleanup->m_fInAtExitList = false;
  279. pCleanup->DeleteYourself();
  280. }
  281. fSuccess = TRUE;
  282. }
  283. break;
  284. case DLL_PROCESS_ATTACH:
  285. ::SxspInitializeSListHead(&sxspAtExitList);
  286. fSuccess = TRUE;
  287. break;
  288. }
  289. Exit:
  290. return fSuccess;
  291. }
  292. extern "C"
  293. {
  294. BOOL g_fInCrtInit;
  295. //
  296. // This is the internal CRT routine that does the bulk of
  297. // the initialization and uninitialization.
  298. //
  299. BOOL
  300. WINAPI
  301. _CRT_INIT(
  302. HINSTANCE hDllInstnace,
  303. DWORD dwReason,
  304. PVOID pvReason
  305. );
  306. void
  307. SxspCrtRaiseExit(
  308. PCSTR pszCaller,
  309. int crtError
  310. )
  311. //
  312. // all the various CRT functions that end up calling ExitProcess end up here
  313. // see crt0dat.c
  314. //
  315. {
  316. const static struct
  317. {
  318. NTSTATUS ntstatus;
  319. PCSTR psz;
  320. } rgErrors[] =
  321. {
  322. { STATUS_FATAL_APP_EXIT, "STATUS_FATAL_APP_EXIT" },
  323. { STATUS_DLL_INIT_FAILED, "STATUS_DLL_INIT_FAILED" },
  324. };
  325. const ULONG nInCrtInit = g_fInCrtInit ? 1 : 0;
  326. //
  327. // if (!g_fInCrtInit), then throwing STATUS_DLL_INIT_FAILED is dubious,
  328. // but there no clearly good answer, maybe STATUS_NO_MEMORY, maybe introduce
  329. // an NTSTATUS facility to wrap the values in.
  330. //
  331. ::FusionpDbgPrintEx(
  332. FUSION_DBG_LEVEL_ERROR,
  333. "SXS: [0x%lx.0x%lx] %s(crtError:%d, g_fInCrtInit:%s) calling RaiseException(%08lx %s)\n",
  334. GetCurrentProcessId(),
  335. GetCurrentThreadId(),
  336. pszCaller,
  337. crtError,
  338. nInCrtInit ? "true" : "false",
  339. rgErrors[nInCrtInit].ntstatus,
  340. rgErrors[nInCrtInit].psz
  341. );
  342. ::RaiseException(
  343. static_cast<DWORD>(rgErrors[nInCrtInit].ntstatus),
  344. 0, // flags
  345. 0, // number of extra parameters
  346. NULL); // extra parameters
  347. //
  348. // RaiseException returns void, and generally doesn't return, though it
  349. // can if you intervene in a debugger.
  350. //
  351. }
  352. extern void (__cdecl * _aexit_rtn)(int);
  353. void
  354. __cdecl
  355. SxsCrtAExitRoutine(
  356. int crtError
  357. )
  358. //
  359. // This is our replacement for an internal CRT routine that otherwise
  360. // calls ExitProcess.
  361. //
  362. {
  363. SxspCrtRaiseExit(__FUNCTION__, crtError);
  364. }
  365. }
  366. /*
  367. NTRAID#NTBUG9-591174-2002/03/31-JayKrell
  368. It'd be nice if we could just use msvcrt.dll without this hacking..
  369. */
  370. BOOL WINAPI
  371. DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
  372. /*
  373. This mess is because
  374. we need destructors to run, even if there is an exception
  375. the startup code in msvcrt.dll and libcmt.lib is not very good
  376. it tends to call MessageBox and/or ExitProcess upon out of memory
  377. we need it to simply propagate an error
  378. */
  379. {
  380. #if !FUSION_WIN
  381. //
  382. // having this do-nothing function makes our DLL_THREAD_ATTACH handling simpler.
  383. //
  384. return TRUE;
  385. #else
  386. BOOL fSuccess = FALSE;
  387. DWORD dwExceptionCode = 0;
  388. __try
  389. {
  390. __try
  391. {
  392. g_fInCrtInit = TRUE;
  393. if (dwReason == DLL_PROCESS_ATTACH)
  394. {
  395. _aexit_rtn = SxsCrtAExitRoutine;
  396. //
  397. // __app_type and __error_mode determine if
  398. // _CRT_INIT calls MessageBox or WriteFile(GetStdHandle()) upon errors.
  399. // MessageBox is a big nono in csrss.
  400. // WriteFile we expect to fail, but that's ok, and they don't check
  401. // the return value.
  402. //
  403. // It should be sufficient to set __error_mode.
  404. //
  405. _set_error_mode(_OUT_TO_STDERR);
  406. }
  407. fSuccess = _CRT_INIT(hInstance, dwReason, pvReserved);
  408. }
  409. __finally
  410. {
  411. g_fInCrtInit = FALSE;
  412. }
  413. }
  414. __except(
  415. ( (dwExceptionCode = GetExceptionCode()) == STATUS_DLL_INIT_FAILED
  416. || dwExceptionCode == STATUS_FATAL_APP_EXIT
  417. )
  418. ? EXCEPTION_EXECUTE_HANDLER
  419. : EXCEPTION_CONTINUE_SEARCH)
  420. {
  421. }
  422. return fSuccess;
  423. #endif // FUSION_WIN
  424. }
  425. BOOL WINAPI
  426. DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
  427. {
  428. BOOL fSuccess = FALSE;
  429. COMMON_HANDLER_PROLOG(dwReason);
  430. switch (dwReason)
  431. {
  432. case DLL_PROCESS_ATTACH:
  433. fSuccess = FusionpInitializeHeap(hInstance);
  434. break;
  435. case DLL_PROCESS_DETACH:
  436. #if defined(FUSION_DEBUG_HEAP)
  437. ::FusionpDumpHeap(L"");
  438. #endif
  439. ::FusionpUninitializeHeap();
  440. fSuccess = TRUE;
  441. break;
  442. }
  443. Exit:
  444. return fSuccess;
  445. }
  446. BOOL WINAPI
  447. DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
  448. {
  449. BOOL fSuccess = FALSE;
  450. COMMON_HANDLER_PROLOG(dwReason);
  451. switch (dwReason)
  452. {
  453. case DLL_PROCESS_ATTACH:
  454. fSuccess = SxspInitActCtxContributors();
  455. break;
  456. case DLL_PROCESS_DETACH:
  457. SxspUninitActCtxContributors();
  458. fSuccess = TRUE;
  459. break;
  460. }
  461. Exit:
  462. return fSuccess;
  463. }
  464. BOOL
  465. WINAPI
  466. DllStartup_AlternateAssemblyStoreRoot(HINSTANCE, DWORD dwReason, PVOID pvReserved)
  467. {
  468. BOOL fSuccess = FALSE;
  469. COMMON_HANDLER_PROLOG(dwReason);
  470. switch (dwReason)
  471. {
  472. case DLL_PROCESS_DETACH:
  473. if (g_AlternateAssemblyStoreRoot != NULL)
  474. {
  475. CSxsPreserveLastError ple;
  476. delete[] const_cast<PWSTR>(g_AlternateAssemblyStoreRoot);
  477. g_AlternateAssemblyStoreRoot = NULL;
  478. ple.Restore();
  479. }
  480. fSuccess = TRUE;
  481. break;
  482. case DLL_PROCESS_ATTACH:
  483. g_AlternateAssemblyStoreRoot = NULL;
  484. fSuccess = TRUE;
  485. break;
  486. }
  487. Exit:
  488. return fSuccess;
  489. }
  490. BOOL
  491. WINAPI
  492. DllStartup_FileHashCriticalSectionInitialization(
  493. HINSTANCE hInstance,
  494. DWORD dwReason,
  495. PVOID pvReserved
  496. )
  497. {
  498. BOOL fSuccess = FALSE;
  499. //
  500. // We're always called back on disconnect, which isn't really a bug,
  501. // but a different contract that this can't uphold. Instead, we'll
  502. // keep rollback information here about whether or not the csec was
  503. // initialized.
  504. //
  505. static BOOL s_fCritSecCreated;
  506. COMMON_HANDLER_PROLOG(dwReason);
  507. switch (dwReason)
  508. {
  509. case DLL_PROCESS_DETACH:
  510. if (s_fCritSecCreated)
  511. {
  512. ::DeleteCriticalSection(&g_csHashFile);
  513. s_fCritSecCreated = FALSE;
  514. }
  515. fSuccess = TRUE;
  516. break;
  517. case DLL_PROCESS_ATTACH:
  518. if (!s_fCritSecCreated)
  519. {
  520. if (!::FusionpInitializeCriticalSection(&g_csHashFile))
  521. goto Exit;
  522. s_fCritSecCreated = TRUE;
  523. }
  524. fSuccess = TRUE;
  525. break;
  526. }
  527. Exit:
  528. return fSuccess;
  529. }