Source code of Windows XP (NT5)
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.

596 lines
16 KiB

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