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.

694 lines
19 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. thread.c
  5. Abstract:
  6. This module implements verification functions for thread interfaces.
  7. Author:
  8. Silviu Calinoiu (SilviuC) 22-Feb-2001
  9. Revision History:
  10. Daniel Mihai (DMihai) 25-Apr-2002
  11. Hook thread pool and WMI threads.
  12. --*/
  13. #include "pch.h"
  14. #include "verifier.h"
  15. #include "support.h"
  16. #include "logging.h"
  17. #include "tracker.h"
  18. //
  19. // Why do we hook Exit/TerminateThread instead of NtTerminateThread?
  20. //
  21. // Because kernel32 calls NtTerminateThread in legitimate contexts.
  22. // After all this is the implementation for Exit/TerminateThread.
  23. // It would be difficult to discriminate good calls from bad calls.
  24. // So we prefer to intercept Exit/Thread and returns from thread
  25. // functions.
  26. //
  27. //
  28. // Standard function used for hooking a thread function.
  29. //
  30. DWORD
  31. WINAPI
  32. AVrfpStandardThreadFunction (
  33. LPVOID Info
  34. );
  35. //
  36. // Common point to check for thread termination.
  37. //
  38. VOID
  39. AVrfpCheckThreadTermination (
  40. HANDLE Thread
  41. );
  42. VOID
  43. AVrfpCheckCurrentThreadTermination (
  44. VOID
  45. );
  46. /////////////////////////////////////////////////////////////////////
  47. /////////////////////////////////////////////////////////////////////
  48. /////////////////////////////////////////////////////////////////////
  49. //WINBASEAPI
  50. DECLSPEC_NORETURN
  51. VOID
  52. WINAPI
  53. AVrfpExitProcess(
  54. IN UINT uExitCode
  55. )
  56. {
  57. typedef VOID (WINAPI * FUNCTION_TYPE) (UINT);
  58. FUNCTION_TYPE Function;
  59. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  60. AVRF_INDEX_KERNEL32_EXITPROCESS);
  61. //
  62. // Check out if there are other threads running while ExitProcess
  63. // gets called. This can cause problems because the threads are
  64. // terminated unconditionally and then ExitProcess() calls
  65. // LdrShutdownProcess() which will try to notify all DLLs to cleanup.
  66. // During cleanup any number of operations can happen that will result
  67. // in deadlocks since all those threads have been terminated
  68. // unconditionally
  69. //
  70. #if 0
  71. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DANGEROUS_APIS) != 0) {
  72. PCHAR InfoBuffer;
  73. ULONG RequiredLength = 0;
  74. ULONG NumberOfThreads;
  75. ULONG EntryOffset;
  76. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  77. NTSTATUS Status;
  78. Status = NtQuerySystemInformation (SystemProcessInformation,
  79. NULL,
  80. 0,
  81. &RequiredLength);
  82. if (Status == STATUS_INFO_LENGTH_MISMATCH && RequiredLength != 0) {
  83. InfoBuffer = AVrfpAllocate (RequiredLength);
  84. if (InfoBuffer) {
  85. //
  86. // Note that the RequiredLength is not 100% guaranteed to be good
  87. // since in between the two query calls several other processes
  88. // may have been created. If this is the case we bail out and skip
  89. // the verification.
  90. //
  91. Status = NtQuerySystemInformation (SystemProcessInformation,
  92. InfoBuffer,
  93. RequiredLength,
  94. NULL);
  95. if (NT_SUCCESS(Status)) {
  96. EntryOffset = 0;
  97. NumberOfThreads = 0;
  98. do {
  99. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&InfoBuffer[EntryOffset];
  100. if (ProcessInfo->UniqueProcessId == NtCurrentTeb()->ClientId.UniqueProcess) {
  101. NumberOfThreads = ProcessInfo->NumberOfThreads;
  102. break;
  103. }
  104. EntryOffset += ProcessInfo->NextEntryOffset;
  105. } while(ProcessInfo->NextEntryOffset != 0);
  106. ASSERT (NumberOfThreads > 0);
  107. if (NumberOfThreads > 1) {
  108. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL | APPLICATION_VERIFIER_NO_BREAK,
  109. "ExitProcess() called while multiple threads are running",
  110. NumberOfThreads, "Number of threads running",
  111. 0, NULL, 0, NULL, 0, NULL);
  112. }
  113. }
  114. else {
  115. DbgPrint ("AVRF: NtQuerySystemInformation(SystemProcessInformation) "
  116. "failed with %X \n",
  117. Status);
  118. }
  119. //
  120. // We are done with the buffer. Time to free it.
  121. //
  122. AVrfpFree (InfoBuffer);
  123. }
  124. }
  125. else {
  126. DbgPrint ("AVRF: NtQuerySystemInformation(SystemProcessInformation, null) "
  127. "failed with %X \n",
  128. Status);
  129. }
  130. }
  131. #endif // #if 0
  132. //
  133. // Make a note of who called ExitProcess(). This can be helpful for debugging
  134. // weird process shutdown hangs.
  135. //
  136. AVrfLogInTracker (AVrfThreadTracker,
  137. TRACK_EXIT_PROCESS,
  138. (PVOID)(ULONG_PTR)uExitCode,
  139. NULL, NULL, NULL, _ReturnAddress());
  140. //
  141. // Call the real thing.
  142. //
  143. (* Function)(uExitCode);
  144. }
  145. //WINBASEAPI
  146. DECLSPEC_NORETURN
  147. VOID
  148. WINAPI
  149. AVrfpExitThread(
  150. IN DWORD dwExitCode
  151. )
  152. {
  153. typedef VOID (WINAPI * FUNCTION_TYPE) (DWORD);
  154. FUNCTION_TYPE Function;
  155. PAVRF_THREAD_ENTRY Entry;
  156. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  157. AVRF_INDEX_KERNEL32_EXITTHREAD);
  158. //
  159. // Perform all typical checks for a thread that will exit.
  160. //
  161. AVrfpCheckCurrentThreadTermination ();
  162. //
  163. // Before calling the real ExitThread we need to free the thread
  164. // entry from the thread table.
  165. //
  166. Entry = AVrfpThreadTableSearchEntry (NtCurrentTeb()->ClientId.UniqueThread);
  167. //
  168. // N.B. It is possible to not find an entry in the thread table if the
  169. // thread was not created using CreateThread but rather some more
  170. // basic function from ntdll.dll.
  171. //
  172. if (Entry != NULL) {
  173. AVrfpThreadTableRemoveEntry (Entry);
  174. AVrfpFree (Entry);
  175. }
  176. //
  177. // Call the real thing.
  178. //
  179. (* Function)(dwExitCode);
  180. }
  181. //WINBASEAPI
  182. DECLSPEC_NORETURN
  183. VOID
  184. WINAPI
  185. AVrfpFreeLibraryAndExitThread(
  186. IN HMODULE hLibModule,
  187. IN DWORD dwExitCode
  188. )
  189. {
  190. typedef VOID (WINAPI * FUNCTION_TYPE) (HMODULE, DWORD);
  191. FUNCTION_TYPE Function;
  192. PAVRF_THREAD_ENTRY Entry;
  193. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  194. AVRF_INDEX_KERNEL32_FREELIBRARYANDEXITTHREAD);
  195. //
  196. // Perform all typical checks for a thread that will exit.
  197. //
  198. AVrfpCheckCurrentThreadTermination ();
  199. //
  200. // Before calling the real FreeLibraryAndExitThread we need to free the thread
  201. // entry from the thread table.
  202. //
  203. Entry = AVrfpThreadTableSearchEntry (NtCurrentTeb()->ClientId.UniqueThread);
  204. //
  205. // N.B. It is possible to not find an entry in the thread table if the
  206. // thread was not created using CreateThread but rather some more
  207. // basic function from ntdll.dll.
  208. //
  209. if (Entry != NULL) {
  210. AVrfpThreadTableRemoveEntry (Entry);
  211. AVrfpFree (Entry);
  212. }
  213. //
  214. // Call the real thing.
  215. //
  216. (* Function)(hLibModule, dwExitCode);
  217. }
  218. /////////////////////////////////////////////////////////////////////
  219. /////////////////////////////////// Terminate thread / Suspend thread
  220. /////////////////////////////////////////////////////////////////////
  221. //WINBASEAPI
  222. BOOL
  223. WINAPI
  224. AVrfpTerminateThread(
  225. IN OUT HANDLE hThread,
  226. IN DWORD dwExitCode
  227. )
  228. {
  229. typedef BOOL (WINAPI * FUNCTION_TYPE) (HANDLE, DWORD);
  230. FUNCTION_TYPE Function;
  231. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  232. AVRF_INDEX_KERNEL32_TERMINATETHREAD);
  233. //
  234. // Keep track of who calls TerminateThread() even if we are going to break
  235. // for it. This helps investigations of deadlocked processes that have run
  236. // without the dangerous_apis check enabled.
  237. //
  238. AVrfLogInTracker (AVrfThreadTracker,
  239. TRACK_TERMINATE_THREAD,
  240. hThread,
  241. NULL, NULL, NULL, _ReturnAddress());
  242. //
  243. // Perform all typical checks for a thread that will exit.
  244. //
  245. AVrfpCheckThreadTermination (hThread);
  246. //
  247. // This API should not be called. We need to report this.
  248. // This is useful if we did not detect any orphans but we still want
  249. // to complain.
  250. //
  251. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DANGEROUS_APIS) != 0) {
  252. VERIFIER_STOP (APPLICATION_VERIFIER_TERMINATE_THREAD_CALL | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  253. "TerminateThread() called. This function should not be used.",
  254. NtCurrentTeb()->ClientId.UniqueThread, "Caller thread ID",
  255. 0, NULL, 0, NULL, 0, NULL);
  256. }
  257. return (* Function)(hThread, dwExitCode);
  258. }
  259. /////////////////////////////////////////////////////////////////////
  260. /////////////////////////////////////////////////////////////////////
  261. /////////////////////////////////////////////////////////////////////
  262. //WINBASEAPI
  263. DWORD
  264. WINAPI
  265. AVrfpSuspendThread(
  266. IN HANDLE hThread
  267. )
  268. {
  269. typedef DWORD (WINAPI * FUNCTION_TYPE) (HANDLE);
  270. FUNCTION_TYPE Function;
  271. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  272. AVRF_INDEX_KERNEL32_SUSPENDTHREAD);
  273. //
  274. // Keep track of who calls SuspendThread() even if we are not going to break
  275. // for it. This helps investigations of deadlocked processes.
  276. //
  277. AVrfLogInTracker (AVrfThreadTracker,
  278. TRACK_SUSPEND_THREAD,
  279. hThread,
  280. NULL, NULL, NULL, _ReturnAddress());
  281. //
  282. // One might think that we can check for orphan locks at this point
  283. // by calling RtlCheckForOrphanedCriticalSections(hThread).
  284. // Unfortunately this cannot be done because garbage collectors
  285. // for various virtual machines (Java, C#) can do this in valid
  286. // conditions.
  287. //
  288. return (* Function)(hThread);
  289. }
  290. /////////////////////////////////////////////////////////////////////
  291. /////////////////////////////////////////////////////////////////////
  292. /////////////////////////////////////////////////////////////////////
  293. //WINBASEAPI
  294. HANDLE
  295. WINAPI
  296. AVrfpCreateThread(
  297. IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
  298. IN SIZE_T dwStackSize,
  299. IN LPTHREAD_START_ROUTINE lpStartAddress,
  300. IN LPVOID lpParameter,
  301. IN DWORD dwCreationFlags,
  302. OUT LPDWORD lpThreadId
  303. )
  304. /*++
  305. CreateThread hook
  306. --*/
  307. {
  308. typedef HANDLE (WINAPI * FUNCTION_TYPE) (LPSECURITY_ATTRIBUTES,
  309. SIZE_T,
  310. LPTHREAD_START_ROUTINE,
  311. LPVOID,
  312. DWORD,
  313. LPDWORD);
  314. FUNCTION_TYPE Function;
  315. HANDLE Result;
  316. PAVRF_THREAD_ENTRY Info;
  317. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  318. AVRF_INDEX_KERNEL32_CREATETHREAD);
  319. Info = AVrfpAllocate (sizeof *Info);
  320. if (Info == NULL) {
  321. NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
  322. return NULL;
  323. }
  324. Info->Parameter = lpParameter;
  325. Info->Function = lpStartAddress;
  326. Info->ParentThreadId = NtCurrentTeb()->ClientId.UniqueThread;
  327. Info->StackSize = dwStackSize;
  328. Info->CreationFlags = dwCreationFlags;
  329. Result = (* Function) (lpThreadAttributes,
  330. dwStackSize,
  331. AVrfpStandardThreadFunction,
  332. (PVOID)Info,
  333. dwCreationFlags,
  334. lpThreadId);
  335. if (Result == FALSE) {
  336. AVrfpFree (Info);
  337. }
  338. return Result;
  339. }
  340. ULONG
  341. AVrfpThreadFunctionExceptionFilter (
  342. ULONG ExceptionCode,
  343. PVOID ExceptionRecord
  344. )
  345. {
  346. //
  347. // Skip timeout exceptions because they are dealt with in
  348. // the default exception handler.
  349. //
  350. if (ExceptionCode == STATUS_POSSIBLE_DEADLOCK) {
  351. return EXCEPTION_CONTINUE_SEARCH;
  352. }
  353. //
  354. // Skip breakpoint exceptions raised within thread functions.
  355. //
  356. if (ExceptionCode == STATUS_BREAKPOINT) {
  357. return EXCEPTION_CONTINUE_SEARCH;
  358. }
  359. VERIFIER_STOP (APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  360. "unexpected exception raised in thread function",
  361. ExceptionCode, "Exception code.",
  362. ((PEXCEPTION_POINTERS)ExceptionRecord)->ExceptionRecord, "Exception record. Use .exr to display it.",
  363. ((PEXCEPTION_POINTERS)ExceptionRecord)->ContextRecord, "Context record. Use .cxr to display it.",
  364. 0, "");
  365. //
  366. // After we issued a verifier stop, if we decide to continue then
  367. // we need to look for the next exception handler.
  368. //
  369. return EXCEPTION_CONTINUE_SEARCH;
  370. }
  371. DWORD
  372. WINAPI
  373. AVrfpStandardThreadFunction (
  374. LPVOID Context
  375. )
  376. {
  377. PAVRF_THREAD_ENTRY Info = (PAVRF_THREAD_ENTRY)Context;
  378. DWORD Result;
  379. PAVRF_THREAD_ENTRY SearchEntry;
  380. //
  381. // The initialization below matters only in case the thread function raises
  382. // an access violation. In most cases this will terminate the entire
  383. // process.
  384. //
  385. Result = 0;
  386. try {
  387. //
  388. // Add the thread entry to the thread table.
  389. //
  390. Info->Id = NtCurrentTeb()->ClientId.UniqueThread;
  391. AVrfpThreadTableAddEntry (Info);
  392. //
  393. // Call the real thing.
  394. //
  395. Result = (Info->Function)(Info->Parameter);
  396. }
  397. except (AVrfpThreadFunctionExceptionFilter (_exception_code(), _exception_info())) {
  398. //
  399. // Nothing.
  400. //
  401. }
  402. //
  403. // Perform all typical checks for a thread that has just finished.
  404. //
  405. AVrfpCheckCurrentThreadTermination ();
  406. //
  407. // The thread entry should be `Info' but we will search it in the thread
  408. // table nevertheless because there is a case when they can be different.
  409. // This happens if fibers are used and a fiber starts in one thread and
  410. // exits in another one. It is not clear if this is a safe programming
  411. // practice but it is not rejected by current implementation and
  412. // documentation.
  413. //
  414. SearchEntry = AVrfpThreadTableSearchEntry (NtCurrentTeb()->ClientId.UniqueThread);
  415. if (SearchEntry != NULL) {
  416. AVrfpThreadTableRemoveEntry (SearchEntry);
  417. AVrfpFree (SearchEntry);
  418. }
  419. return Result;
  420. }
  421. /////////////////////////////////////////////////////////////////////
  422. ///////////////////////////////////////////// thread pool thread hook
  423. /////////////////////////////////////////////////////////////////////
  424. PRTLP_START_THREAD AVrfpBaseCreateThreadPoolThreadOriginal;
  425. PRTLP_EXIT_THREAD AVrfpBaseExitThreadPoolThreadOriginal;
  426. NTSTATUS
  427. NTAPI
  428. AVrfpBaseCreateThreadPoolThread(
  429. PUSER_THREAD_START_ROUTINE Function,
  430. PVOID Parameter,
  431. HANDLE * ThreadHandleReturn
  432. )
  433. {
  434. PAVRF_THREAD_ENTRY Info;
  435. PTEB Teb;
  436. NTSTATUS Status = STATUS_SUCCESS;
  437. Teb = NtCurrentTeb();
  438. Info = AVrfpAllocate (sizeof *Info);
  439. if (Info == NULL) {
  440. Status = STATUS_NO_MEMORY;
  441. goto Done;
  442. }
  443. Info->Parameter = Parameter;
  444. Info->Function = (PTHREAD_START_ROUTINE)Function;
  445. Info->ParentThreadId = Teb->ClientId.UniqueThread;
  446. Status = (*AVrfpBaseCreateThreadPoolThreadOriginal) ((PUSER_THREAD_START_ROUTINE)AVrfpStandardThreadFunction,
  447. Info,
  448. ThreadHandleReturn);
  449. Done:
  450. if (!NT_SUCCESS(Status)) {
  451. if (Info != NULL) {
  452. AVrfpFree (Info);
  453. }
  454. Teb->LastStatusValue = Status;
  455. }
  456. return Status;
  457. }
  458. NTSTATUS
  459. NTAPI
  460. AVrfpBaseExitThreadPoolThread(
  461. NTSTATUS Status
  462. )
  463. {
  464. PAVRF_THREAD_ENTRY Entry;
  465. //
  466. // Perform all typical checks for a thread that will exit.
  467. //
  468. AVrfpCheckCurrentThreadTermination ();
  469. //
  470. // Before calling the real ExitThread we need to free the thread
  471. // entry from the thread table.
  472. //
  473. Entry = AVrfpThreadTableSearchEntry (NtCurrentTeb()->ClientId.UniqueThread);
  474. if (Entry != NULL) {
  475. AVrfpThreadTableRemoveEntry (Entry);
  476. AVrfpFree (Entry);
  477. }
  478. //
  479. // Call the real thing.
  480. //
  481. return (*AVrfpBaseExitThreadPoolThreadOriginal) (Status);
  482. }
  483. NTSTATUS
  484. NTAPI
  485. AVrfpRtlSetThreadPoolStartFunc(
  486. PRTLP_START_THREAD StartFunc,
  487. PRTLP_EXIT_THREAD ExitFunc
  488. )
  489. {
  490. //
  491. // Save the original thread pool start and exit functions.
  492. //
  493. AVrfpBaseCreateThreadPoolThreadOriginal = StartFunc;
  494. AVrfpBaseExitThreadPoolThreadOriginal = ExitFunc;
  495. //
  496. // Hook the thread pool start and exit functions to our private version.
  497. //
  498. return RtlSetThreadPoolStartFunc (AVrfpBaseCreateThreadPoolThread,
  499. AVrfpBaseExitThreadPoolThread);
  500. }
  501. /////////////////////////////////////////////////////////////////////
  502. /////////////////////////////////////////////////////////////////////
  503. /////////////////////////////////////////////////////////////////////
  504. VOID
  505. AVrfpCheckThreadTermination (
  506. HANDLE Thread
  507. )
  508. {
  509. //
  510. // Traverse the list of critical sections and look for any that
  511. // have issues (double initialized, corrupted, etc.). The function
  512. // will also break for locks abandoned (owned by the thread just
  513. // about to terminate).
  514. //
  515. RtlCheckForOrphanedCriticalSections (Thread);
  516. }
  517. VOID
  518. AVrfpCheckCurrentThreadTermination (
  519. VOID
  520. )
  521. {
  522. PAVRF_TLS_STRUCT TlsStruct;
  523. TlsStruct = AVrfpGetVerifierTlsValue();
  524. if (TlsStruct != NULL && TlsStruct->CountOfOwnedCriticalSections > 0) {
  525. AVrfpCheckThreadTermination (NtCurrentThread());
  526. }
  527. }