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.

526 lines
12 KiB

  1. #include "ntsdextp.h"
  2. #define REASONABLE_NUMBER 8
  3. typedef BOOL (_ID_MATCH_FN)(
  4. PVOID A,
  5. PVOID B);
  6. typedef _ID_MATCH_FN * PID_MATCH_FN;
  7. typedef VOID (_ID_BANNER_FN)(
  8. PVOID Id
  9. );
  10. typedef _ID_BANNER_FN * PID_BANNER_FN;
  11. typedef VOID (_HANDLE_CALLBACK_FN)(
  12. PVOID Context,
  13. HANDLE Here,
  14. HANDLE There
  15. );
  16. typedef _HANDLE_CALLBACK_FN * PHANDLE_CALLBACK_FN;
  17. #define MATCH_LARGE_INT ((PID_MATCH_FN)1)
  18. typedef struct _HANDLE_TRACK {
  19. LIST_ENTRY List ;
  20. ULONG Flags ;
  21. ULONG Count ;
  22. ULONG Size ;
  23. PHANDLE Handles ;
  24. HANDLE HandleList[ REASONABLE_NUMBER ];
  25. UCHAR IdData[ 1 ];
  26. } HANDLE_TRACK, * PHANDLE_TRACK ;
  27. typedef struct _HANDLE_TRACK_ARRAY {
  28. ULONG Count ;
  29. ULONG Size ;
  30. ULONG IdDataSize ;
  31. PID_MATCH_FN MatchFunc ;
  32. LIST_ENTRY List ;
  33. } HANDLE_TRACK_ARRAY, * PHANDLE_TRACK_ARRAY ;
  34. typedef struct _THREAD_TRACK_INFO {
  35. CLIENT_ID Id ;
  36. PVOID Win32StartAddress ;
  37. DWORD Status ;
  38. } THREAD_TRACK_INFO ;
  39. typedef struct _HANDLE_LEAK_HELPER {
  40. PWSTR Type ;
  41. PID_BANNER_FN Banner ;
  42. PHANDLE_CALLBACK_FN Filter ;
  43. ULONG ArraySize ;
  44. PID_MATCH_FN Match ;
  45. } HANDLE_LEAK_HELPER, * PHANDLE_LEAK_HELPER ;
  46. _ID_BANNER_FN ThreadBanner ;
  47. _ID_BANNER_FN TokenBanner ;
  48. _HANDLE_CALLBACK_FN ThreadCallback ;
  49. _HANDLE_CALLBACK_FN TokenCallback ;
  50. HANDLE_LEAK_HELPER HandleLeakHelpers[] = {
  51. { L"Thread", ThreadBanner, ThreadCallback, sizeof( THREAD_TRACK_INFO ), MATCH_LARGE_INT },
  52. { L"Token", TokenBanner, TokenCallback, sizeof( TOKEN_CONTROL ), MATCH_LARGE_INT }
  53. };
  54. PHANDLE_TRACK_ARRAY
  55. CreateArray(
  56. ULONG IdDataSize,
  57. PID_MATCH_FN MatchFn
  58. )
  59. {
  60. PHANDLE_TRACK_ARRAY Array ;
  61. Array = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( HANDLE_TRACK_ARRAY ) );
  62. if ( Array )
  63. {
  64. Array->Count = 0 ;
  65. Array->Size = 0;
  66. Array->IdDataSize = IdDataSize ;
  67. Array->MatchFunc = MatchFn ;
  68. InitializeListHead( &Array->List );
  69. return Array ;
  70. }
  71. return NULL ;
  72. }
  73. VOID
  74. DeleteArray(
  75. PHANDLE_TRACK_ARRAY Array
  76. )
  77. {
  78. ULONG i ;
  79. PHANDLE_TRACK Track ;
  80. while ( !IsListEmpty( &Array->List ) )
  81. {
  82. Track = (PHANDLE_TRACK) RemoveHeadList( &Array->List );
  83. if ( Track->Handles != Track->HandleList )
  84. {
  85. RtlFreeHeap( RtlProcessHeap(), 0, Track->Handles );
  86. }
  87. RtlFreeHeap( RtlProcessHeap(), 0, Track );
  88. }
  89. RtlFreeHeap( RtlProcessHeap(), 0, Array );
  90. }
  91. VOID
  92. ExtendTrack(
  93. PHANDLE_TRACK Track
  94. )
  95. {
  96. PHANDLE NewHandle ;
  97. NewHandle = RtlAllocateHeap( RtlProcessHeap(), 0, (Track->Size + REASONABLE_NUMBER ) *
  98. sizeof( HANDLE ) );
  99. if ( NewHandle )
  100. {
  101. CopyMemory( NewHandle,
  102. Track->Handles,
  103. Track->Count * sizeof( HANDLE ) );
  104. if ( Track->Handles != Track->HandleList )
  105. {
  106. RtlFreeHeap( RtlProcessHeap(), 0, Track->Handles );
  107. }
  108. Track->Handles = NewHandle ;
  109. Track->Size += REASONABLE_NUMBER ;
  110. }
  111. }
  112. VOID
  113. AddHandleToArray(
  114. PHANDLE_TRACK_ARRAY Array,
  115. PVOID IdData,
  116. HANDLE Handle
  117. )
  118. {
  119. ULONG i;
  120. ULONG j;
  121. BOOL Match ;
  122. PHANDLE_TRACK Track ;
  123. PLIST_ENTRY Scan ;
  124. Scan = Array->List.Flink ;
  125. while ( Scan != &Array->List )
  126. {
  127. Track = (PHANDLE_TRACK) Scan ;
  128. if ( Array->MatchFunc == MATCH_LARGE_INT )
  129. {
  130. Match = ((PLARGE_INTEGER) Track->IdData)->QuadPart ==
  131. ((PLARGE_INTEGER) IdData)->QuadPart ;
  132. }
  133. else
  134. {
  135. Match = Array->MatchFunc( Track->IdData, IdData );
  136. }
  137. if ( Match )
  138. {
  139. //
  140. // We have a match:
  141. //
  142. if ( Track->Count == Track->Size )
  143. {
  144. ExtendTrack( Track );
  145. }
  146. if ( Track->Count < Track->Size )
  147. {
  148. Track->Handles[
  149. Track->Count ] = Handle ;
  150. Track->Count++;
  151. }
  152. return ;
  153. }
  154. Scan = Scan->Flink ;
  155. }
  156. //
  157. // No match, gotta add a new tid
  158. //
  159. Track = RtlAllocateHeap( RtlProcessHeap(), 0,
  160. sizeof( HANDLE_TRACK ) + Array->IdDataSize );
  161. if ( Track )
  162. {
  163. Track->Size = REASONABLE_NUMBER ;
  164. Track->Count = 1 ;
  165. Track->Handles = Track->HandleList ;
  166. Track->HandleList[0] = Handle ;
  167. CopyMemory( Track->IdData, IdData, Array->IdDataSize );
  168. InsertTailList( &Array->List, &Track->List );
  169. }
  170. }
  171. VOID
  172. DumpArray(
  173. PHANDLE_TRACK_ARRAY Array,
  174. PID_BANNER_FN Banner
  175. )
  176. {
  177. ULONG j;
  178. PHANDLE_TRACK Track ;
  179. PLIST_ENTRY Scan ;
  180. Scan = Array->List.Flink ;
  181. while ( Scan != &Array->List )
  182. {
  183. Track = (PHANDLE_TRACK) Scan ;
  184. Banner( Track->IdData );
  185. dprintf(" Handles \t%d: ", Track->Count );
  186. for ( j = 0 ; j < Track->Count ; j++ )
  187. {
  188. dprintf("%x, ", Track->Handles[j] );
  189. }
  190. dprintf("\n");
  191. Scan = Scan->Flink ;
  192. }
  193. }
  194. VOID
  195. HandleScanner(
  196. HANDLE hCurrentProcess,
  197. PWSTR Type,
  198. PVOID Context,
  199. PHANDLE_CALLBACK_FN Callback
  200. )
  201. {
  202. DWORD HandleCount;
  203. NTSTATUS Status;
  204. DWORD Total;
  205. DWORD Handle;
  206. DWORD Hits;
  207. DWORD Matches;
  208. HANDLE hHere ;
  209. PHANDLE_TRACK_ARRAY Array ;
  210. POBJECT_TYPE_INFORMATION pTypeInfo;
  211. UCHAR Buffer[1024];
  212. Status = NtQueryInformationProcess( hCurrentProcess,
  213. ProcessHandleCount,
  214. &HandleCount,
  215. sizeof( HandleCount ),
  216. NULL );
  217. if ( !NT_SUCCESS( Status ) )
  218. {
  219. return;
  220. }
  221. Hits = 0;
  222. Handle = 0;
  223. Matches = 0;
  224. while ( Hits < HandleCount )
  225. {
  226. Status = NtDuplicateObject( hCurrentProcess, (HANDLE)(DWORD_PTR)Handle,
  227. NtCurrentProcess(), &hHere,
  228. 0, 0,
  229. DUPLICATE_SAME_ACCESS );
  230. if ( NT_SUCCESS( Status ) )
  231. {
  232. pTypeInfo = (POBJECT_TYPE_INFORMATION) Buffer;
  233. ZeroMemory( Buffer, 1024 );
  234. Status = NtQueryObject( hHere, ObjectTypeInformation, pTypeInfo, 1024, NULL );
  235. if (NT_SUCCESS(Status))
  236. {
  237. if ( wcscmp( pTypeInfo->TypeName.Buffer, Type ) == 0 )
  238. {
  239. //
  240. // Score!
  241. //
  242. Callback( Context, hHere, (HANDLE)(DWORD_PTR)Handle );
  243. Matches++ ;
  244. }
  245. }
  246. Hits++ ;
  247. NtClose( hHere );
  248. }
  249. Handle += 4;
  250. }
  251. dprintf("%d handles to objects of type %ws\n", Matches, Type );
  252. }
  253. VOID
  254. ThreadBanner(
  255. PVOID Id
  256. )
  257. {
  258. UCHAR Symbol[ MAX_PATH ];
  259. DWORD_PTR Disp ;
  260. THREAD_TRACK_INFO * Info ;
  261. UCHAR ExitStatus[ 32 ];
  262. Info = (THREAD_TRACK_INFO *) Id ;
  263. Symbol[0] = '\0';
  264. GetSymbol( Info->Win32StartAddress, Symbol, &Disp );
  265. if ( Info->Status != STILL_ACTIVE )
  266. {
  267. sprintf(ExitStatus, " Stopped, %#x", Info->Status );
  268. }
  269. else
  270. {
  271. strcpy( ExitStatus, "<Running>");
  272. }
  273. if ( Symbol[0] )
  274. {
  275. dprintf("Thread %x.%x (%s) %s\n", Info->Id.UniqueProcess,
  276. Info->Id.UniqueThread,
  277. Symbol,
  278. ExitStatus );
  279. }
  280. else
  281. {
  282. dprintf("Thread %x.%x %s\n", Info->Id.UniqueProcess,
  283. Info->Id.UniqueThread,
  284. ExitStatus );
  285. }
  286. }
  287. VOID
  288. ThreadCallback(
  289. PVOID Context,
  290. HANDLE Here,
  291. HANDLE There
  292. )
  293. {
  294. NTSTATUS Status ;
  295. THREAD_BASIC_INFORMATION Info;
  296. THREAD_TRACK_INFO ThdInfo ;
  297. ZeroMemory( &ThdInfo, sizeof( ThdInfo ) );
  298. Status = NtQueryInformationThread( Here,
  299. ThreadBasicInformation,
  300. &Info,
  301. sizeof( Info ),
  302. NULL );
  303. if ( NT_SUCCESS( Status ) )
  304. {
  305. ThdInfo.Id = Info.ClientId ;
  306. ThdInfo.Status = Info.ExitStatus ;
  307. Status = NtQueryInformationThread( Here,
  308. ThreadQuerySetWin32StartAddress,
  309. &ThdInfo.Win32StartAddress,
  310. sizeof( PVOID ),
  311. NULL );
  312. AddHandleToArray( Context, &ThdInfo , There );
  313. }
  314. }
  315. VOID
  316. TokenCallback(
  317. PVOID Context,
  318. HANDLE Here,
  319. HANDLE There
  320. )
  321. {
  322. NTSTATUS Status ;
  323. TOKEN_CONTROL Control ;
  324. TOKEN_STATISTICS Stats ;
  325. ULONG Size ;
  326. Status = NtQueryInformationToken( Here,
  327. TokenStatistics,
  328. &Stats,
  329. sizeof( Stats ),
  330. &Size );
  331. if ( NT_SUCCESS( Status ) )
  332. {
  333. Control.TokenId = Stats.TokenId ;
  334. Control.AuthenticationId = Stats.AuthenticationId ;
  335. Control.ModifiedId = Stats.ModifiedId ;
  336. NtQueryInformationToken( Here, TokenSource, &Control.TokenSource, sizeof( TOKEN_SOURCE ), &Size );
  337. AddHandleToArray( Context, &Control, There );
  338. }
  339. else
  340. {
  341. dprintf("Unable to query token information, %x\n", Status );
  342. }
  343. }
  344. VOID
  345. TokenBanner(
  346. PVOID Id
  347. )
  348. {
  349. PTOKEN_CONTROL Control ;
  350. Control = (PTOKEN_CONTROL) Id ;
  351. dprintf("Token Id %x:%x, LogonId = %x:%x, Source = %s\n",
  352. Control->TokenId.HighPart, Control->TokenId.LowPart,
  353. Control->AuthenticationId.HighPart, Control->AuthenticationId.LowPart,
  354. Control->TokenSource.SourceName );
  355. }
  356. DECLARE_API( hleak )
  357. {
  358. UNICODE_STRING String ;
  359. PHANDLE_LEAK_HELPER Helper = NULL ;
  360. PHANDLE_TRACK_ARRAY Array ;
  361. int i ;
  362. INIT_API();
  363. if ( !args ||
  364. (*args == '\0' ) )
  365. {
  366. dprintf( "!hleak <typename>\n" );
  367. goto Exit;
  368. }
  369. while ( *args == ' ' )
  370. {
  371. args++ ;
  372. }
  373. if ( !RtlCreateUnicodeStringFromAsciiz( &String, args ) )
  374. {
  375. goto Exit;
  376. }
  377. for ( i = 0 ;
  378. i < sizeof( HandleLeakHelpers ) / sizeof( HANDLE_LEAK_HELPER ) ;
  379. i++ )
  380. {
  381. if ( _wcsicmp( String.Buffer, HandleLeakHelpers[ i ].Type ) == 0 )
  382. {
  383. Helper = &HandleLeakHelpers[ i ];
  384. break;
  385. }
  386. }
  387. if ( Helper == NULL )
  388. {
  389. dprintf( "The type '%ws' was not recognized. Valid types are:\n", String.Buffer );
  390. for ( i = 0 ;
  391. i < sizeof( HandleLeakHelpers ) / sizeof( HANDLE_LEAK_HELPER ) ;
  392. i++ )
  393. {
  394. dprintf( "\t%ws\n", HandleLeakHelpers[ i ].Type );
  395. }
  396. RtlFreeUnicodeString( &String );
  397. goto Exit;
  398. }
  399. RtlFreeUnicodeString( &String );
  400. Array = CreateArray( Helper->ArraySize, Helper->Match );
  401. if ( !Array )
  402. {
  403. dprintf( "not enough memory\n" );
  404. }
  405. HandleScanner( g_hCurrentProcess,
  406. Helper->Type,
  407. Array,
  408. Helper->Filter );
  409. DumpArray( Array, Helper->Banner );
  410. DeleteArray( Array );
  411. Exit:
  412. EXIT_API();
  413. }