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.

1239 lines
31 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. bowutils.c
  5. Abstract:
  6. This module implements various useful routines for the NT datagram
  7. receiver (bowser).
  8. Author:
  9. Larry Osterman (larryo) 6-May-1991
  10. Revision History:
  11. 24-Sep-1991 larryo
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, BowserMapUsersBuffer)
  18. #pragma alloc_text(PAGE, BowserLockUsersBuffer)
  19. #pragma alloc_text(PAGE, BowserConvertType3IoControlToType2IoControl)
  20. #pragma alloc_text(PAGE, BowserPackNtString)
  21. #pragma alloc_text(PAGE, BowserPackUnicodeString)
  22. #pragma alloc_text(PAGE, BowserRandom)
  23. #pragma alloc_text(PAGE, BowserTimeUp)
  24. #pragma alloc_text(PAGE, BowserReferenceDiscardableCode)
  25. #pragma alloc_text(PAGE, BowserDereferenceDiscardableCode)
  26. #pragma alloc_text(PAGE, BowserUninitializeDiscardableCode)
  27. #pragma alloc_text(INIT, BowserInitializeDiscardableCode)
  28. #if DBG
  29. #ifndef PRODUCT1
  30. #pragma alloc_text(PAGE, BowserTrace)
  31. #endif
  32. #pragma alloc_text(PAGE, BowserInitializeTraceLog)
  33. #pragma alloc_text(PAGE, BowserOpenTraceLogFile)
  34. #pragma alloc_text(PAGE, BowserUninitializeTraceLog)
  35. #pragma alloc_text(PAGE, BowserDebugCall)
  36. #endif
  37. #endif
  38. BOOLEAN
  39. BowserMapUsersBuffer (
  40. IN PIRP Irp,
  41. OUT PVOID *UserBuffer,
  42. IN ULONG Length
  43. )
  44. /*++
  45. Routine Description:
  46. This routine will probe and lock the buffer described by the
  47. provided Irp.
  48. Arguments:
  49. IN PIRP Irp - Supplies the IRP that is to be mapped.
  50. OUT PVOID *Buffer - Returns a buffer that maps the user's buffer in the IRP
  51. Return Value:
  52. TRUE - The buffer was mapped into the current address space.
  53. FALSE - The buffer was NOT mapped in, it was already mappable.
  54. --*/
  55. {
  56. PAGED_CODE();
  57. if (Irp->MdlAddress) {
  58. *UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, LowPagePriority);
  59. return FALSE;
  60. } else {
  61. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  62. *UserBuffer = Irp->AssociatedIrp.SystemBuffer;
  63. } else if (Irp->RequestorMode != KernelMode) {
  64. PIO_STACK_LOCATION IrpSp;
  65. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  66. if ((Length != 0) && (Irp->UserBuffer != 0)) {
  67. if ((IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) ||
  68. (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)) {
  69. ULONG ControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  70. if ((ControlCode & 3) == METHOD_NEITHER) {
  71. ProbeForWrite( Irp->UserBuffer,
  72. Length,
  73. sizeof(UCHAR) );
  74. } else {
  75. ASSERT ((ControlCode & 3) != METHOD_BUFFERED);
  76. ASSERT ((ControlCode & 3) != METHOD_IN_DIRECT);
  77. ASSERT ((ControlCode & 3) != METHOD_OUT_DIRECT);
  78. }
  79. } else if ((IrpSp->MajorFunction == IRP_MJ_READ) ||
  80. (IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) ||
  81. (IrpSp->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION) ||
  82. (IrpSp->MajorFunction == IRP_MJ_QUERY_SECURITY) ||
  83. (IrpSp->MajorFunction == IRP_MJ_DIRECTORY_CONTROL)) {
  84. ProbeForWrite( Irp->UserBuffer,
  85. Length,
  86. sizeof(UCHAR) );
  87. } else {
  88. ProbeForRead( Irp->UserBuffer,
  89. Length,
  90. sizeof(UCHAR) );
  91. }
  92. }
  93. *UserBuffer = Irp->UserBuffer;
  94. }
  95. return FALSE;
  96. }
  97. }
  98. NTSTATUS
  99. BowserLockUsersBuffer (
  100. IN PIRP Irp,
  101. IN LOCK_OPERATION Operation,
  102. IN ULONG BufferLength
  103. )
  104. /*++
  105. Routine Description:
  106. This routine will probe and lock the buffer described by the
  107. provided Irp.
  108. Arguments:
  109. IN PIRP Irp - Supplies the IRP that is to be locked.
  110. IN LOCK_OPERATION Operation - Supplies the operation type to probe.
  111. Return Value:
  112. None.
  113. --*/
  114. {
  115. NTSTATUS Status = STATUS_SUCCESS;
  116. PAGED_CODE();
  117. if ((Irp->MdlAddress == NULL)) {
  118. try {
  119. Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer,
  120. BufferLength,
  121. FALSE,
  122. TRUE,
  123. NULL);
  124. if (Irp->MdlAddress == NULL) {
  125. return(STATUS_INSUFFICIENT_RESOURCES);
  126. }
  127. //
  128. // Now probe and lock down the user's data buffer.
  129. //
  130. MmProbeAndLockPages(Irp->MdlAddress,
  131. Irp->RequestorMode,
  132. Operation);
  133. } except (BR_EXCEPTION) {
  134. Status = GetExceptionCode();
  135. if (Irp->MdlAddress != NULL) {
  136. //
  137. // We blew up in the probe and lock, free up the MDL
  138. // and set the IRP to have a null MDL pointer - we are failing the
  139. // request
  140. //
  141. IoFreeMdl(Irp->MdlAddress);
  142. Irp->MdlAddress = NULL;
  143. }
  144. }
  145. }
  146. return Status;
  147. }
  148. NTSTATUS
  149. BowserConvertType3IoControlToType2IoControl (
  150. IN PIRP Irp,
  151. IN PIO_STACK_LOCATION IrpSp
  152. )
  153. /*++
  154. Routine Description:
  155. This routine does the work necessary to convert a type 3 IoCtl to a
  156. type 2 IoCtl. We do this when we have to pass a user IRP to the FSP.
  157. Arguments:
  158. IN PIRP Irp - Supplies an IRP to convert
  159. IN PIO_STACK_LOCATION IrpSp - Supplies an Irp Stack location for convenience
  160. Return Value:
  161. NTSTATUS - Status of operation
  162. Note: This must be called in the FSD.
  163. --*/
  164. {
  165. NTSTATUS Status;
  166. PAGED_CODE();
  167. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0) {
  168. Status = BowserLockUsersBuffer(Irp, IoWriteAccess, IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
  169. //
  170. // If we were unable to lock the users output buffer, return now.
  171. //
  172. if (!NT_SUCCESS(Status)) {
  173. return Status;
  174. }
  175. }
  176. ASSERT (Irp->AssociatedIrp.SystemBuffer == NULL);
  177. try {
  178. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) {
  179. PCHAR InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  180. ULONG InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  181. Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(PagedPool,
  182. InputBufferLength, ' GD');
  183. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  184. return STATUS_INSUFFICIENT_RESOURCES;
  185. }
  186. //
  187. // If called from a user process,
  188. // probe the buffer to ensure it is in the callers address space.
  189. //
  190. if (Irp->RequestorMode != KernelMode) {
  191. ProbeForRead( InputBuffer,
  192. InputBufferLength,
  193. sizeof(UCHAR));
  194. }
  195. RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
  196. InputBuffer,
  197. InputBufferLength);
  198. Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
  199. } else {
  200. Irp->AssociatedIrp.SystemBuffer = NULL;
  201. }
  202. } except (BR_EXCEPTION) {
  203. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  204. ExFreePool(Irp->AssociatedIrp.SystemBuffer);
  205. }
  206. return GetExceptionCode();
  207. }
  208. return STATUS_SUCCESS;
  209. }
  210. ULONG
  211. BowserPackNtString(
  212. PUNICODE_STRING string,
  213. ULONG_PTR BufferDisplacement,
  214. PCHAR dataend,
  215. PCHAR * laststring
  216. )
  217. /** BowserPackNtString
  218. *
  219. * BowserPackNtString is used to stuff variable-length data, which
  220. * is pointed to by (surpise!) a pointer. The data is assumed
  221. * to be a nul-terminated string (ASCIIZ). Repeated calls to
  222. * this function are used to pack data from an entire structure.
  223. *
  224. * Upon first call, the laststring pointer should point to just
  225. * past the end of the buffer. Data will be copied into the buffer from
  226. * the end, working towards the beginning. If a data item cannot
  227. * fit, the pointer will be set to NULL, else the pointer will be
  228. * set to the new data location.
  229. *
  230. * Pointers which are passed in as NULL will be set to be pointer
  231. * to and empty string, as the NULL-pointer is reserved for
  232. * data which could not fit as opposed to data not available.
  233. *
  234. * Returns: 0 if could not fit data into buffer
  235. * else size of data stuffed (guaranteed non-zero)
  236. *
  237. * See the test case for sample usage. (tst/packtest.c)
  238. */
  239. {
  240. LONG size;
  241. PAGED_CODE();
  242. dlog(DPRT_PACK, ("BowserPackNtString:\n"));
  243. dlog(DPRT_PACK, (" string=%Fp, *string=%Fp, **string=\"%us\"\n",
  244. string, *string, *string));
  245. dlog(DPRT_PACK, (" end=%Fp\n", dataend));
  246. dlog(DPRT_PACK, (" last=%Fp, *last=%Fp, **last=\"%us\"\n",
  247. laststring, *laststring, *laststring));
  248. ASSERT (dataend < *laststring);
  249. //
  250. // is there room for the string?
  251. //
  252. size = string->Length;
  253. if ((*laststring - dataend) < size) {
  254. string->Length = 0;
  255. return(0);
  256. } else {
  257. *laststring -= size;
  258. RtlCopyMemory(*laststring, string->Buffer, size);
  259. string->Buffer = (PWSTR)((*laststring) - BufferDisplacement);
  260. return(size);
  261. }
  262. }
  263. ULONG
  264. BowserPackUnicodeString(
  265. IN OUT PWCHAR * string, // pointer by reference: string to be copied.
  266. IN ULONG StringLength, // Length of this string (in bytes) (w/o trailing zero)
  267. IN ULONG_PTR OutputBufferDisplacement, // Amount to subtract from output buffer
  268. IN PVOID dataend, // pointer to end of fixed size data.
  269. IN OUT PVOID * laststring // pointer by reference: top of string data.
  270. )
  271. /*++
  272. Routine Description:
  273. BowserPackUnicodeString is used to stuff variable-length data, which
  274. is pointed to by (surpise!) a pointer. The data is assumed
  275. to be a nul-terminated string (ASCIIZ). Repeated calls to
  276. this function are used to pack data from an entire structure.
  277. Upon first call, the laststring pointer should point to just
  278. past the end of the buffer. Data will be copied into the buffer from
  279. the end, working towards the beginning. If a data item cannot
  280. fit, the pointer will be set to NULL, else the pointer will be
  281. set to the new data location.
  282. Pointers which are passed in as NULL will be set to be pointer
  283. to and empty string, as the NULL-pointer is reserved for
  284. data which could not fit as opposed to data not available.
  285. See the test case for sample usage. (tst/packtest.c)
  286. Arguments:
  287. string - pointer by reference: string to be copied.
  288. dataend - pointer to end of fixed size data.
  289. laststring - pointer by reference: top of string data.
  290. Return Value:
  291. 0 - if it could not fit data into the buffer. Or...
  292. sizeOfData - the size of data stuffed (guaranteed non-zero)
  293. --*/
  294. {
  295. DWORD size;
  296. DWORD Available = (DWORD)((PCHAR)*laststring - (PCHAR)dataend);
  297. WCHAR StringBuffer[1] = L"";
  298. PAGED_CODE();
  299. //
  300. // Verify that there is room left for the string. If a NULL string
  301. // is input, there must be at least room for a UNICODE NULL, so set
  302. // size to sizeof(WCHAR) in this case.
  303. //
  304. if (*string == NULL) {
  305. StringLength = 0;
  306. *string = StringBuffer;
  307. }
  308. size = StringLength + sizeof(WCHAR);
  309. // if the end of the buffer passed to us is not aligned properly for wide chars, shift it inwards to align it
  310. *laststring = ROUND_DOWN_POINTER(*laststring, ALIGN_WCHAR);
  311. if (*laststring < dataend || size > Available) {
  312. *string = UNICODE_NULL;
  313. return(0);
  314. }
  315. *((PCHAR *)laststring) -= size;
  316. RtlCopyMemory(*laststring, *string, size-sizeof(WCHAR));
  317. *string = *laststring;
  318. (*string)[StringLength/2] = L'\0';
  319. *(PCHAR*)string -=OutputBufferDisplacement;
  320. return(size);
  321. } // BowserUnicodePackString
  322. ULONG
  323. BowserTimeUp(
  324. VOID
  325. )
  326. /*++
  327. Routine Description:
  328. BowserTimeUp is used to return the number of seconds the browser has been
  329. running.
  330. Arguments:
  331. None
  332. Return Value:
  333. Number of seconds the browser has been up.
  334. --*/
  335. {
  336. LARGE_INTEGER CurrentTime;
  337. LARGE_INTEGER TimeDelta;
  338. LARGE_INTEGER TimeUp;
  339. //
  340. // These are the magic numbers needed to do our extended division. The
  341. // only numbers we ever need to divide by are
  342. //
  343. // 10,000 = convert 100ns tics to millisecond tics
  344. //
  345. //
  346. // These values were stolen from ntos\rtl\time.c
  347. //
  348. LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  349. #define SHIFT10000 13
  350. PAGED_CODE();
  351. KeQuerySystemTime(&CurrentTime);
  352. TimeDelta.QuadPart = CurrentTime.QuadPart - BowserStartTime.QuadPart;
  353. //
  354. // TimeDelta is the number of 100ns units the bowser has been up. Convert
  355. // it to milliseconds using the magic routine.
  356. //
  357. TimeUp = RtlExtendedMagicDivide(TimeDelta, Magic10000, SHIFT10000);
  358. //
  359. // Please note that TimeUp.LowPart wraps after about 49 days,
  360. // this means that if a machine has been up for more than 49 days,
  361. // we peg at 0xffffffff.
  362. //
  363. if (TimeUp.HighPart != 0) {
  364. return(0xffffffff);
  365. }
  366. return(TimeUp.LowPart);
  367. }
  368. ULONG
  369. BowserRandom(
  370. IN ULONG MaxValue
  371. )
  372. /*++
  373. Routine Description:
  374. BowserRandom is used to return a random number between 0 and MaxValue
  375. Arguments:
  376. MaxValue - The maximum value to return.
  377. Return Value:
  378. Random # between 0 and MaxValue
  379. --*/
  380. {
  381. PAGED_CODE();
  382. return RtlRandom(&BowserRandomSeed) % MaxValue;
  383. }
  384. VOID
  385. BowserReferenceDiscardableCode(
  386. DISCARDABLE_SECTION_NAME SectionName
  387. )
  388. /*++
  389. Routine Description:
  390. BowserReferenceDiscardableCode is called to reference the browsers
  391. discardable code section.
  392. If the section is not present in memory, MmLockPagableCodeSection is
  393. called to fault the section into memory.
  394. Arguments:
  395. None.
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. PAGED_CODE();
  401. RdrReferenceDiscardableCode(SectionName);
  402. }
  403. VOID
  404. BowserDereferenceDiscardableCode(
  405. DISCARDABLE_SECTION_NAME SectionName
  406. )
  407. /*++
  408. Routine Description:
  409. BowserDereferenceDiscardableCode is called to dereference the browsers
  410. discardable code section.
  411. When the reference count drops to 0, a timer is set that will fire in <n>
  412. seconds, after which time the section will be unlocked.
  413. Arguments:
  414. None.
  415. Return Value:
  416. None.
  417. --*/
  418. {
  419. PAGED_CODE();
  420. RdrDereferenceDiscardableCode(SectionName);
  421. }
  422. VOID
  423. BowserInitializeDiscardableCode(
  424. VOID
  425. )
  426. {
  427. }
  428. VOID
  429. BowserUninitializeDiscardableCode(
  430. VOID
  431. )
  432. {
  433. PAGED_CODE();
  434. }
  435. #if BOWSERPOOLDBG
  436. typedef struct {
  437. ULONG Count;
  438. ULONG Size;
  439. PCHAR FileName;
  440. ULONG LineNumber;
  441. } POOL_STATS, *PPOOL_STATS;
  442. typedef struct _POOL_HEADER {
  443. // LIST_ENTRY ListEntry;
  444. ULONG NumberOfBytes;
  445. PPOOL_STATS Stats;
  446. } POOL_HEADER, *PPOOL_HEADER;
  447. ULONG CurrentAllocationCount;
  448. ULONG CurrentAllocationSize;
  449. ULONG NextFreeEntry = 0;
  450. POOL_STATS PoolStats[POOL_MAXTYPE+1];
  451. PVOID
  452. BowserAllocatePool (
  453. IN POOL_TYPE PoolType,
  454. IN ULONG NumberOfBytes,
  455. IN PCHAR FileName,
  456. IN ULONG LineNumber,
  457. IN ULONG Tag
  458. )
  459. {
  460. PPOOL_HEADER header;
  461. KIRQL oldIrql;
  462. #if 1
  463. ULONG i;
  464. #endif
  465. #if POOL_TAGGING
  466. header = ExAllocatePoolWithTag( PoolType, sizeof(POOL_HEADER) + NumberOfBytes, Tag );
  467. #else
  468. header = ExAllocatePool( PoolType, sizeof(POOL_HEADER) + NumberOfBytes );
  469. #endif
  470. if ( header == NULL ) {
  471. return NULL;
  472. }
  473. header->NumberOfBytes = NumberOfBytes;
  474. // DbgPrint( "BOWSER: allocated type %d, size %d at %x\n", AllocationType, NumberOfBytes, header );
  475. ACQUIRE_SPIN_LOCK( &BowserTimeSpinLock, &oldIrql );
  476. CurrentAllocationCount++;
  477. CurrentAllocationSize += NumberOfBytes;
  478. #if 1
  479. //
  480. // Lets see if we've already allocated one of these guys.
  481. //
  482. for (i = 0;i < POOL_MAXTYPE ; i+= 1 ) {
  483. if ((PoolStats[i].LineNumber == LineNumber) &&
  484. (PoolStats[i].FileName == FileName)) {
  485. //
  486. // Yup, remember this allocation and return.
  487. //
  488. header->Stats = &PoolStats[i];
  489. PoolStats[i].Count++;
  490. PoolStats[i].Size += NumberOfBytes;
  491. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  492. return header + 1;
  493. }
  494. }
  495. for (i = NextFreeEntry; i < POOL_MAXTYPE ; i+= 1 ) {
  496. if ((PoolStats[i].LineNumber == 0) &&
  497. (PoolStats[i].FileName == NULL)) {
  498. PoolStats[i].Count++;
  499. PoolStats[i].Size += NumberOfBytes;
  500. PoolStats[i].FileName = FileName;
  501. PoolStats[i].LineNumber = LineNumber;
  502. header->Stats = &PoolStats[i];
  503. NextFreeEntry = i+1;
  504. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  505. return header + 1;
  506. }
  507. }
  508. header->Stats = &PoolStats[i];
  509. PoolStats[POOL_MAXTYPE].Count++;
  510. PoolStats[POOL_MAXTYPE].Size += NumberOfBytes;
  511. #endif
  512. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  513. return header + 1;
  514. }
  515. PVOID
  516. BowserAllocatePoolWithQuota (
  517. IN POOL_TYPE PoolType,
  518. IN ULONG NumberOfBytes,
  519. IN PCHAR FileName,
  520. IN ULONG LineNumber,
  521. IN ULONG Tag
  522. )
  523. {
  524. PPOOL_HEADER header;
  525. KIRQL oldIrql;
  526. #if 1
  527. ULONG i;
  528. #endif
  529. #if POOL_TAGGING
  530. header = ExAllocatePoolWithTagQuota( PoolType, sizeof(POOL_HEADER) + NumberOfBytes, Tag );
  531. #else
  532. header = ExAllocatePoolWithQuota( PoolType, sizeof(POOL_HEADER) + NumberOfBytes );
  533. #endif
  534. if ( header == NULL ) {
  535. return NULL;
  536. }
  537. header->NumberOfBytes = NumberOfBytes;
  538. // DbgPrint( "BOWSER: allocated type %d, size %d at %x\n", AllocationType, NumberOfBytes, header );
  539. ACQUIRE_SPIN_LOCK( &BowserTimeSpinLock, &oldIrql );
  540. CurrentAllocationCount++;
  541. CurrentAllocationSize += NumberOfBytes;
  542. #if 1
  543. //
  544. // Lets see if we've already allocated one of these guys.
  545. //
  546. for (i = 0;i < POOL_MAXTYPE ; i+= 1 ) {
  547. if ((PoolStats[i].LineNumber == LineNumber) &&
  548. (PoolStats[i].FileName == FileName)) {
  549. //
  550. // Yup, remember this allocation and return.
  551. //
  552. header->Stats = &PoolStats[i];
  553. PoolStats[i].Count++;
  554. PoolStats[i].Size += NumberOfBytes;
  555. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  556. return header + 1;
  557. }
  558. }
  559. for (i = NextFreeEntry; i < POOL_MAXTYPE ; i+= 1 ) {
  560. if ((PoolStats[i].LineNumber == 0) &&
  561. (PoolStats[i].FileName == NULL)) {
  562. PoolStats[i].Count++;
  563. PoolStats[i].Size += NumberOfBytes;
  564. PoolStats[i].FileName = FileName;
  565. PoolStats[i].LineNumber = LineNumber;
  566. header->Stats = &PoolStats[i];
  567. NextFreeEntry = i+1;
  568. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  569. return header + 1;
  570. }
  571. }
  572. header->Stats = &PoolStats[i];
  573. PoolStats[POOL_MAXTYPE].Count++;
  574. PoolStats[POOL_MAXTYPE].Size += NumberOfBytes;
  575. #endif
  576. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  577. return header + 1;
  578. }
  579. VOID
  580. BowserFreePool (
  581. IN PVOID P
  582. )
  583. {
  584. PPOOL_HEADER header;
  585. KIRQL oldIrql;
  586. PPOOL_STATS stats;
  587. ULONG size;
  588. header = (PPOOL_HEADER)P - 1;
  589. size = header->NumberOfBytes;
  590. stats = header->Stats;
  591. // if ( allocationType > POOL_MAXTYPE ) allocationType = POOL_MAXTYPE;
  592. // DbgPrint( "BOWSER: freed type %d, size %d at %x\n", allocationType, size, header );
  593. ACQUIRE_SPIN_LOCK( &BowserTimeSpinLock, &oldIrql );
  594. CurrentAllocationCount--;
  595. CurrentAllocationSize -= size;
  596. #if 1
  597. stats->Count--;
  598. stats->Size -= size;
  599. #endif
  600. RELEASE_SPIN_LOCK( &BowserTimeSpinLock, oldIrql );
  601. ExFreePool( header );
  602. return;
  603. }
  604. #endif // BOWSERPOOLDBG
  605. #if DBG
  606. ERESOURCE
  607. BrowserTraceLock;
  608. HANDLE
  609. BrowserTraceLogHandle = NULL;
  610. UCHAR LastCharacter = '\n';
  611. #ifndef PRODUCT1
  612. VOID
  613. BowserTrace(
  614. PCHAR FormatString,
  615. ...
  616. )
  617. #define LAST_NAMED_ARGUMENT FormatString
  618. {
  619. #define BR_OUTPUT_STRING_BUFFER_SIZE 1024
  620. CHAR OutputString[BR_OUTPUT_STRING_BUFFER_SIZE];
  621. IO_STATUS_BLOCK IoStatus;
  622. BOOLEAN ProcessAttached = FALSE;
  623. BOOLEAN ReleaseResource = FALSE;
  624. va_list ParmPtr; // Pointer to stack parms.
  625. KAPC_STATE ApcState;
  626. NTSTATUS Status;
  627. PAGED_CODE();
  628. try {
  629. //
  630. // Acquire the BrowserTraceLock to prevent race condition
  631. // when two threads try to initialize the handle
  632. //
  633. ExAcquireResourceExclusive(&BrowserTraceLock, TRUE);
  634. ReleaseResource = TRUE;
  635. if (BrowserTraceLogHandle == NULL) {
  636. // Attach to FSP when using handle
  637. if (IoGetCurrentProcess() != BowserFspProcess) {
  638. KeStackAttachProcess(BowserFspProcess, &ApcState );
  639. ProcessAttached = TRUE;
  640. }
  641. if (!NT_SUCCESS(BowserOpenTraceLogFile(L"\\SystemRoot\\Bowser.Log"))) {
  642. BrowserTraceLogHandle = (HANDLE) -1;
  643. if (ProcessAttached) {
  644. KeUnstackDetachProcess( &ApcState );
  645. ProcessAttached = FALSE;
  646. }
  647. if (ReleaseResource) {
  648. ExReleaseResource(&BrowserTraceLock);
  649. ReleaseResource = FALSE;
  650. }
  651. return;
  652. }
  653. } else if (BrowserTraceLogHandle == (HANDLE) -1) {
  654. if (ProcessAttached) {
  655. KeUnstackDetachProcess( &ApcState );
  656. ProcessAttached = FALSE;
  657. }
  658. if (ReleaseResource) {
  659. ExReleaseResource(&BrowserTraceLock);
  660. ReleaseResource = FALSE;
  661. }
  662. return;
  663. }
  664. } finally {
  665. if (ReleaseResource) {
  666. ExReleaseResource(&BrowserTraceLock);
  667. ReleaseResource = FALSE;
  668. }
  669. if (ProcessAttached) {
  670. KeUnstackDetachProcess( &ApcState );
  671. ProcessAttached = FALSE;
  672. }
  673. }
  674. //
  675. // We need a try-finally. In addition, have a try-except so that
  676. // exceptions are caught here itself.
  677. //
  678. try {
  679. try {
  680. LARGE_INTEGER EndOfFile;
  681. ExAcquireResourceExclusive(&BrowserTraceLock, TRUE);
  682. ReleaseResource = TRUE;
  683. // re-verify we should be tracing (under lock).
  684. if (BrowserTraceLogHandle == NULL) {
  685. try_return(Status);
  686. }
  687. EndOfFile.HighPart = 0xffffffff;
  688. EndOfFile.LowPart = FILE_WRITE_TO_END_OF_FILE;
  689. if (LastCharacter == '\n') {
  690. LARGE_INTEGER SystemTime;
  691. TIME_FIELDS TimeFields;
  692. KeQuerySystemTime(&SystemTime);
  693. ExSystemTimeToLocalTime(&SystemTime, &SystemTime);
  694. RtlTimeToTimeFields(&SystemTime, &TimeFields);
  695. //
  696. // The last character written was a newline character. We should
  697. // timestamp this record in the file.
  698. //
  699. StringCbPrintfA(OutputString,
  700. BR_OUTPUT_STRING_BUFFER_SIZE,
  701. "%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d: ",
  702. TimeFields.Month,
  703. TimeFields.Day,
  704. TimeFields.Hour,
  705. TimeFields.Minute,
  706. TimeFields.Second,
  707. TimeFields.Milliseconds);
  708. // Attach to FSP when using handle
  709. if ( !ProcessAttached && (IoGetCurrentProcess() != BowserFspProcess) ) {
  710. KeStackAttachProcess(BowserFspProcess, &ApcState );
  711. ProcessAttached = TRUE;
  712. }
  713. if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) {
  714. KdPrint(("Error writing time to Browser log file: %lX\n", Status));
  715. try_return(Status);
  716. }
  717. if (!NT_SUCCESS(IoStatus.Status)) {
  718. KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status));
  719. try_return(Status);
  720. }
  721. if (IoStatus.Information != strlen(OutputString)) {
  722. KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status));
  723. try_return(Status);
  724. }
  725. }
  726. va_start(ParmPtr, LAST_NAMED_ARGUMENT);
  727. // Be in caller's process when referencing parameters.
  728. if (ProcessAttached) {
  729. KeUnstackDetachProcess( &ApcState );
  730. ProcessAttached = FALSE;
  731. }
  732. //
  733. // Format the parameters to the string.
  734. //
  735. StringCchVPrintfA(OutputString, BR_OUTPUT_STRING_BUFFER_SIZE, FormatString, ParmPtr);
  736. // Attach to FSP when using handle
  737. if (IoGetCurrentProcess() != BowserFspProcess) {
  738. KeStackAttachProcess(BowserFspProcess, &ApcState );
  739. ProcessAttached = TRUE;
  740. }
  741. if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) {
  742. KdPrint(("Error writing string to Browser log file: %ld\n", Status));
  743. try_return(Status);
  744. }
  745. if (!NT_SUCCESS(IoStatus.Status)) {
  746. KdPrint(("Error writing string to Browser log file: %lX\n", IoStatus.Status));
  747. try_return(Status);
  748. }
  749. if (IoStatus.Information != strlen(OutputString)) {
  750. KdPrint(("Error writing string to Browser log file: %ld\n", IoStatus.Status));
  751. try_return(Status);
  752. }
  753. //
  754. // Remember the last character output to the log.
  755. //
  756. LastCharacter = OutputString[strlen(OutputString)-1];
  757. try_exit:NOTHING;
  758. } finally {
  759. if (ReleaseResource) {
  760. ExReleaseResource(&BrowserTraceLock);
  761. ReleaseResource = FALSE;
  762. }
  763. if (ProcessAttached) {
  764. KeUnstackDetachProcess( &ApcState );
  765. ProcessAttached = FALSE;
  766. }
  767. }
  768. } except(EXCEPTION_EXECUTE_HANDLER){
  769. }
  770. }
  771. #endif
  772. VOID
  773. BowserInitializeTraceLog()
  774. {
  775. PAGED_CODE();
  776. ExInitializeResource(&BrowserTraceLock);
  777. }
  778. NTSTATUS
  779. BowserOpenTraceLogFile(
  780. IN PWCHAR TraceFile
  781. )
  782. {
  783. UNICODE_STRING TraceFileName;
  784. OBJECT_ATTRIBUTES ObjA;
  785. NTSTATUS Status;
  786. IO_STATUS_BLOCK IoStatusBlock;
  787. PAGED_CODE();
  788. RtlInitUnicodeString(&TraceFileName, TraceFile);
  789. InitializeObjectAttributes(&ObjA, &TraceFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  790. Status = IoCreateFile(&BrowserTraceLogHandle,
  791. FILE_APPEND_DATA|SYNCHRONIZE,
  792. &ObjA,
  793. &IoStatusBlock,
  794. NULL,
  795. FILE_ATTRIBUTE_NORMAL,
  796. FILE_SHARE_READ,
  797. FILE_OPEN_IF,
  798. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY,
  799. NULL,
  800. 0,
  801. CreateFileTypeNone,
  802. NULL,
  803. IO_FORCE_ACCESS_CHECK | // Ensure the user has access to the file
  804. IO_NO_PARAMETER_CHECKING | // All of the buffers are kernel buffers
  805. IO_CHECK_CREATE_PARAMETERS // But double check parameter consistancy
  806. );
  807. if (!NT_SUCCESS(Status)) {
  808. KdPrint(("Bowser: Error creating trace file %ws %lX\n", TraceFile, Status));
  809. return Status;
  810. }
  811. return Status;
  812. }
  813. VOID
  814. BowserUninitializeTraceLog()
  815. {
  816. BOOLEAN ProcessAttached = FALSE;
  817. KAPC_STATE ApcState;
  818. PAGED_CODE();
  819. ExDeleteResource(&BrowserTraceLock);
  820. if (BrowserTraceLogHandle != NULL) {
  821. if (IoGetCurrentProcess() != BowserFspProcess) {
  822. KeStackAttachProcess(BowserFspProcess, &ApcState );
  823. ProcessAttached = TRUE;
  824. }
  825. ZwClose(BrowserTraceLogHandle);
  826. if (ProcessAttached) {
  827. KeUnstackDetachProcess( &ApcState );
  828. ProcessAttached = FALSE;
  829. }
  830. }
  831. BrowserTraceLogHandle = NULL;
  832. }
  833. NTSTATUS
  834. BowserDebugCall(
  835. IN PLMDR_REQUEST_PACKET InputBuffer,
  836. IN ULONG InputBufferLength
  837. )
  838. {
  839. NTSTATUS Status;
  840. BOOLEAN ProcessAttached = FALSE;
  841. KAPC_STATE ApcState;
  842. PAGED_CODE();
  843. if (IoGetCurrentProcess() != BowserFspProcess) {
  844. KeStackAttachProcess(BowserFspProcess, &ApcState );
  845. ProcessAttached = TRUE;
  846. }
  847. try {
  848. if (InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
  849. try_return(Status=STATUS_BUFFER_TOO_SMALL);
  850. }
  851. if ( InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION_DOM ) {
  852. try_return(Status=STATUS_INVALID_PARAMETER);
  853. }
  854. if (InputBuffer->Parameters.Debug.OpenLog && InputBuffer->Parameters.Debug.CloseLog) {
  855. try_return(Status=STATUS_INVALID_PARAMETER);
  856. }
  857. if (InputBuffer->Parameters.Debug.OpenLog) {
  858. ENSURE_IN_INPUT_BUFFER_STR( InputBuffer->Parameters.Debug.TraceFileName);
  859. Status = BowserOpenTraceLogFile(InputBuffer->Parameters.Debug.TraceFileName);
  860. } else if (InputBuffer->Parameters.Debug.CloseLog) {
  861. Status = ZwClose(BrowserTraceLogHandle);
  862. if (NT_SUCCESS(Status)) {
  863. BrowserTraceLogHandle = NULL;
  864. }
  865. } else if (InputBuffer->Parameters.Debug.TruncateLog) {
  866. FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
  867. IO_STATUS_BLOCK IoStatus;
  868. if (BrowserTraceLogHandle == NULL) {
  869. try_return(Status=STATUS_INVALID_HANDLE);
  870. }
  871. EndOfFileInformation.EndOfFile.HighPart = 0;
  872. EndOfFileInformation.EndOfFile.LowPart = 0;
  873. Status = NtSetInformationFile(BrowserTraceLogHandle,
  874. &IoStatus,
  875. &EndOfFileInformation,
  876. sizeof(EndOfFileInformation),
  877. FileEndOfFileInformation);
  878. } else {
  879. BowserDebugLogLevel = InputBuffer->Parameters.Debug.DebugTraceBits;
  880. KdPrint(("Setting Browser Debug Trace Bits to %lx\n", BowserDebugLogLevel));
  881. Status = STATUS_SUCCESS;
  882. }
  883. try_return(Status);
  884. try_exit:NOTHING;
  885. } finally {
  886. if (ProcessAttached) {
  887. KeUnstackDetachProcess( &ApcState );
  888. ProcessAttached = FALSE;
  889. }
  890. }
  891. return Status;
  892. }
  893. #endif
  894. BOOL
  895. BowserValidUnicodeString(
  896. IN PUNICODE_STRING Str
  897. )
  898. {
  899. // lifted from ASSERT_WELL_FORMED_UNICODE_STRING_IN - ntos\rtl\ntrtlp.h
  900. if ( !((Str)->Length&1) && (!((Str)->Buffer) || !(sizeof((Str)->Buffer)&1) ) ) {
  901. //
  902. // check for aligned buffer
  903. if POINTER_IS_ALIGNED( (Str)->Buffer, ALIGN_WCHAR ) {
  904. return TRUE;
  905. }
  906. }
  907. return FALSE;
  908. }