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.

2686 lines
72 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. smbtrsup.c
  5. Abstract:
  6. This module contains the code to implement the kernel mode SmbTrace
  7. component within the LanMan server and redirector.
  8. The interface between the kernel mode component and the
  9. server/redirector is found in nt\private\inc\smbtrsup.h
  10. The interface providing user-level access to SmbTrace is found in
  11. nt\private\inc\smbtrace.h
  12. Author:
  13. Peter Gray (w-peterg) 23-March-1992
  14. Revision History:
  15. Stephan Mueller (t-stephm) 21-July-1992
  16. Completed, fixed bugs, moved all associated declarations here
  17. from various places in the server, ported to the redirector
  18. and converted to a kernel DLL.
  19. --*/
  20. #include <ntifs.h>
  21. #include <smbtrace.h> // for names and structs shared with user-mode app
  22. #define _SMBTRSUP_SYS_ 1 // to get correct definitions for exported variables
  23. #include <smbtrsup.h> // for functions exported to server/redirector
  24. #if DBG
  25. ULONG SmbtrsupDebug = 0;
  26. #define TrPrint(x) if (SmbtrsupDebug) KdPrint(x)
  27. #else
  28. #define TrPrint(x)
  29. #endif
  30. //
  31. // we assume all well-known names are #defined in Unicode, and require
  32. // them to be so: in the SmbTrace application and the smbtrsup.sys package
  33. //
  34. #ifndef UNICODE
  35. #error "UNICODE build required"
  36. #endif
  37. #if DBG
  38. #define PAGED_DBG 1
  39. #endif
  40. #ifdef PAGED_DBG
  41. #undef PAGED_CODE
  42. #define PAGED_CODE() \
  43. struct { ULONG bogus; } ThisCodeCantBePaged; \
  44. ThisCodeCantBePaged; \
  45. if (KeGetCurrentIrql() > APC_LEVEL) { \
  46. KdPrint(( "SMBTRSUP: Pageable code called at IRQL %d. File %s, Line %d\n", KeGetCurrentIrql(), __FILE__, __LINE__ )); \
  47. ASSERT(FALSE); \
  48. }
  49. #define PAGED_CODE_CHECK() if (ThisCodeCantBePaged) ;
  50. ULONG ThisCodeCantBePaged;
  51. #else
  52. #define PAGED_CODE_CHECK()
  53. #endif
  54. #if PAGED_DBG
  55. #define ACQUIRE_SPIN_LOCK(a, b) { \
  56. PAGED_CODE_CHECK(); \
  57. KeAcquireSpinLock(a, b); \
  58. }
  59. #define RELEASE_SPIN_LOCK(a, b) { \
  60. PAGED_CODE_CHECK(); \
  61. KeReleaseSpinLock(a, b); \
  62. }
  63. #else
  64. #define ACQUIRE_SPIN_LOCK(a, b) KeAcquireSpinLock(a, b)
  65. #define RELEASE_SPIN_LOCK(a, b) KeReleaseSpinLock(a, b)
  66. #endif
  67. //
  68. // Increment shared variable in instance data using appropriate interlock
  69. //
  70. #define LOCK_INC_ID(var) \
  71. ExInterlockedAddUlong( (PULONG)&ID(var), \
  72. 1, &ID(var##Interlock) )
  73. //
  74. // Zero shared variable in instance data using appropriate interlock
  75. //
  76. #define LOCK_ZERO_ID(var) { \
  77. ID(var) = 0; \
  78. }
  79. //
  80. // The various states SmbTrace can be in. These states are internal
  81. // only. The external SmbTraceActive variable contains much less
  82. // detailed information: it is TRUE when TraceRunning, FALSE in any other
  83. // state.
  84. //
  85. typedef enum _SMBTRACE_STATE {
  86. TraceStopped, // not running
  87. TraceStarting, // preparing to run
  88. TraceStartStopFile, // starting, but want to shut down immediately
  89. // because the FileObject closed
  90. TraceStartStopNull, // starting, but want to shut down immediately
  91. // because a new fsctl came in
  92. TraceAppWaiting, // waiting for application to die
  93. TraceRunning, // processing SMBs
  94. TraceStopping // waiting for smbtrace thread to stop
  95. } SMBTRACE_STATE;
  96. //
  97. // Structure used to hold information regarding an SMB which is put into
  98. // the SmbTrace thread queue.
  99. //
  100. typedef struct _SMBTRACE_QUEUE_ENTRY {
  101. LIST_ENTRY ListEntry; // usual doubly-linked list
  102. ULONG SmbLength; // the length of this SMB
  103. PVOID Buffer; // pointer into SmbTracePortMemoryHeap
  104. // or non-paged pool
  105. PVOID SmbAddress; // address of real SMB, if SMB still
  106. // available (i.e. if slow mode)
  107. BOOLEAN BufferNonPaged; // TRUE if Buffer in non-paged pool, FALSE if
  108. // Buffer in SmbTracePortMemoryHeap
  109. // Redirector-specific
  110. PKEVENT WaitEvent; // pointer to worker thread event to be
  111. // signalled when SMB has been processed
  112. // slow mode specific
  113. } SMBTRACE_QUEUE_ENTRY, *PSMBTRACE_QUEUE_ENTRY;
  114. //
  115. // Instance data is specific to the component being traced. In order
  116. // to unclutter the source code, use the following macro to access
  117. // instance specific data.
  118. // Every exported function either has an explicit parameter (named
  119. // Component) which the caller provides, or is implicitly applicable
  120. // only to one component, and has a local variable named Component
  121. // which is always set to the appropriate value.
  122. //
  123. #define ID(field) (SmbTraceData[Component].field)
  124. //
  125. // Instance data. The fields which need to be statically initialized
  126. // are declared before those that we don't care to initialize.
  127. //
  128. typedef struct _INSTANCE_DATA {
  129. //
  130. // Statically initialized fields.
  131. //
  132. //
  133. // Names for identifying the component being traced in KdPrint messages,
  134. // and global objects
  135. //
  136. PCHAR ComponentName;
  137. PWSTR SharedMemoryName;
  138. PWSTR NewSmbEventName;
  139. PWSTR DoneSmbEventName;
  140. //
  141. // Prevent reinitializing resources if rdr/srv reloaded
  142. //
  143. BOOLEAN InstanceInitialized;
  144. //
  145. // some tracing parameters, from SmbTrace application
  146. //
  147. BOOLEAN SingleSmbMode;
  148. CLONG Verbosity;
  149. //
  150. // State of the current trace.
  151. //
  152. SMBTRACE_STATE TraceState;
  153. //
  154. // Pointer to file object of client who started the current trace.
  155. //
  156. PFILE_OBJECT StartersFileObject;
  157. //
  158. // Fsp process of the component we're tracing in.
  159. //
  160. PEPROCESS FspProcess;
  161. //
  162. // All subsequent fields are not expliticly statically initiliazed.
  163. //
  164. //
  165. // Current count of number of SMBs lost since last one output.
  166. // Use an interlock to access, cleared when an SMB is sent to
  167. // the client successfully. This lock is used with ExInterlockedXxx
  168. // routines, so it cannot be treated as a real spin lock (i.e.
  169. // don't use KeAcquireSpinLock.)
  170. //
  171. KSPIN_LOCK SmbsLostInterlock;
  172. ULONG SmbsLost;
  173. //
  174. // some events, only accessed within the kernel
  175. //
  176. KEVENT ActiveEvent;
  177. KEVENT TerminatedEvent;
  178. KEVENT TerminationEvent;
  179. KEVENT AppTerminationEvent;
  180. KEVENT NeedMemoryEvent;
  181. //
  182. // some events, shared with the outside world
  183. //
  184. HANDLE NewSmbEvent;
  185. HANDLE DoneSmbEvent;
  186. //
  187. // Handle to the shared memory used for communication between
  188. // the server/redirector and SmbTrace.
  189. //
  190. HANDLE SectionHandle;
  191. //
  192. // Pointers to control the shared memory for the SmbTrace application.
  193. // The port memory heap handle is initialized to NULL to indicate that
  194. // there is no connection with SmbTrace yet.
  195. //
  196. PVOID PortMemoryBase;
  197. ULONG_PTR PortMemorySize;
  198. ULONG TableSize;
  199. PVOID PortMemoryHeap;
  200. //
  201. // serialized access to the heap,
  202. // to allow clean shutdown (StateInterlock)
  203. //
  204. KSPIN_LOCK HeapReferenceCountLock;
  205. PERESOURCE StateInterlock;
  206. PERESOURCE HeapInterlock;
  207. ULONG HeapReferenceCount;
  208. WORK_QUEUE_ITEM DereferenceWorkQueueItem;
  209. //
  210. // Pointers to the structured data, located in the shared memory.
  211. //
  212. PSMBTRACE_TABLE_HEADER TableHeader;
  213. PSMBTRACE_TABLE_ENTRY Table;
  214. //
  215. // Fields for the SmbTrace queue. The server/redirector puts
  216. // incoming and outgoing SMBs into this queue (when
  217. // SmbTraceActive[Component] is TRUE and they are processed
  218. // by the SmbTrace thread.
  219. //
  220. LIST_ENTRY Queue; // The queue itself
  221. KSPIN_LOCK QueueInterlock; // Synchronizes access to queue
  222. KSEMAPHORE QueueSemaphore; // Counts elements in queue
  223. } INSTANCE_DATA;
  224. #ifdef ALLOC_DATA_PRAGMA
  225. #pragma data_seg("PAGESMBD")
  226. #endif
  227. //
  228. // Global variables for SmbTrace support
  229. //
  230. INSTANCE_DATA SmbTraceData[] = {
  231. //
  232. // Server data
  233. //
  234. {
  235. "Srv", // ComponentName
  236. SMBTRACE_SRV_SHARED_MEMORY_NAME, // SharedMemoryName
  237. SMBTRACE_SRV_NEW_SMB_EVENT_NAME, // NewSmbEventName
  238. SMBTRACE_SRV_DONE_SMB_EVENT_NAME, // DoneSmbEventName
  239. FALSE, // InstanceInitialized
  240. FALSE, // SingleSmbMode
  241. SMBTRACE_VERBOSITY_ERROR, // Verbosity
  242. TraceStopped, // TraceState
  243. NULL, // StartersFileObject
  244. NULL // FspProcess
  245. // rest of fields expected to get 'all-zeroes'
  246. },
  247. //
  248. // Redirector data
  249. //
  250. {
  251. "Rdr", // ComponentName
  252. SMBTRACE_LMR_SHARED_MEMORY_NAME, // SharedMemoryName
  253. SMBTRACE_LMR_NEW_SMB_EVENT_NAME, // NewSmbEventName
  254. SMBTRACE_LMR_DONE_SMB_EVENT_NAME, // DoneSmbEventName
  255. FALSE, // InstanceInitialized
  256. FALSE, // SingleSmbMode
  257. SMBTRACE_VERBOSITY_ERROR, // Verbosity
  258. TraceStopped, // TraceState
  259. NULL, // StartersFileObject
  260. NULL // FspProcess
  261. // rest of fields expected to get 'all-zeroes'
  262. }
  263. };
  264. //
  265. // some state booleans, exported to clients. For this reason,
  266. // they're stored separately from the rest of the instance data.
  267. // Initially, SmbTrace is neither active nor transitioning.
  268. //
  269. BOOLEAN SmbTraceActive[] = {FALSE, FALSE};
  270. BOOLEAN SmbTraceTransitioning[] = {FALSE, FALSE};
  271. HANDLE
  272. SmbTraceDiscardableCodeHandle = 0;
  273. HANDLE
  274. SmbTraceDiscardableDataHandle = 0;
  275. #ifdef ALLOC_DATA_PRAGMA
  276. #pragma data_seg()
  277. #endif
  278. //
  279. // Forward declarations of internal routines
  280. //
  281. BOOLEAN
  282. SmbTraceReferenceHeap(
  283. IN SMBTRACE_COMPONENT Component
  284. );
  285. VOID
  286. SmbTraceDereferenceHeap(
  287. IN SMBTRACE_COMPONENT Component
  288. );
  289. VOID
  290. SmbTraceDisconnect(
  291. IN SMBTRACE_COMPONENT Component
  292. );
  293. VOID
  294. SmbTraceEmptyQueue (
  295. IN SMBTRACE_COMPONENT Component
  296. );
  297. VOID
  298. SmbTraceThreadEntry(
  299. IN PVOID Context
  300. );
  301. NTSTATUS
  302. SmbTraceFreeMemory (
  303. IN SMBTRACE_COMPONENT Component
  304. );
  305. VOID
  306. SmbTraceToClient(
  307. IN PVOID Smb,
  308. IN CLONG SmbLength,
  309. IN PVOID SmbAddress,
  310. IN SMBTRACE_COMPONENT Component
  311. );
  312. ULONG
  313. SmbTraceMdlLength(
  314. IN PMDL Mdl
  315. );
  316. VOID
  317. SmbTraceCopyMdlContiguous(
  318. OUT PVOID Destination,
  319. IN PMDL Mdl,
  320. IN ULONG Length
  321. );
  322. //NTSTATUS
  323. //DriverEntry(
  324. // IN PDRIVER_OBJECT DriverObject,
  325. // IN PUNICODE_STRING RegistryPath
  326. // );
  327. VOID
  328. SmbTraceDeferredDereferenceHeap(
  329. IN PVOID Context
  330. );
  331. #ifdef ALLOC_PRAGMA
  332. #pragma alloc_text(PAGE, SmbTraceInitialize)
  333. #pragma alloc_text(PAGE, SmbTraceTerminate)
  334. #pragma alloc_text(PAGE, SmbTraceStart)
  335. #pragma alloc_text(PAGE, SmbTraceStop)
  336. #pragma alloc_text(PAGE, SmbTraceCompleteSrv)
  337. #pragma alloc_text(PAGE, SmbTraceDisconnect)
  338. #pragma alloc_text(PAGE, SmbTraceEmptyQueue)
  339. #pragma alloc_text(PAGE, SmbTraceThreadEntry)
  340. #pragma alloc_text(PAGE, SmbTraceFreeMemory)
  341. #pragma alloc_text(PAGE, SmbTraceToClient)
  342. #pragma alloc_text(PAGE, SmbTraceDeferredDereferenceHeap)
  343. #pragma alloc_text(PAGESMBC, SmbTraceCompleteRdr)
  344. #pragma alloc_text(PAGESMBC, SmbTraceReferenceHeap)
  345. #pragma alloc_text(PAGESMBC, SmbTraceDereferenceHeap)
  346. #pragma alloc_text(PAGESMBC, SmbTraceMdlLength)
  347. #pragma alloc_text(PAGESMBC, SmbTraceCopyMdlContiguous)
  348. #endif
  349. //
  350. // Exported routines
  351. //
  352. NTSTATUS
  353. SmbTraceInitialize (
  354. IN SMBTRACE_COMPONENT Component
  355. )
  356. /*++
  357. Routine Description:
  358. This routine initializes the SmbTrace component-specific instance
  359. globals. On first-ever invocation, it performs truly global
  360. initialization.
  361. Arguments:
  362. Component - Context from which we're called: server or redirector
  363. Return Value:
  364. NTSTATUS - Indicates failure if unable to allocate resources
  365. --*/
  366. {
  367. PAGED_CODE();
  368. if ( ID(InstanceInitialized) == FALSE ) {
  369. //
  370. // Component specific initialization -- events and locks.
  371. //
  372. KeInitializeEvent( &ID(ActiveEvent), NotificationEvent, FALSE);
  373. KeInitializeEvent( &ID(TerminatedEvent), NotificationEvent, FALSE);
  374. KeInitializeEvent( &ID(TerminationEvent), NotificationEvent, FALSE);
  375. KeInitializeEvent( &ID(AppTerminationEvent), NotificationEvent, FALSE);
  376. KeInitializeEvent( &ID(NeedMemoryEvent), NotificationEvent, FALSE);
  377. KeInitializeSpinLock( &ID(SmbsLostInterlock) );
  378. KeInitializeSpinLock( &ID(HeapReferenceCountLock) );
  379. ID(StateInterlock) = ExAllocatePoolWithTag(
  380. NonPagedPool,
  381. sizeof(ERESOURCE),
  382. 'tbmS'
  383. );
  384. if ( ID(StateInterlock) == NULL ) {
  385. return STATUS_INSUFFICIENT_RESOURCES;
  386. }
  387. ExInitializeResourceLite( ID(StateInterlock) );
  388. ID(HeapInterlock) = ExAllocatePoolWithTag(
  389. NonPagedPool,
  390. sizeof(ERESOURCE),
  391. 'tbmS'
  392. );
  393. if ( ID(HeapInterlock) == NULL ) {
  394. ExDeleteResourceLite( ID(StateInterlock) );
  395. ExFreePool( ID(StateInterlock) );
  396. ID(StateInterlock) = NULL;
  397. return STATUS_INSUFFICIENT_RESOURCES;
  398. }
  399. ExInitializeResourceLite( ID(HeapInterlock) );
  400. ID(InstanceInitialized) = TRUE;
  401. }
  402. return STATUS_SUCCESS;
  403. } // SmbTraceInitialize
  404. VOID
  405. SmbTraceTerminate (
  406. IN SMBTRACE_COMPONENT Component
  407. )
  408. /*++
  409. Routine Description:
  410. This routine cleans up the SmbTrace component-specific instance
  411. globals. It should be called by the component when the component
  412. is unloaded.
  413. Arguments:
  414. Component - Context from which we're called: server or redirector
  415. Return Value:
  416. None
  417. --*/
  418. {
  419. PAGED_CODE();
  420. if ( ID(InstanceInitialized) ) {
  421. ExDeleteResourceLite( ID(StateInterlock) );
  422. ExFreePool( ID(StateInterlock) );
  423. ExDeleteResourceLite( ID(HeapInterlock) );
  424. ExFreePool( ID(HeapInterlock) );
  425. ID(InstanceInitialized) = FALSE;
  426. }
  427. return;
  428. } // SmbTraceTerminate
  429. NTSTATUS
  430. SmbTraceStart (
  431. IN ULONG InputBufferLength,
  432. IN ULONG OutputBufferLength,
  433. IN OUT PVOID ConfigInOut,
  434. IN PFILE_OBJECT FileObject,
  435. IN SMBTRACE_COMPONENT Component
  436. )
  437. /*++
  438. Routine Description:
  439. This routine performs all the work necessary to connect the server/
  440. redirector to SmbTrace. It creates the section of shared memory to
  441. be used, then creates the events needed. All these objects are then
  442. opened by the client (smbtrace) program. This code initializes the
  443. table, the heap stored in the section and table header. This routine
  444. must be called from an Fsp process.
  445. Arguments:
  446. InputBufferLength - Length of the ConfigInOut packet
  447. OutputBufferLength - Length expected for the ConfigInOut packet returned
  448. ConfigInOut - A structure that has configuration information.
  449. FileObject - FileObject of the process requesting that SmbTrace be started,
  450. used to automatically shut down when the app dies.
  451. Component - Context from which we're called: server or redirector
  452. Return Value:
  453. NTSTATUS - result of operation.
  454. --*/
  455. // size of our one, particular, ACL
  456. #define ACL_LENGTH (ULONG)sizeof(ACL) + \
  457. (ULONG)sizeof(ACCESS_ALLOWED_ACE) + \
  458. sizeof(LUID) + \
  459. 8
  460. {
  461. NTSTATUS status;
  462. UNICODE_STRING memoryNameU;
  463. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  464. UCHAR Buffer[ACL_LENGTH];
  465. PACL AdminAcl = (PACL)(&Buffer[0]);
  466. SECURITY_DESCRIPTOR securityDescriptor;
  467. UNICODE_STRING eventNameU;
  468. OBJECT_ATTRIBUTES objectAttributes;
  469. ULONG i;
  470. LARGE_INTEGER sectionSize;
  471. PSMBTRACE_CONFIG_PACKET_REQ ConfigPacket;
  472. PSMBTRACE_CONFIG_PACKET_RESP ConfigPacketResp;
  473. HANDLE threadHandle;
  474. PAGED_CODE();
  475. ASSERT( ID(InstanceInitialized) );
  476. //
  477. // Validate the buffer lengths passed in.
  478. //
  479. if ( ( InputBufferLength != sizeof( SMBTRACE_CONFIG_PACKET_REQ ) )
  480. || ( OutputBufferLength != sizeof( SMBTRACE_CONFIG_PACKET_RESP ) )
  481. ) {
  482. TrPrint(( "%s!SmbTraceStart: config packet(s) of wrong size!\n",
  483. ID(ComponentName) ));
  484. return STATUS_INFO_LENGTH_MISMATCH;
  485. }
  486. ExAcquireResourceExclusiveLite( ID(StateInterlock), TRUE );
  487. if ( ID(TraceState) != TraceStopped ) {
  488. ExReleaseResourceLite( ID(StateInterlock) );
  489. return STATUS_INVALID_DEVICE_STATE;
  490. }
  491. ASSERT(!SmbTraceActive[Component]);
  492. ASSERT (SmbTraceDiscardableDataHandle == NULL);
  493. ASSERT (SmbTraceDiscardableCodeHandle == NULL);
  494. SmbTraceDiscardableCodeHandle = MmLockPagableCodeSection(SmbTraceReferenceHeap);
  495. SmbTraceDiscardableDataHandle = MmLockPagableDataSection(SmbTraceData);
  496. ID(TraceState) = TraceStarting;
  497. //
  498. // Initialize global variables so that we know what to close on errexit
  499. //
  500. ID(SectionHandle) = NULL;
  501. ID(PortMemoryHeap) = NULL;
  502. ID(NewSmbEvent) = NULL;
  503. ID(DoneSmbEvent) = NULL;
  504. //
  505. // Caution! Both input and output packets are the same, we must
  506. // read all of the input before we write any output.
  507. //
  508. ConfigPacket = (PSMBTRACE_CONFIG_PACKET_REQ) ConfigInOut;
  509. ConfigPacketResp = (PSMBTRACE_CONFIG_PACKET_RESP) ConfigInOut;
  510. //
  511. // Set the mode of operation (read all values).
  512. //
  513. ID(SingleSmbMode) = ConfigPacket->SingleSmbMode;
  514. ID(Verbosity) = ConfigPacket->Verbosity;
  515. ID(PortMemorySize) = ConfigPacket->BufferSize;
  516. ID(TableSize) = ConfigPacket->TableSize;
  517. //
  518. // Create a security descriptor containing a discretionary Acl
  519. // allowing administrator access. This SD will be used to allow
  520. // Smbtrace access to the shared memory and the notification events.
  521. //
  522. // Create Acl allowing administrator access using well-known Sid.
  523. status = RtlCreateAcl( AdminAcl, ACL_LENGTH, ACL_REVISION2 );
  524. if ( !NT_SUCCESS(status) ) {
  525. TrPrint((
  526. "%s!SmbTraceStart: RtlCreateAcl failed: %X\n",
  527. ID(ComponentName), status ));
  528. goto errexit;
  529. }
  530. status = RtlAddAccessAllowedAce(
  531. AdminAcl,
  532. ACL_REVISION2,
  533. GENERIC_ALL,
  534. SeExports->SeAliasAdminsSid
  535. );
  536. if ( !NT_SUCCESS(status) ) {
  537. TrPrint((
  538. "%s!SmbTraceStart: RtlAddAccessAllowedAce failed: %X\n",
  539. ID(ComponentName), status ));
  540. goto errexit;
  541. }
  542. // Create SecurityDescriptor containing AdminAcl as a discrectionary ACL.
  543. RtlCreateSecurityDescriptor(
  544. &securityDescriptor,
  545. SECURITY_DESCRIPTOR_REVISION1
  546. );
  547. if ( !NT_SUCCESS(status) ) {
  548. TrPrint((
  549. "%s!SmbTraceStart: RtlCreateSecurityDescriptor failed: %X\n",
  550. ID(ComponentName), status ));
  551. goto errexit;
  552. }
  553. status = RtlSetDaclSecurityDescriptor(
  554. &securityDescriptor,
  555. TRUE,
  556. AdminAcl,
  557. FALSE
  558. );
  559. if ( !NT_SUCCESS(status) ) {
  560. TrPrint((
  561. "%s!SmbTraceStart: "
  562. "RtlSetDAclAllowedSecurityDescriptor failed: %X\n",
  563. ID(ComponentName), status ));
  564. goto errexit;
  565. }
  566. //
  567. // Create the section to be used for communication between the
  568. // server/redirector and SmbTrace.
  569. //
  570. // Define the object name.
  571. RtlInitUnicodeString( &memoryNameU, ID(SharedMemoryName) );
  572. // Define the object information, including security descriptor and name.
  573. InitializeObjectAttributes(
  574. &objectAttributes,
  575. &memoryNameU,
  576. OBJ_CASE_INSENSITIVE,
  577. NULL,
  578. &securityDescriptor
  579. );
  580. // Setup the section size.
  581. sectionSize.QuadPart = ID(PortMemorySize);
  582. // Create the named section of memory with all of our attributes.
  583. status = ZwCreateSection(
  584. &ID(SectionHandle),
  585. SECTION_MAP_READ | SECTION_MAP_WRITE,
  586. &objectAttributes,
  587. &sectionSize,
  588. PAGE_READWRITE,
  589. SEC_RESERVE,
  590. NULL // file handle
  591. );
  592. if ( !NT_SUCCESS(status) ) {
  593. TrPrint(( "%s!SmbTraceStart: ZwCreateSection failed: %X\n",
  594. ID(ComponentName), status ));
  595. goto errexit;
  596. }
  597. // Now, map it into our address space.
  598. ID(PortMemoryBase) = NULL;
  599. status = ZwMapViewOfSection(
  600. ID(SectionHandle),
  601. NtCurrentProcess(),
  602. &ID(PortMemoryBase),
  603. 0, // zero bits (don't care)
  604. 0, // commit size
  605. NULL, // SectionOffset
  606. &ID(PortMemorySize), // viewSize
  607. ViewUnmap, // inheritDisposition
  608. 0L, // allocation type
  609. PAGE_READWRITE // protection
  610. );
  611. if ( !NT_SUCCESS(status) ) {
  612. TrPrint(( "%s!SmbTraceStart: NtMapViewOfSection failed: %X\n",
  613. ID(ComponentName), status ));
  614. goto errexit;
  615. }
  616. //
  617. // Set up the shared section memory as a heap.
  618. //
  619. // *** Note that the HeapInterlock for the client instance is passed
  620. // to the heap manager to be used for serialization of
  621. // allocation and deallocation. It is necessary for the
  622. // resource to be allocated FROM NONPAGED POOL externally to the
  623. // heap manager, because if we let the heap manager allocate
  624. // the resource, if would allocate it from process virtual
  625. // memory.
  626. //
  627. ID(PortMemoryHeap) = RtlCreateHeap(
  628. 0, // Flags
  629. ID(PortMemoryBase), // HeapBase
  630. ID(PortMemorySize), // ReserveSize
  631. PAGE_SIZE, // CommitSize
  632. ID(HeapInterlock), // Lock
  633. 0 // Reserved
  634. );
  635. //
  636. // Allocate and initialize the table and its header.
  637. //
  638. ID(TableHeader) = RtlAllocateHeap(
  639. ID(PortMemoryHeap), 0,
  640. sizeof( SMBTRACE_TABLE_HEADER )
  641. );
  642. ID(Table) = RtlAllocateHeap(
  643. ID(PortMemoryHeap), 0,
  644. sizeof( SMBTRACE_TABLE_ENTRY ) * ID(TableSize)
  645. );
  646. if ( (ID(TableHeader) == NULL) || (ID(Table) == NULL) ) {
  647. TrPrint((
  648. "%s!SmbTraceStart: Not enough memory!\n",
  649. ID(ComponentName) ));
  650. status = STATUS_NO_MEMORY;
  651. goto errexit;
  652. }
  653. // Initialize the values inside.
  654. ID(TableHeader)->HighestConsumed = 0;
  655. ID(TableHeader)->NextFree = 1;
  656. ID(TableHeader)->ApplicationStop = FALSE;
  657. for ( i = 0; i < ID(TableSize); i++) {
  658. ID(Table)[i].BufferOffset = 0L;
  659. ID(Table)[i].SmbLength = 0L;
  660. }
  661. //
  662. // Create the required event handles.
  663. //
  664. // Define the object information.
  665. RtlInitUnicodeString( &eventNameU, ID(NewSmbEventName) );
  666. InitializeObjectAttributes(
  667. &objectAttributes,
  668. &eventNameU,
  669. OBJ_CASE_INSENSITIVE,
  670. NULL,
  671. &securityDescriptor
  672. );
  673. // Open the named object.
  674. status = ZwCreateEvent(
  675. &ID(NewSmbEvent),
  676. EVENT_ALL_ACCESS,
  677. &objectAttributes,
  678. NotificationEvent,
  679. FALSE // initial state
  680. );
  681. if ( !NT_SUCCESS(status) ) {
  682. TrPrint(( "%s!SmbTraceStart: ZwCreateEvent (1st) failed: %X\n",
  683. ID(ComponentName), status ));
  684. goto errexit;
  685. }
  686. if ( ID(SingleSmbMode) ) { // this event may not be required.
  687. // Define the object information.
  688. RtlInitUnicodeString( &eventNameU, ID(DoneSmbEventName) );
  689. InitializeObjectAttributes(
  690. &objectAttributes,
  691. &eventNameU,
  692. OBJ_CASE_INSENSITIVE,
  693. NULL,
  694. &securityDescriptor
  695. );
  696. // Create the named object.
  697. status = ZwCreateEvent(
  698. &ID(DoneSmbEvent),
  699. EVENT_ALL_ACCESS,
  700. &objectAttributes,
  701. NotificationEvent,
  702. FALSE // initial state
  703. );
  704. if ( !NT_SUCCESS(status) ) {
  705. TrPrint((
  706. "%s!SmbTraceStart: NtCreateEvent (2nd) failed: %X\n",
  707. ID(ComponentName), status ));
  708. goto errexit;
  709. }
  710. TrPrint(( "%s!SmbTraceStart: DoneSmbEvent handle %x in process %x\n",
  711. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  712. }
  713. //
  714. // Reset any events that may be in the wrong state from a previous run.
  715. //
  716. KeResetEvent(&ID(TerminationEvent));
  717. KeResetEvent(&ID(TerminatedEvent));
  718. //
  719. // Connection was successful, now start the SmbTrace thread.
  720. //
  721. //
  722. // Create the SmbTrace thread and wait for it to finish
  723. // initializing (at which point SmbTraceActiveEvent is set)
  724. //
  725. status = PsCreateSystemThread(
  726. &threadHandle,
  727. THREAD_ALL_ACCESS,
  728. NULL,
  729. NtCurrentProcess(),
  730. NULL,
  731. (PKSTART_ROUTINE) SmbTraceThreadEntry,
  732. (PVOID)Component
  733. );
  734. if ( !NT_SUCCESS(status) ) {
  735. TrPrint((
  736. "%s!SmbTraceStart: PsCreateSystemThread failed: %X\n",
  737. ID(ComponentName), status ));
  738. goto errexit;
  739. }
  740. //
  741. // Wait until SmbTraceThreadEntry has finished initializing
  742. //
  743. (VOID)KeWaitForSingleObject(
  744. &ID(ActiveEvent),
  745. UserRequest,
  746. KernelMode,
  747. FALSE,
  748. NULL
  749. );
  750. //
  751. // Close the handle to the process so the object will be
  752. // destroyed when the thread dies.
  753. //
  754. ZwClose( threadHandle );
  755. //
  756. // Record who started SmbTrace so we can stop if he dies or otherwise
  757. // closes this handle to us.
  758. //
  759. ID(StartersFileObject) = FileObject;
  760. //
  761. // Record caller's process; which is always the appropriate Fsp
  762. // process.
  763. //
  764. ID(FspProcess) = PsGetCurrentProcess();
  765. //
  766. // Setup the response packet, since everything worked (write all values).
  767. //
  768. ConfigPacketResp->HeaderOffset = (ULONG)
  769. ( (ULONG_PTR)ID(TableHeader)
  770. - (ULONG_PTR)ID(PortMemoryBase) );
  771. ConfigPacketResp->TableOffset = (ULONG)
  772. ( (ULONG_PTR)ID(Table)
  773. - (ULONG_PTR)ID(PortMemoryBase) );
  774. TrPrint(( "%s!SmbTraceStart: SmbTrace started.\n", ID(ComponentName) ));
  775. ExReleaseResourceLite( ID(StateInterlock) );
  776. //
  777. // if someone wanted it shut down while it was starting, shut it down
  778. //
  779. switch ( ID(TraceState) ) {
  780. case TraceStartStopFile :
  781. SmbTraceStop( ID(StartersFileObject), Component );
  782. return STATUS_UNSUCCESSFUL; // app closed, so we should shut down
  783. break;
  784. case TraceStartStopNull :
  785. SmbTraceStop( NULL, Component );
  786. return STATUS_UNSUCCESSFUL; // someone requested a shut down
  787. break;
  788. default :
  789. ID(TraceState) = TraceRunning;
  790. SmbTraceActive[Component] = TRUE;
  791. return STATUS_SUCCESS;
  792. }
  793. errexit:
  794. SmbTraceDisconnect( Component );
  795. ID(TraceState) = TraceStopped;
  796. ExReleaseResourceLite( ID(StateInterlock) );
  797. //
  798. // return original failure status code, not success of cleanup
  799. //
  800. return status;
  801. } // SmbTraceStart
  802. // constant only of interest while constructing the particular Acl
  803. // in SmbTraceStart
  804. #undef ACL_LENGTH
  805. NTSTATUS
  806. SmbTraceStop(
  807. IN PFILE_OBJECT FileObject OPTIONAL,
  808. IN SMBTRACE_COMPONENT Component
  809. )
  810. /*++
  811. Routine Description:
  812. This routine stops tracing in the server/redirector. If no
  813. FileObject is provided, the SmbTrace application is stopped.
  814. If a FileObject is provided, SmbTrace is stopped if the
  815. FileObject refers to the one who started it.
  816. Arguments:
  817. FileObject - FileObject of a process that terminated. If it's the process
  818. that requested SmbTracing, we shut down automatically.
  819. Component - Context from which we're called: server or redirector
  820. Return Value:
  821. NTSTATUS - result of operation. Possible results are:
  822. STATUS_SUCCESS - SmbTrace was stopped
  823. STATUS_UNSUCCESSFUL - SmbTrace was not stopped because the
  824. provided FileObject did not refer to the SmbTrace starter
  825. or because SmbTrace was not running.
  826. --*/
  827. {
  828. PAGED_CODE();
  829. //
  830. // If we haven't been initialized, there's nothing to stop. (And no
  831. // resource to acquire!)
  832. //
  833. if ( !ID(InstanceInitialized) ) {
  834. return STATUS_UNSUCCESSFUL;
  835. }
  836. //
  837. // If it's not the FileObject that started SmbTrace, we don't care.
  838. // From then on, if ARGUMENT_PRESENT(FileObject) it's the right one.
  839. //
  840. if ( ARGUMENT_PRESENT(FileObject) &&
  841. FileObject != ID(StartersFileObject)
  842. ) {
  843. return STATUS_UNSUCCESSFUL;
  844. }
  845. ExAcquireResourceExclusiveLite( ID(StateInterlock), TRUE );
  846. //
  847. // Depending on the current state of SmbTrace and whether this is
  848. // a FileObject or unconditional shutdown request, we do different
  849. // things. It is always clear at this point, though, that
  850. // SmbTraceActive should be set to FALSE.
  851. //
  852. SmbTraceActive[Component] = FALSE;
  853. switch ( ID(TraceState) ) {
  854. case TraceStopped :
  855. case TraceStopping :
  856. case TraceStartStopFile :
  857. case TraceStartStopNull :
  858. // if we're not running or already in a mode where we know we'll
  859. // soon be shut down, ignore the request.
  860. ExReleaseResourceLite( ID(StateInterlock) );
  861. return STATUS_UNSUCCESSFUL;
  862. break;
  863. case TraceStarting :
  864. // inform starting SmbTrace that it should shut down immediately
  865. // upon finishing initialization. It needs to know whether this
  866. // is a FileObject or unconditional shutdown request.
  867. ID(TraceState) = ARGUMENT_PRESENT(FileObject)
  868. ? TraceStartStopFile
  869. : TraceStartStopNull;
  870. ExReleaseResourceLite( ID(StateInterlock) );
  871. return STATUS_SUCCESS;
  872. break;
  873. case TraceAppWaiting :
  874. // we're waiting for the application to die already, so ignore
  875. // new unconditional requests. But FileObject requests are
  876. // welcomed. We cause the SmbTrace thread to kill itself.
  877. if ( ARGUMENT_PRESENT(FileObject) ) {
  878. break; // thread kill code follows switch
  879. } else {
  880. ExReleaseResourceLite( ID(StateInterlock) );
  881. return STATUS_UNSUCCESSFUL;
  882. }
  883. break;
  884. case TraceRunning :
  885. // if it's a FileObject request, the app is dead, so we cause
  886. // the SmbTrace thread to kill itself. Otherwise, we need to
  887. // signal the app to stop and return. When the app is gone, we
  888. // will be called again; this time with a FileObject.
  889. if ( ARGUMENT_PRESENT(FileObject) ) {
  890. break; // thread kill code follows switch
  891. } else {
  892. KeSetEvent( &ID(AppTerminationEvent), 2, FALSE );
  893. ID(TraceState) = TraceAppWaiting;
  894. ExReleaseResourceLite( ID(StateInterlock) );
  895. return STATUS_SUCCESS;
  896. }
  897. break;
  898. default :
  899. ASSERT(!"SmbTraceStop: invalid TraceState");
  900. break;
  901. }
  902. //
  903. // We reach here from within the switch only in the case where
  904. // we actually want to kill the SmbTrace thread. Signal it to
  905. // wake up, and wait until it terminates. Signal DoneSmbEvent
  906. // in case it is currently waiting for the application to signal
  907. // it in slow mode.
  908. //
  909. ID(StartersFileObject) = NULL;
  910. if ( ID(SingleSmbMode)) {
  911. BOOLEAN ProcessAttached = FALSE;
  912. if (PsGetCurrentProcess() != ID(FspProcess)) {
  913. KeAttachProcess(ID(FspProcess));
  914. ProcessAttached = TRUE;
  915. }
  916. TrPrint(( "%s!SmbTraceStop: Signal DoneSmbEvent, handle %x, process %x.\n",
  917. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  918. ZwSetEvent( ID(DoneSmbEvent), NULL );
  919. if (ProcessAttached) {
  920. KeDetachProcess();
  921. }
  922. }
  923. TrPrint(( "%s!SmbTraceStop: Signal Termination Event.\n", ID(ComponentName) ));
  924. ID(TraceState) = TraceStopping;
  925. KeSetEvent( &ID(TerminationEvent), 2, FALSE );
  926. ExReleaseResourceLite( ID(StateInterlock) );
  927. KeWaitForSingleObject(
  928. &ID(TerminatedEvent),
  929. UserRequest,
  930. KernelMode,
  931. FALSE,
  932. NULL
  933. );
  934. TrPrint(( "%s!SmbTraceStop: Terminated Event is set.\n", ID(ComponentName) ));
  935. ExAcquireResourceExclusiveLite( ID(StateInterlock), TRUE );
  936. ID(TraceState) = TraceStopped;
  937. ExReleaseResourceLite( ID(StateInterlock) );
  938. TrPrint(( "%s!SmbTraceStop: SmbTrace stopped.\n", ID(ComponentName) ));
  939. MmUnlockPagableImageSection(SmbTraceDiscardableCodeHandle);
  940. SmbTraceDiscardableCodeHandle = NULL;
  941. MmUnlockPagableImageSection(SmbTraceDiscardableDataHandle);
  942. SmbTraceDiscardableDataHandle = NULL;
  943. return STATUS_SUCCESS;
  944. } // SmbTraceStop
  945. VOID
  946. SmbTraceCompleteSrv (
  947. IN PMDL SmbMdl,
  948. IN PVOID Smb,
  949. IN CLONG SmbLength
  950. )
  951. /*++
  952. Routine Description:
  953. Server version.
  954. Snapshot an SMB and export it to the SmbTrace application. How
  955. this happens is determined by which mode (fast or slow) SmbTracing
  956. was requested in. In the server, it is easy to guarantee that when
  957. tracing, a thread is always executing in the Fsp.
  958. Fast mode: the SMB is copied into shared memory and an entry for it
  959. is queued to the server SmbTrace thread, which asynchronously
  960. passes SMBs to the app. If there is insufficient memory
  961. for anything (SMB, queue entry, etc.) the SMB is lost.
  962. Slow mode: identical to Fast mode except that this thread waits
  963. until the server SmbTrace thread signals that the app has finished
  964. processing the SMB. Because each thread waits until its SMB has
  965. been completely processed, there is much less chance of running
  966. out of any resources.
  967. The SMB is either contained in SmbMdl, or at address Smb with length
  968. SmbLength.
  969. Arguments:
  970. SmbMdl - an Mdl containing the SMB.
  971. Smb - a pointer to the SMB.
  972. SmbLength - the length of the SMB.
  973. Return Value:
  974. None
  975. --*/
  976. {
  977. PSMBTRACE_QUEUE_ENTRY queueEntry;
  978. PVOID buffer;
  979. SMBTRACE_COMPONENT Component = SMBTRACE_SERVER;
  980. KEVENT WaitEvent;
  981. PAGED_CODE();
  982. //
  983. // This routine is server specific.
  984. //
  985. ASSERT( ID(TraceState) == TraceRunning );
  986. ASSERT( SmbTraceActive[SMBTRACE_SERVER] );
  987. //
  988. // We want either an Mdl, or a pointer and a length, or occasionally,
  989. // a completely NULL response.
  990. //
  991. ASSERT( ( SmbMdl == NULL && Smb != NULL && SmbLength != 0 )
  992. || ( SmbMdl != NULL && Smb == NULL && SmbLength == 0 )
  993. || ( SmbMdl == NULL && Smb == NULL && SmbLength == 0 ) );
  994. //
  995. // We've taken pains not to be at DPC level and to be in
  996. // the Fsp context too, for that matter.
  997. //
  998. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL);
  999. ASSERT( PsGetCurrentProcess() == ID(FspProcess) );
  1000. //
  1001. // Ensure that SmbTrace really is still active and hence, the
  1002. // shared memory is still around.
  1003. //
  1004. if ( SmbTraceReferenceHeap( Component ) == FALSE ) {
  1005. return;
  1006. }
  1007. //
  1008. // If the SMB is currently in an MDL, we don't yet have the length,
  1009. // which we need, to know how much memory to allocate.
  1010. //
  1011. if ( SmbMdl != NULL ) {
  1012. SmbLength = SmbTraceMdlLength(SmbMdl);
  1013. }
  1014. //
  1015. // If we are in slow mode, then we wait after queuing the SMB
  1016. // to the SmbTrace thread. If we are set for fast mode we
  1017. // garbage collect in case of no memory.
  1018. //
  1019. if ( ID(SingleSmbMode) ) {
  1020. KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
  1021. }
  1022. queueEntry = ExAllocatePoolWithTag( NonPagedPool,
  1023. sizeof(SMBTRACE_QUEUE_ENTRY),
  1024. 'tbmS'
  1025. );
  1026. if ( queueEntry == NULL ) {
  1027. // No free memory, this SMB is lost. Record its loss.
  1028. LOCK_INC_ID(SmbsLost);
  1029. SmbTraceDereferenceHeap( Component );
  1030. return;
  1031. }
  1032. //
  1033. // Allocate the required amount of memory in our heap
  1034. // in the shared memory.
  1035. //
  1036. buffer = RtlAllocateHeap( ID(PortMemoryHeap), 0, SmbLength );
  1037. if ( buffer == NULL ) {
  1038. // No free memory, this SMB is lost. Record its loss.
  1039. // Very unlikely in slow mode.
  1040. LOCK_INC_ID(SmbsLost);
  1041. ExFreePool( queueEntry );
  1042. if ( !ID(SingleSmbMode) ) {
  1043. //
  1044. // Encourage some garbage collection.
  1045. //
  1046. KeSetEvent( &ID(NeedMemoryEvent), 0, FALSE );
  1047. }
  1048. SmbTraceDereferenceHeap( Component );
  1049. return;
  1050. }
  1051. //
  1052. // Copy the SMB to shared memory pointed to by the queue entry,
  1053. // keeping in mind whether it's in an Mdl or contiguous to begin
  1054. // with, and also preserving the address of the real SMB...
  1055. //
  1056. if ( SmbMdl != NULL ) {
  1057. SmbTraceCopyMdlContiguous( buffer, SmbMdl, SmbLength );
  1058. queueEntry->SmbAddress = SmbMdl;
  1059. } else {
  1060. RtlCopyMemory( buffer, Smb, SmbLength );
  1061. queueEntry->SmbAddress = Smb;
  1062. }
  1063. queueEntry->SmbLength = SmbLength;
  1064. queueEntry->Buffer = buffer;
  1065. queueEntry->BufferNonPaged = FALSE;
  1066. //
  1067. // In slow mode, we want to wait until the SMB has been eaten,
  1068. // in fast mode, we don't want to pass the address of the real
  1069. // SMB along, since the SMB is long gone by the time it gets
  1070. // decoded and printed.
  1071. //
  1072. if ( ID(SingleSmbMode) ) {
  1073. queueEntry->WaitEvent = &WaitEvent;
  1074. } else {
  1075. queueEntry->WaitEvent = NULL;
  1076. queueEntry->SmbAddress = NULL;
  1077. }
  1078. //
  1079. // ...queue the entry to the SmbTrace thread...
  1080. //
  1081. ExInterlockedInsertTailList(
  1082. &ID(Queue),
  1083. &queueEntry->ListEntry,
  1084. &ID(QueueInterlock)
  1085. );
  1086. KeReleaseSemaphore(
  1087. &ID(QueueSemaphore),
  1088. SEMAPHORE_INCREMENT,
  1089. 1,
  1090. FALSE
  1091. );
  1092. //
  1093. // ...and wait for the SMB to be eaten, in slow mode.
  1094. //
  1095. if ( ID(SingleSmbMode) ) {
  1096. TrPrint(( "%s!SmbTraceCompleteSrv: Slow mode wait\n", ID(ComponentName) ));
  1097. KeWaitForSingleObject(
  1098. &WaitEvent,
  1099. UserRequest,
  1100. KernelMode,
  1101. FALSE,
  1102. NULL
  1103. );
  1104. TrPrint(( "%s!SmbTraceCompleteSrv: Slow mode wait done\n", ID(ComponentName) ));
  1105. }
  1106. SmbTraceDereferenceHeap( Component );
  1107. return;
  1108. } // SmbTraceCompleteSrv
  1109. VOID
  1110. SmbTraceCompleteRdr (
  1111. IN PMDL SmbMdl,
  1112. IN PVOID Smb,
  1113. IN CLONG SmbLength
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Redirector version
  1118. Snapshot an SMB and export it to the SmbTrace application. How
  1119. this happens is determined by which mode (fast or slow) SmbTracing
  1120. was requested in, and which context (DPC, Fsp or Fsd) the current
  1121. thread is executing in.
  1122. Fast mode: the SMB is copied into shared memory and an entry for it
  1123. is queued to the redirector SmbTrace thread, which asynchronously
  1124. passes SMBs to the app. (When in DPC, the SMB is copied to non-paged
  1125. pool instead of shared memory, and the SmbTrace thread deals with
  1126. moving it to shared memory later.) If there is insufficient memory
  1127. for anything (SMB, queue entry, etc.) the SMB is lost.
  1128. Slow mode: identical to Fast mode except that this thread waits
  1129. until the server SmbTrace thread signals that the app has finished
  1130. processing the SMB. Because each thread waits until its SMB has
  1131. been completely processed, there is much less chance of running
  1132. out of any resources. If at DPC level, we behave exactly as in the
  1133. fast mode case, because it would be a Bad Thing to block this thread
  1134. at DPC level.
  1135. The SMB is either contained in SmbMdl, or at address Smb with length
  1136. SmbLength.
  1137. Arguments:
  1138. SmbMdl - an Mdl containing the SMB.
  1139. Smb - a pointer to the SMB.
  1140. SmbLength - the length of the SMB.
  1141. Return Value:
  1142. None
  1143. --*/
  1144. {
  1145. PSMBTRACE_QUEUE_ENTRY queueEntry;
  1146. PVOID buffer;
  1147. BOOLEAN ProcessAttached = FALSE;
  1148. BOOLEAN AtDpcLevel;
  1149. SMBTRACE_COMPONENT Component = SMBTRACE_REDIRECTOR;
  1150. KEVENT WaitEvent;
  1151. //
  1152. // This routine is redirector specific.
  1153. //
  1154. ASSERT( ID(TraceState) == TraceRunning );
  1155. ASSERT( SmbTraceActive[SMBTRACE_REDIRECTOR] );
  1156. //
  1157. // We want either an Mdl, or a pointer and a length, or occasionally,
  1158. // a completely NULL response
  1159. //
  1160. ASSERT( ( SmbMdl == NULL && Smb != NULL && SmbLength != 0 )
  1161. || ( SmbMdl != NULL && Smb == NULL && SmbLength == 0 )
  1162. || ( SmbMdl == NULL && Smb == NULL && SmbLength == 0 ) );
  1163. //
  1164. // Ensure that SmbTrace really is still active and hence, the
  1165. // shared memory is still around.
  1166. //
  1167. if ( SmbTraceReferenceHeap( Component ) == FALSE ) {
  1168. return;
  1169. }
  1170. //
  1171. // To avoid multiple system calls, we find out once and for all.
  1172. //
  1173. AtDpcLevel = (BOOLEAN)(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  1174. //
  1175. // If the SMB is currently in an MDL, we don't yet have the length,
  1176. // which we need to know how much memory to allocate.
  1177. //
  1178. if ( SmbMdl != NULL ) {
  1179. SmbLength = SmbTraceMdlLength(SmbMdl);
  1180. }
  1181. //
  1182. // If we are in slow mode, then we wait after queuing the SMB
  1183. // to the SmbTrace thread. If we are set for fast mode we
  1184. // garbage collect in case of no memory. If we're at DPC level,
  1185. // we store the SMB in non-paged pool.
  1186. //
  1187. if ( ID(SingleSmbMode) ) {
  1188. KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
  1189. }
  1190. //
  1191. // allocate queue entry
  1192. //
  1193. queueEntry = ExAllocatePoolWithTag(
  1194. NonPagedPool,
  1195. sizeof(SMBTRACE_QUEUE_ENTRY),
  1196. 'tbmS'
  1197. );
  1198. if ( queueEntry == NULL ) {
  1199. // No free memory, this SMB is lost. Record its loss.
  1200. LOCK_INC_ID(SmbsLost);
  1201. SmbTraceDereferenceHeap( Component );
  1202. return;
  1203. }
  1204. //
  1205. // allocate buffer for SMB, in non-paged pool or shared heap as
  1206. // appropriate
  1207. //
  1208. if ( AtDpcLevel ) {
  1209. buffer = ExAllocatePoolWithTag( NonPagedPool, SmbLength, 'tbmS' );
  1210. queueEntry->BufferNonPaged = TRUE;
  1211. } else {
  1212. if ( PsGetCurrentProcess() != ID(FspProcess) ) {
  1213. KeAttachProcess(ID(FspProcess));
  1214. ProcessAttached = TRUE;
  1215. }
  1216. buffer = RtlAllocateHeap( ID(PortMemoryHeap), 0, SmbLength );
  1217. queueEntry->BufferNonPaged = FALSE;
  1218. }
  1219. if ( buffer == NULL ) {
  1220. if ( ProcessAttached ) {
  1221. KeDetachProcess();
  1222. }
  1223. // No free memory, this SMB is lost. Record its loss.
  1224. LOCK_INC_ID(SmbsLost);
  1225. if (!ID(SingleSmbMode)) {
  1226. //
  1227. // If it was shared memory we ran out of, encourage
  1228. // some garbage collection.
  1229. //
  1230. if ( !queueEntry->BufferNonPaged ) {
  1231. KeSetEvent( &ID(NeedMemoryEvent), 0, FALSE );
  1232. }
  1233. }
  1234. ExFreePool( queueEntry );
  1235. SmbTraceDereferenceHeap( Component );
  1236. return;
  1237. }
  1238. //
  1239. // Copy the SMB to shared or non-paged memory pointed to by the
  1240. // queue entry, keeping in mind whether it's in an Mdl or contiguous
  1241. // to begin with, and also preserving the address of the real SMB...
  1242. //
  1243. if ( SmbMdl != NULL ) {
  1244. SmbTraceCopyMdlContiguous( buffer, SmbMdl, SmbLength );
  1245. queueEntry->SmbAddress = SmbMdl;
  1246. } else {
  1247. RtlCopyMemory( buffer, Smb, SmbLength );
  1248. queueEntry->SmbAddress = Smb;
  1249. }
  1250. if ( ProcessAttached ) {
  1251. KeDetachProcess();
  1252. }
  1253. queueEntry->SmbLength = SmbLength;
  1254. queueEntry->Buffer = buffer;
  1255. //
  1256. // In slow mode, we want to wait until the SMB has been eaten,
  1257. // in fast mode, we don't want to pass the address of the real
  1258. // SMB along, since the SMB is long gone by the time it gets
  1259. // decoded and printed.
  1260. //
  1261. if ( ID(SingleSmbMode) && !AtDpcLevel ) {
  1262. queueEntry->WaitEvent = &WaitEvent;
  1263. } else {
  1264. queueEntry->WaitEvent = NULL;
  1265. queueEntry->SmbAddress = NULL;
  1266. }
  1267. //
  1268. // ...queue the entry to the SmbTrace thread...
  1269. //
  1270. ExInterlockedInsertTailList(
  1271. &ID(Queue),
  1272. &queueEntry->ListEntry,
  1273. &ID(QueueInterlock)
  1274. );
  1275. KeReleaseSemaphore(
  1276. &ID(QueueSemaphore),
  1277. SEMAPHORE_INCREMENT,
  1278. 1,
  1279. FALSE
  1280. );
  1281. //
  1282. // ...and wait for the SMB to be eaten, in slow mode.
  1283. //
  1284. if ( ID(SingleSmbMode) && !AtDpcLevel ) {
  1285. TrPrint(( "%s!SmbTraceCompleteRdr: Slow mode wait\n", ID(ComponentName) ));
  1286. KeWaitForSingleObject(
  1287. &WaitEvent,
  1288. UserRequest,
  1289. KernelMode,
  1290. FALSE,
  1291. NULL
  1292. );
  1293. TrPrint(( "%s!SmbTraceCompleteRdr: Slow mode wait done\n", ID(ComponentName) ));
  1294. }
  1295. SmbTraceDereferenceHeap( Component );
  1296. return;
  1297. } // SmbTraceCompleteRdr
  1298. //
  1299. // Internal routines
  1300. //
  1301. BOOLEAN
  1302. SmbTraceReferenceHeap(
  1303. IN SMBTRACE_COMPONENT Component
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. This routine references the SmbTrace shared memory heap,
  1308. ensuring it isn't disposed of while caller is using it.
  1309. Arguments:
  1310. Component - Context from which we're called: server or redirector
  1311. Return Value:
  1312. BOOLEAN - TRUE if SmbTrace is still active, and hence
  1313. heap exists and was successfully referenced.
  1314. FALSE otherwise.
  1315. --*/
  1316. {
  1317. BOOLEAN retval = TRUE; // assume we'll get it
  1318. KIRQL OldIrql;
  1319. ACQUIRE_SPIN_LOCK( &ID(HeapReferenceCountLock), &OldIrql );
  1320. if ( ID(TraceState) != TraceRunning ) {
  1321. retval = FALSE;
  1322. } else {
  1323. ASSERT( ID(HeapReferenceCount) > 0 );
  1324. if( ID(HeapReferenceCount) > 0 )
  1325. {
  1326. ID(HeapReferenceCount)++;
  1327. TrPrint(( "%s!SmbTraceReferenceHeap: Count now %lx\n",
  1328. ID(ComponentName),
  1329. ID(HeapReferenceCount) ));
  1330. }
  1331. else
  1332. {
  1333. retval = FALSE;
  1334. }
  1335. }
  1336. RELEASE_SPIN_LOCK( &ID(HeapReferenceCountLock), OldIrql );
  1337. return retval;
  1338. } // SmbTraceReferenceHeap
  1339. VOID
  1340. SmbTraceDeferredDereferenceHeap(
  1341. IN PVOID Context
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. If a caller dereferences a heap to 0 from DPC_LEVEL, this routine will
  1346. be called in a system thread to complete the dereference at task time.
  1347. Arguments:
  1348. Component - Context from which we're called: server or redirector
  1349. Return Value:
  1350. None
  1351. --*/
  1352. {
  1353. PAGED_CODE();
  1354. SmbTraceDereferenceHeap((SMBTRACE_COMPONENT)Context);
  1355. }
  1356. VOID
  1357. SmbTraceDereferenceHeap(
  1358. IN SMBTRACE_COMPONENT Component
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. This routine dereferences the SmbTrace shared memory heap,
  1363. disposing of it when the reference count is zero.
  1364. Arguments:
  1365. Component - Context from which we're called: server or redirector
  1366. Return Value:
  1367. None
  1368. --*/
  1369. {
  1370. ULONG oldCount;
  1371. KIRQL OldIrql;
  1372. ACQUIRE_SPIN_LOCK( &ID(HeapReferenceCountLock), &OldIrql );
  1373. if (ID(HeapReferenceCount) > 1) {
  1374. ID(HeapReferenceCount) --;
  1375. TrPrint(( "%s!SmbTraceDereferenceHeap: Count now %lx\n",
  1376. ID(ComponentName),
  1377. ID(HeapReferenceCount) ));
  1378. RELEASE_SPIN_LOCK( &ID(HeapReferenceCountLock), OldIrql );
  1379. return;
  1380. }
  1381. RELEASE_SPIN_LOCK( &ID(HeapReferenceCountLock), OldIrql );
  1382. //
  1383. // If we are executing at DPC_LEVEL, we cannot dereference the heap
  1384. // to 0.
  1385. //
  1386. if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
  1387. ExInitializeWorkItem(&ID(DereferenceWorkQueueItem), SmbTraceDeferredDereferenceHeap, (PVOID)Component);
  1388. ExQueueWorkItem(&ID(DereferenceWorkQueueItem), DelayedWorkQueue);
  1389. return;
  1390. }
  1391. ACQUIRE_SPIN_LOCK( &ID(HeapReferenceCountLock), &OldIrql );
  1392. oldCount = ID(HeapReferenceCount)--;
  1393. TrPrint(( "%s!SmbTraceDereferenceHeap: Count now %lx\n",
  1394. ID(ComponentName),
  1395. ID(HeapReferenceCount) ));
  1396. RELEASE_SPIN_LOCK( &ID(HeapReferenceCountLock), OldIrql );
  1397. if ( oldCount == 1 ) {
  1398. //
  1399. // Free the section, release the handles and such.
  1400. //
  1401. SmbTraceDisconnect( Component );
  1402. }
  1403. return;
  1404. } // SmbTraceDereferenceHeap
  1405. VOID
  1406. SmbTraceDisconnect (
  1407. IN SMBTRACE_COMPONENT Component
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This routine reverses all the effects of SmbTraceStart. Mostly,
  1412. it just needs to close certain handles to do this.
  1413. Arguments:
  1414. Component - Context from which we're called: server or redirector
  1415. Return Value:
  1416. None - always works
  1417. --*/
  1418. {
  1419. BOOLEAN ProcessAttached = FALSE;
  1420. PAGED_CODE();
  1421. if (PsGetCurrentProcess() != ID(FspProcess)) {
  1422. KeAttachProcess(ID(FspProcess));
  1423. ProcessAttached = TRUE;
  1424. }
  1425. if ( ID(DoneSmbEvent) != NULL ) {
  1426. // Worker thread may be blocked on this, so we set it first
  1427. TrPrint(( "%s!SmbTraceDisconnect: Signal DoneSmbEvent, handle %x, process %x.\n",
  1428. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  1429. ZwSetEvent( ID(DoneSmbEvent), NULL );
  1430. TrPrint(( "%s!SmbTraceDisconnect: Close DoneSmbEvent, handle %x, process %x.\n",
  1431. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  1432. ZwClose( ID(DoneSmbEvent) );
  1433. ID(DoneSmbEvent) = NULL;
  1434. }
  1435. if ( ID(NewSmbEvent) != NULL ) {
  1436. ZwClose( ID(NewSmbEvent) );
  1437. ID(NewSmbEvent) = NULL;
  1438. }
  1439. if ( ID(PortMemoryHeap) != NULL ) {
  1440. RtlDestroyHeap( ID(PortMemoryHeap) );
  1441. ID(PortMemoryHeap) = NULL;
  1442. }
  1443. if ( ID(SectionHandle) != NULL ) {
  1444. ZwClose( ID(SectionHandle) );
  1445. ID(SectionHandle) = NULL;
  1446. }
  1447. if (ProcessAttached) {
  1448. KeDetachProcess();
  1449. }
  1450. return;
  1451. } // SmbTraceDisconnect
  1452. VOID
  1453. SmbTraceEmptyQueue (
  1454. IN SMBTRACE_COMPONENT Component
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. This routine empties the queue of unprocessed SMBs.
  1459. Arguments:
  1460. Component - Context from which we're called: server or redirector
  1461. Return Value:
  1462. None - always works
  1463. --*/
  1464. {
  1465. PLIST_ENTRY listEntry;
  1466. PSMBTRACE_QUEUE_ENTRY queueEntry;
  1467. PAGED_CODE();
  1468. while ( ( listEntry = ExInterlockedRemoveHeadList(
  1469. &ID(Queue),
  1470. &ID(QueueInterlock)
  1471. )
  1472. ) != NULL
  1473. ) {
  1474. queueEntry = CONTAINING_RECORD(
  1475. listEntry,
  1476. SMBTRACE_QUEUE_ENTRY,
  1477. ListEntry
  1478. );
  1479. //
  1480. // If data for this entry is in non-paged pool, free it too.
  1481. // This only ever happens in the redirector.
  1482. //
  1483. if ( queueEntry->BufferNonPaged ) {
  1484. ASSERT( Component == SMBTRACE_REDIRECTOR );
  1485. ExFreePool( queueEntry->Buffer );
  1486. }
  1487. //
  1488. // If a worker thread is waiting on this event, let it go.
  1489. // This only ever happens in slow mode.
  1490. //
  1491. if ( queueEntry->WaitEvent != NULL ) {
  1492. ASSERT( ID(SingleSmbMode) == TRUE );
  1493. KeSetEvent( queueEntry->WaitEvent, 0, FALSE );
  1494. }
  1495. ExFreePool( queueEntry );
  1496. }
  1497. return;
  1498. } // SmbTraceEmptyQueue
  1499. VOID
  1500. SmbTraceThreadEntry (
  1501. IN PVOID Context
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This routine is the entry point of the SmbTrace thread for the server/
  1506. redirector. It is started by SmbTraceStart. This thread loops
  1507. continuously until the client SmbTrace dies or another SmbTrace sends
  1508. an FsCtl to stop the trace.
  1509. Arguments:
  1510. Context - pointer to context block containing component from which
  1511. we're called: server or redirector
  1512. Return Value:
  1513. None
  1514. --*/
  1515. // we wait for termination, work-to-do and need-memory events
  1516. #define NUMBER_OF_BLOCKING_OBJECTS 4
  1517. // keep these definitions in sync
  1518. #define INDEX_WAIT_TERMINATIONEVENT 0
  1519. #define INDEX_WAIT_APPTERMINATIONEVENT 1
  1520. #define INDEX_WAIT_NEEDMEMORYEVENT 2
  1521. #define INDEX_WAIT_QUEUESEMAPHORE 3
  1522. #define STATUS_WAIT_TERMINATIONEVENT STATUS_WAIT_0
  1523. #define STATUS_WAIT_APPTERMINATIONEVENT STATUS_WAIT_1
  1524. #define STATUS_WAIT_NEEDMEMORYEVENT STATUS_WAIT_2
  1525. #define STATUS_WAIT_QUEUESEMAPHORE STATUS_WAIT_3
  1526. {
  1527. NTSTATUS status;
  1528. PLIST_ENTRY listEntry;
  1529. PSMBTRACE_QUEUE_ENTRY queueEntry;
  1530. PVOID buffer;
  1531. PVOID waitObjects[NUMBER_OF_BLOCKING_OBJECTS];
  1532. SMBTRACE_COMPONENT Component;
  1533. BOOLEAN Looping;
  1534. #if NUMBER_OF_BLOCKING_OBJECTS > THREAD_WAIT_OBJECTS
  1535. //
  1536. // If we try to wait on too many objects, we need to allocate
  1537. // our own wait blocks.
  1538. //
  1539. KWAIT_BLOCK waitBlocks[NUMBER_OF_BLOCKING_OBJECTS];
  1540. #endif
  1541. PAGED_CODE();
  1542. //
  1543. // Context is really just the component
  1544. //
  1545. Component = (SMBTRACE_COMPONENT)(UINT_PTR)Context;
  1546. //
  1547. // Initialize the queue.
  1548. //
  1549. InitializeListHead( &ID(Queue) );
  1550. KeInitializeSpinLock( &ID(QueueInterlock) );
  1551. KeInitializeSemaphore( &ID(QueueSemaphore), 0, 0x7FFFFFFF );
  1552. //
  1553. // Set up the array of objects to wait on. We wait (in order)
  1554. // for our termination event, the appliction termination event,
  1555. // a no shared memory event or an SMB request to show up in the
  1556. // SmbTrace queue.
  1557. //
  1558. waitObjects[INDEX_WAIT_TERMINATIONEVENT] = &ID(TerminationEvent);
  1559. waitObjects[INDEX_WAIT_APPTERMINATIONEVENT] = &ID(AppTerminationEvent);
  1560. waitObjects[INDEX_WAIT_NEEDMEMORYEVENT] = &ID(NeedMemoryEvent);
  1561. waitObjects[INDEX_WAIT_QUEUESEMAPHORE] = &ID(QueueSemaphore);
  1562. //
  1563. // No SMBs have been lost yet, and this thread is the first user
  1564. // of the shared memory. It's also a special user in that it gets
  1565. // access before TraceState == TraceRunning, a requirement for all
  1566. // subsequent referencers.
  1567. //
  1568. ID(SmbsLost) = 0L;
  1569. ID(HeapReferenceCount) = 1;
  1570. //
  1571. // Signal to the FSP that we are ready to start capturing SMBs.
  1572. //
  1573. KeSetEvent( &ID(ActiveEvent), 0, FALSE );
  1574. //
  1575. // Main loop, executed until the thread is terminated.
  1576. //
  1577. TrPrint(( "%s!SmbTraceThread: Tracing started.\n", ID(ComponentName) ));
  1578. Looping = TRUE;
  1579. while( Looping ) {
  1580. TrPrint(( "%s!SmbTraceThread: WaitForMultiple.\n", ID(ComponentName) ));
  1581. status = KeWaitForMultipleObjects(
  1582. NUMBER_OF_BLOCKING_OBJECTS,
  1583. &waitObjects[0],
  1584. WaitAny,
  1585. UserRequest,
  1586. KernelMode,
  1587. FALSE,
  1588. NULL,
  1589. #if NUMBER_OF_BLOCKING_OBJECTS > THREAD_WAIT_OBJECTS
  1590. &waitBlocks[0]
  1591. #else
  1592. NULL
  1593. #endif
  1594. );
  1595. if ( !NT_SUCCESS(status) ) {
  1596. TrPrint((
  1597. "%s!SmbTraceThreadEntry: KeWaitForMultipleObjectsfailed: %X\n",
  1598. ID(ComponentName), status ));
  1599. } else {
  1600. TrPrint((
  1601. "%s!SmbTraceThreadEntry: %lx\n",
  1602. ID(ComponentName), status ));
  1603. }
  1604. switch( status ) {
  1605. case STATUS_WAIT_TERMINATIONEVENT:
  1606. //
  1607. // Stop looping, and then proceed to clean up and die.
  1608. //
  1609. Looping = FALSE;
  1610. break;
  1611. case STATUS_WAIT_APPTERMINATIONEVENT:
  1612. // Turn off the event so we don't go in a tight loop
  1613. KeResetEvent(&ID(AppTerminationEvent));
  1614. //
  1615. // Inform the app that it is time to die. The NULL SMB
  1616. // sent here may not be the next to be processed by the
  1617. // app, but the ApplicationStop bit will be detected
  1618. // immediately.
  1619. //
  1620. ID(TableHeader)->ApplicationStop = TRUE;
  1621. SmbTraceToClient( NULL, 0, NULL, Component );
  1622. break;
  1623. case STATUS_WAIT_NEEDMEMORYEVENT:
  1624. // Turn off the event so we don't go in a loop.
  1625. KeResetEvent(&ID(NeedMemoryEvent));
  1626. //
  1627. // Do a garbage collection, freeing all memory that is
  1628. // allocated in the shared memory but that has been read
  1629. // by the client.
  1630. //
  1631. SmbTraceFreeMemory( Component );
  1632. break;
  1633. case STATUS_WAIT_QUEUESEMAPHORE:
  1634. //
  1635. // If any get through once we've gone into AppWaiting
  1636. // state, don't bother sending them on, they're not
  1637. // going to get processed.
  1638. //
  1639. if ( ID(TraceState) == TraceAppWaiting ) {
  1640. SmbTraceEmptyQueue( Component );
  1641. break;
  1642. }
  1643. //
  1644. // Remove the first element in the our queue. A
  1645. // work item is represented by our header followed by
  1646. // an SMB. We must free the entry after we are done
  1647. // with it.
  1648. //
  1649. listEntry = ExInterlockedRemoveHeadList(
  1650. &ID(Queue),
  1651. &ID(QueueInterlock)
  1652. );
  1653. if ( listEntry != NULL ) {
  1654. //
  1655. // Get the address of the queue entry.
  1656. //
  1657. queueEntry = CONTAINING_RECORD(
  1658. listEntry,
  1659. SMBTRACE_QUEUE_ENTRY,
  1660. ListEntry
  1661. );
  1662. //
  1663. // If the data is in non-paged pool, move it to shared
  1664. // memory and free the non-paged pool before passing
  1665. // the SMB to the client. Note that in this case,
  1666. // there's no need to signal anyone. They ain't waiting.
  1667. //
  1668. if ( queueEntry->BufferNonPaged ) {
  1669. //
  1670. // Server never uses non-paged pool.
  1671. //
  1672. ASSERT( Component != SMBTRACE_SERVER );
  1673. buffer = RtlAllocateHeap( ID(PortMemoryHeap), 0,
  1674. queueEntry->SmbLength );
  1675. if ( buffer == NULL ) {
  1676. LOCK_INC_ID(SmbsLost);
  1677. ExFreePool( queueEntry->Buffer );
  1678. ExFreePool( queueEntry );
  1679. break;
  1680. }
  1681. RtlCopyMemory( buffer, queueEntry->Buffer,
  1682. queueEntry->SmbLength );
  1683. ExFreePool( queueEntry->Buffer );
  1684. //
  1685. // Send it off. Because the original SMB is long
  1686. // dead, we don't pass its real address along (not
  1687. // that we have it, anyway.)
  1688. //
  1689. ASSERT( queueEntry->SmbAddress == NULL );
  1690. SmbTraceToClient(
  1691. buffer,
  1692. queueEntry->SmbLength,
  1693. NULL,
  1694. Component
  1695. );
  1696. } else {
  1697. //
  1698. // Enter the SMB into the table and send it to the
  1699. // client. Can block in slow mode. When it does so, we'll
  1700. // signal the applicable thread.
  1701. //
  1702. SmbTraceToClient(
  1703. queueEntry->Buffer,
  1704. queueEntry->SmbLength,
  1705. queueEntry->SmbAddress,
  1706. Component
  1707. );
  1708. if ( queueEntry->WaitEvent != NULL ) {
  1709. KeSetEvent( queueEntry->WaitEvent, 0, FALSE );
  1710. }
  1711. }
  1712. //
  1713. // Now, we must free the queue entry.
  1714. //
  1715. ExFreePool( queueEntry );
  1716. }
  1717. break;
  1718. default:
  1719. break;
  1720. }
  1721. }
  1722. //
  1723. // Clean up!
  1724. //
  1725. TrPrint(( "%s!SmbTraceThread: Tracing clean up.\n", ID(ComponentName) ));
  1726. SmbTraceDereferenceHeap( Component );
  1727. SmbTraceEmptyQueue( Component );
  1728. //
  1729. // Signal to SmbTraceStop that we're dying.
  1730. //
  1731. TrPrint(( "%s!SmbTraceThread: Tracing terminated.\n", ID(ComponentName) ));
  1732. KeSetEvent( &ID(TerminatedEvent), 0, FALSE );
  1733. //
  1734. // Kill this thread.
  1735. //
  1736. status = PsTerminateSystemThread( STATUS_SUCCESS );
  1737. // Shouldn't get here
  1738. TrPrint((
  1739. "%s!SmbTraceThreadEntry: PsTerminateSystemThread() failed: %X\n",
  1740. ID(ComponentName), status ));
  1741. } // SmbTraceThreadEntry
  1742. // constant only of interest while constructing waitObject arrays
  1743. // in SmbTraceThreadEntry
  1744. #undef NUMBER_OF_BLOCKING_OBJECTS
  1745. NTSTATUS
  1746. SmbTraceFreeMemory (
  1747. IN SMBTRACE_COMPONENT Component
  1748. )
  1749. /*++
  1750. Routine Description:
  1751. This procedure frees any memory that may have been allocated to an
  1752. SMB that the client has already consumed. It does not alter table
  1753. entries, except to record that the memory buffer has been cleared.
  1754. This routinue is not espectally fast, it should not be called often,
  1755. only when needed.
  1756. Arguments:
  1757. Component - Context from which we're called: server or redirector
  1758. Return Value:
  1759. NTSTATUS - result of operation.
  1760. --*/
  1761. {
  1762. PVOID buffer;
  1763. PSMBTRACE_TABLE_ENTRY tableEntry;
  1764. ULONG tableIndex;
  1765. PAGED_CODE();
  1766. TrPrint(( "%s!SmbTraceFreeMemory: Called for garbage collection.\n",
  1767. ID(ComponentName) ));
  1768. //
  1769. // No free memory in the heap, perhaps we can free some by freeing
  1770. // memory in old table entries. This is expensive for time.
  1771. //
  1772. tableIndex = ID(TableHeader)->NextFree;
  1773. while( tableIndex != ID(TableHeader)->HighestConsumed ) {
  1774. tableEntry = ID(Table) + tableIndex;
  1775. //
  1776. // Check if this table entry has been used but its memory has not
  1777. // been freed yet. If so, free it.
  1778. //
  1779. if ( tableEntry->BufferOffset != 0L ) {
  1780. buffer = (PVOID)( (ULONG_PTR)tableEntry->BufferOffset
  1781. + (ULONG_PTR)ID(PortMemoryBase) );
  1782. RtlFreeHeap( ID(PortMemoryHeap), 0, buffer);
  1783. tableEntry->BufferOffset = 0L;
  1784. }
  1785. tableIndex = (tableIndex + 1) % ID(TableSize);
  1786. }
  1787. return( STATUS_SUCCESS );
  1788. } // SmbTraceFreeMemory
  1789. VOID
  1790. SmbTraceToClient(
  1791. IN PVOID Smb,
  1792. IN CLONG SmbLength,
  1793. IN PVOID SmbAddress,
  1794. IN SMBTRACE_COMPONENT Component
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. Enter an SMB already found in shared memory into the table. Set
  1799. an event for the client. If there is no table space, the SMB is
  1800. not saved. If in slow mode, wait for the client to finish with
  1801. and then free the memory occupied by the SMB.
  1802. Arguments:
  1803. Smb - a pointer to the SMB (which is ALREADY in shared memory).
  1804. Can be NULL, indicating no new SMB is to be added, but the
  1805. application is to be signalled anyway.
  1806. SmbLength - the length of the SMB.
  1807. SmbAddress - the address of the real SMB, not in shared memory.
  1808. Component - Context from which we're called: server or redirector
  1809. Return Value:
  1810. None
  1811. --*/
  1812. {
  1813. NTSTATUS status;
  1814. PVOID buffer;
  1815. PSMBTRACE_TABLE_ENTRY tableEntry;
  1816. ULONG tableIndex;
  1817. PAGED_CODE();
  1818. //
  1819. // Reset DoneSmbEvent so we can determine when the request has been processed
  1820. //
  1821. if ( ID(SingleSmbMode) ) {
  1822. PKEVENT DoneEvent;
  1823. TrPrint(( "%s!SmbTraceToClient: Reset DoneSmbEvent, handle %x, process %x.\n",
  1824. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  1825. status = ObReferenceObjectByHandle( ID(DoneSmbEvent),
  1826. EVENT_MODIFY_STATE,
  1827. NULL,
  1828. KernelMode,
  1829. (PVOID *)&DoneEvent,
  1830. NULL
  1831. );
  1832. ASSERT ( NT_SUCCESS(status) );
  1833. KeResetEvent(DoneEvent);
  1834. ObDereferenceObject(DoneEvent);
  1835. }
  1836. if (Smb != NULL) {
  1837. //
  1838. // See if there is room in the table for a pointer to our SMB.
  1839. //
  1840. if ( ID(TableHeader)->NextFree == ID(TableHeader)->HighestConsumed ) {
  1841. // Tough luck. No memory in the table, this SMB is lost.
  1842. LOCK_INC_ID( SmbsLost );
  1843. RtlFreeHeap( ID(PortMemoryHeap), 0, Smb );
  1844. return;
  1845. }
  1846. tableIndex = ID(TableHeader)->NextFree;
  1847. tableEntry = ID(Table) + tableIndex;
  1848. //
  1849. // Record the number of SMBs that were lost before this one and
  1850. // (maybe) zero the count for the next one.
  1851. //
  1852. tableEntry->NumberMissed = ID(SmbsLost);
  1853. if ( tableEntry->NumberMissed != 0 ) {
  1854. LOCK_ZERO_ID(SmbsLost);
  1855. }
  1856. //
  1857. // Check if this table entry has been used but its memory has not
  1858. // been freed yet. If so, free it.
  1859. //
  1860. if ( tableEntry->BufferOffset != 0L ) {
  1861. buffer = (PVOID)( (ULONG_PTR)tableEntry->BufferOffset
  1862. + (ULONG_PTR)ID(PortMemoryBase) );
  1863. RtlFreeHeap( ID(PortMemoryHeap), 0, buffer);
  1864. tableEntry->BufferOffset = 0L;
  1865. }
  1866. //
  1867. // Record the location and size of this SMB in the table.
  1868. //
  1869. tableEntry->BufferOffset = (ULONG)((ULONG_PTR)Smb - (ULONG_PTR)ID(PortMemoryBase));
  1870. tableEntry->SmbLength = SmbLength;
  1871. //
  1872. // Record the real address of the actual SMB (i.e. not the shared
  1873. // memory copy) if it's available.
  1874. //
  1875. tableEntry->SmbAddress = SmbAddress;
  1876. //
  1877. // Increment the Next Free counter.
  1878. //
  1879. ID(TableHeader)->NextFree = (tableIndex + 1) % ID(TableSize);
  1880. }
  1881. //
  1882. // Unlock the client so it will process this new SMB.
  1883. //
  1884. TrPrint(( "%s!SmbTraceToClient: Set NewSmbEvent.\n", ID(ComponentName) ));
  1885. status = ZwSetEvent( ID(NewSmbEvent), NULL );
  1886. //
  1887. // When stopping the trace we set TraceState to TraceStopping and then
  1888. // DoneSmbEvent. This prevents this routine from blocking indefinitely
  1889. // because it Resets DoneSmbEvent processes the Smb and then checks TraceState
  1890. // before blocking.
  1891. //
  1892. if (( ID(SingleSmbMode) ) &&
  1893. ( ID(TraceState) == TraceRunning )) {
  1894. //
  1895. // Wait for the app to acknowledge that the SMB has been
  1896. // processed.
  1897. //
  1898. TrPrint(( "%s!SmbTraceToClient: Waiting for DoneSmbEvent, handle %x, process %x.\n",
  1899. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  1900. status = ZwWaitForSingleObject(
  1901. ID(DoneSmbEvent),
  1902. FALSE,
  1903. NULL
  1904. );
  1905. TrPrint(( "%s!SmbTraceToClient: DoneSmbEvent is set, handle %x, process %x.\n",
  1906. ID(ComponentName), ID(DoneSmbEvent), PsGetCurrentProcess()));
  1907. ASSERT( NT_SUCCESS(status) );
  1908. if (Smb != NULL) {
  1909. tableEntry->BufferOffset = 0L;
  1910. RtlFreeHeap( ID(PortMemoryHeap), 0, Smb);
  1911. }
  1912. }
  1913. return;
  1914. } // SmbTraceToClient
  1915. ULONG
  1916. SmbTraceMdlLength(
  1917. IN PMDL Mdl
  1918. )
  1919. /*++
  1920. Routine Description:
  1921. Determine the total number of bytes of data found in an Mdl.
  1922. Arguments:
  1923. Mdl - a pointer to an Mdl whose length is to be calculated
  1924. Return Value:
  1925. ULONG - total number of data bytes in Mdl
  1926. --*/
  1927. {
  1928. ULONG Bytes = 0;
  1929. while (Mdl != NULL) {
  1930. Bytes += MmGetMdlByteCount(Mdl);
  1931. Mdl = Mdl->Next;
  1932. }
  1933. return Bytes;
  1934. } // SmbTraceMdlLength
  1935. VOID
  1936. SmbTraceCopyMdlContiguous(
  1937. OUT PVOID Destination,
  1938. IN PMDL Mdl,
  1939. IN ULONG Length
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. Copy the data stored in Mdl into the contiguous memory at
  1944. Destination. Length is present to keep the same interface
  1945. as RtlCopyMemory.
  1946. Arguments:
  1947. Destination - a pointer to previously allocated memory into which
  1948. the Mdl is to be copied.
  1949. Mdl - a pointer to an Mdl which is to be copied to Destination
  1950. Length - number of data bytes expected in Mdl
  1951. Return Value:
  1952. None
  1953. --*/
  1954. {
  1955. PCHAR Dest = Destination;
  1956. PCHAR Src = NULL;
  1957. UNREFERENCED_PARAMETER(Length);
  1958. while (Mdl != NULL) {
  1959. Src = MmGetSystemAddressForMdlSafe(Mdl,NormalPagePriority);
  1960. if (Src != NULL) {
  1961. RtlCopyMemory(
  1962. Dest,
  1963. Src,
  1964. MmGetMdlByteCount(Mdl)
  1965. );
  1966. }
  1967. Dest += MmGetMdlByteCount(Mdl);
  1968. Mdl = Mdl->Next;
  1969. }
  1970. ASSERT((ULONG)(Dest - (PCHAR)Destination) == Length);
  1971. return;
  1972. } // SmbTraceCopyMdlContiguous