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.

1093 lines
30 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. logging.c
  5. Abstract:
  6. Verifier logging and verifier stop logic.
  7. Author:
  8. Silviu Calinoiu (SilviuC) 9-May-2002
  9. Daniel Mihai (DMihai) 9-May-2002
  10. --*/
  11. #include "pch.h"
  12. #include "verifier.h"
  13. #include "logging.h"
  14. #include "support.h"
  15. //
  16. // Verifier stop data.
  17. //
  18. ULONG_PTR AVrfpPreviousStopData[5];
  19. ULONG_PTR AVrfpStopData[5];
  20. LIST_ENTRY AVrfpDisabledStopsList;
  21. ULONG AVrfpNumberOfStopsDisabled;
  22. //
  23. // AVrfpStopDataLock is used to protect any access to
  24. // AVrfpPreviousStopData, AVrfpStopData and AVrfpDisabledStopsList.
  25. //
  26. RTL_CRITICAL_SECTION AVrfpStopDataLock;
  27. //
  28. // Set this value to 0 in the debugger to see duplicate stops.
  29. //
  30. LOGICAL AVrfpAutomaticallyDisableStops = TRUE;
  31. //
  32. // If true then logging was successfully initialized and can be used.
  33. // It is checked in VerifierLogMessage() to make sure we can log.
  34. //
  35. LOGICAL AVrfpLoggingInitialized;
  36. //
  37. // If true then logging was successfully initialized and it should be
  38. // used instead of the verifier stop debugger messages. It is used
  39. // in VerifierStopMessage().
  40. //
  41. LOGICAL AVrfpLoggingEnabled;
  42. //
  43. // True if process termination has been initiated after a
  44. // noncontinuable verifier stop.
  45. //
  46. LOGICAL AVrfpProcessBeingTerminated;
  47. //
  48. // Logging structures.
  49. //
  50. UNICODE_STRING AVrfpLoggingNtPath;
  51. WCHAR AVrfpLoggingPathBuffer [DOS_MAX_PATH_LENGTH];
  52. WCHAR AVrfpVariableValueBuffer [DOS_MAX_PATH_LENGTH];
  53. #define MESSAGE_BUFFER_LENGTH 1024
  54. CHAR AVrfpLoggingMessageBuffer [MESSAGE_BUFFER_LENGTH];
  55. ULONG AVrfpLoggingFailures;
  56. PWSTR AVrfpProcessFullName;
  57. //
  58. // Strings used for logging.
  59. //
  60. #define STR_VRF_LOG_STOP_MESSAGE "\r\n# LOGENTRY VERIFIER STOP %p: pid 0x%X: %s \r\n" \
  61. "# DESCRIPTION BEGIN \r\n" \
  62. "\t%p : %s\r\n\t%p : %s\r\n\t%p : %s\r\n\t%p : %s\r\n" \
  63. "# DESCRIPTION END \r\n"
  64. #define STR_VRF_DBG_STOP_MESSAGE "\n\n" \
  65. "===========================================================\n" \
  66. "VERIFIER STOP %p: pid 0x%X: %s \n" \
  67. "\n\t%p : %s\n\t%p : %s\n\t%p : %s\n\t%p : %s\n" \
  68. "===========================================================\n" \
  69. "%s\n" \
  70. "===========================================================\n\n"
  71. #define STR_VRF_LOG_NOCONTINUE_MESSAGE "\r\n# LOGENTRY VERIFIER: noncontinuable verifier stop" \
  72. " %p encountered. Terminating process. \r\n"
  73. #define STR_VRF_DBG_NOCONTINUE_MESSAGE "AVRF: Noncontinuable verifier stop %p encountered. " \
  74. "Terminating process ... \n"
  75. #define STR_VRF_LOG_STACK_CHECKS_WARN "# LOGENTRY VERIFIER WARNING: pid 0x%X: " \
  76. "stack checks have been disabled \r\n" \
  77. "# DESCRIPTION BEGIN \r\n" \
  78. "Stack checks require a debugger attached to the verified process. \r\n" \
  79. "# DESCRIPTION END \r\n"
  80. #define STR_VRF_LOG_INITIAL_MESSAGE "# LOG_BEGIN `%u/%u/%u %u:%u:%u.%u' `%ws' \r\n"
  81. #define STR_VRF_LOG_INITIAL_SETTINGS "# DESCRIPTION BEGIN \r\n" \
  82. " Global flags: 0x%08X \r\n" \
  83. " Verifier flags: 0x%08X \r\n" \
  84. " Process debugger attached: %s \r\n" \
  85. " Kernel debugger enabled: %s \r\n" \
  86. " Log path: %ws \r\n" \
  87. "# DESCRIPTION END \r\n"
  88. //
  89. // Forward declarations.
  90. //
  91. LOGICAL
  92. AVrfpIsCurrentStopDisabled (
  93. VOID
  94. );
  95. VOID
  96. AVrfpDisableCurrentStop (
  97. VOID
  98. );
  99. NTSTATUS
  100. AVrfpCreateLogFile (
  101. VOID
  102. );
  103. int __cdecl _vsnprintf(char *, size_t, const char *, va_list);
  104. int __cdecl _snwprintf (wchar_t *, size_t, const wchar_t *, ...);
  105. VOID
  106. AVrfpLogInitialMessage (
  107. VOID
  108. );
  109. LOGICAL
  110. AVrfpIsDebuggerPresent (
  111. VOID
  112. );
  113. /////////////////////////////////////////////////////////////////////
  114. ////////////////////////////////////////// Application verifier stops
  115. /////////////////////////////////////////////////////////////////////
  116. VOID
  117. VerifierStopMessage (
  118. ULONG_PTR Code,
  119. PCHAR Message,
  120. ULONG_PTR Param1, PCHAR Description1,
  121. ULONG_PTR Param2, PCHAR Description2,
  122. ULONG_PTR Param3, PCHAR Description3,
  123. ULONG_PTR Param4, PCHAR Description4
  124. )
  125. /*++
  126. Routine description:
  127. This routine is called by various verifier components to report errors found.
  128. The message is logged into the verifier log associated with the process and
  129. also printed in the debugger console.
  130. There are two flags that can be OR'd into the verifier stop code to modify the
  131. behavior:
  132. APPLICATION_VERIFIER_DO_NOT_BREAK - if this bit is set then the verifier stop is
  133. logged in the log and dumped in the debugger console and then the thread execution
  134. continues. For all intents and purposes this is considered a continuable stop.
  135. APPLICATION_VERIFIER_CONTINUABLE_BREAK - if this bit is set the stop is continuable.
  136. The stop is logged and and then a breakpoint gets executed. After the user continues
  137. the execution this verifier stop will be skipped.
  138. If none of the flags above is set the stop is considered non-continuable. In this case
  139. the stop is logged in the log aND dumped in the debugger console and then the process
  140. will be terminated. A final log entry will be logged to explain this action.
  141. Hopefully in time most of the stop codes will be continuable.
  142. Parameters:
  143. Code: Verifier stop code. The two flags described above can be OR'd into the code
  144. to change the behavior of the API. The verifier stop codes are defined in
  145. \base\published\nturtl.w and described in \base\win32\verifier\verifier_stop.doc.
  146. Message: Ascii string describing the failure. It is considered bad style to use several
  147. different messages with the same `Code'. Every different issue should have its own
  148. unique (Code, Message) pair.
  149. Param1, Description1: First arbitrary pointer to information and ascii description.
  150. Param2, Description2: Second arbitrary pointer to information and ascii description.
  151. Param3, Description3: Third arbitrary pointer to information and ascii description.
  152. Param4, Description4: Fourth arbitrary pointer to information and ascii description.
  153. Return value:
  154. None.
  155. --*/
  156. {
  157. LOGICAL DoNotBreak = FALSE;
  158. LOGICAL StopIsDisabled = FALSE;
  159. NTSTATUS Status;
  160. LOGICAL MustExitProcess = FALSE;
  161. LOGICAL ContinuableBreak = FALSE;
  162. LOGICAL BreakWasContinued = FALSE;
  163. PCHAR ContinueMessage;
  164. //
  165. // While process is getting terminated (due to a previous verifier stop)
  166. // we do not allow any new logging or dumping to debugger console.
  167. //
  168. if (AVrfpProcessBeingTerminated) {
  169. return;
  170. }
  171. //
  172. // Extract options from the stop code.
  173. //
  174. if ((Code & APPLICATION_VERIFIER_NO_BREAK)) {
  175. DoNotBreak = TRUE;
  176. Code &= ~APPLICATION_VERIFIER_NO_BREAK;
  177. //
  178. // A no_break is by design continuable.
  179. //
  180. ContinuableBreak = TRUE;
  181. }
  182. if ((Code & APPLICATION_VERIFIER_CONTINUABLE_BREAK)) {
  183. ContinuableBreak = TRUE;
  184. Code &= ~APPLICATION_VERIFIER_CONTINUABLE_BREAK;
  185. }
  186. //
  187. // Serialize multi-threaded access to the stop data.
  188. //
  189. RtlEnterCriticalSection (&AVrfpStopDataLock);
  190. //
  191. // Make it easy for a debugger to pick up the failure info.
  192. //
  193. RtlCopyMemory (AVrfpPreviousStopData,
  194. AVrfpStopData,
  195. sizeof AVrfpStopData);
  196. AVrfpStopData[0] = Code;
  197. AVrfpStopData[1] = Param1;
  198. AVrfpStopData[2] = Param2;
  199. AVrfpStopData[3] = Param3;
  200. AVrfpStopData[4] = Param4;
  201. //
  202. // Check if the current stop is disabled.
  203. //
  204. if (AVrfpAutomaticallyDisableStops != FALSE) {
  205. StopIsDisabled = AVrfpIsCurrentStopDisabled ();
  206. }
  207. //
  208. // If stop has not been encountered before we need to report it
  209. // in the debugger console and the verifier log.
  210. //
  211. if (StopIsDisabled == FALSE) {
  212. if (AVrfpLoggingEnabled) {
  213. VerifierLogMessage (STR_VRF_LOG_STOP_MESSAGE,
  214. Code, RtlGetCurrentProcessId(), Message,
  215. Param1, Description1,
  216. Param2, Description2,
  217. Param3, Description3,
  218. Param4, Description4);
  219. }
  220. if (ContinuableBreak) {
  221. ContinueMessage = "This verifier stop is continuable. \n"
  222. "After debugging it use `go' to continue.";
  223. }
  224. else {
  225. ContinueMessage = "This verifier stop is not continuable. Process will be terminated \n"
  226. "when you use the `go' debugger command.";
  227. }
  228. DbgPrint (STR_VRF_DBG_STOP_MESSAGE,
  229. Code, RtlGetCurrentProcessId(), Message,
  230. Param1, Description1,
  231. Param2, Description2,
  232. Param3, Description3,
  233. Param4, Description4,
  234. ContinueMessage);
  235. if (DoNotBreak == FALSE) {
  236. //
  237. // We do not really break if there is not a debugger around. If we do it
  238. // there will be an unhandle breakpoint exception in the process that
  239. // will be picked up by PC-Health. Since we do not break it will be as if
  240. // someone hit `go' in the debugger.
  241. //
  242. if (AVrfpIsDebuggerPresent() == TRUE) {
  243. DbgBreakPoint ();
  244. }
  245. BreakWasContinued = TRUE;
  246. }
  247. //
  248. // If the stop is not continuable (including the `donotbreak' flavor)
  249. // then we need to terminate the process. Otherwise register the current
  250. // stop as disabled so that we do not see it over and over again.
  251. //
  252. if (ContinuableBreak == FALSE && DoNotBreak == FALSE) {
  253. MustExitProcess = TRUE;
  254. }
  255. else {
  256. if (AVrfpAutomaticallyDisableStops) {
  257. AVrfpDisableCurrentStop ();
  258. }
  259. }
  260. }
  261. RtlLeaveCriticalSection (&AVrfpStopDataLock);
  262. if (MustExitProcess) {
  263. //
  264. // Hopefully in the future most of the verifier stops will be
  265. // continuable. Right now we just terminate the process.
  266. //
  267. if (AVrfpLoggingEnabled) {
  268. VerifierLogMessage (STR_VRF_LOG_NOCONTINUE_MESSAGE, Code);
  269. }
  270. DbgPrint (STR_VRF_DBG_NOCONTINUE_MESSAGE, Code);
  271. AVrfpProcessBeingTerminated = TRUE;
  272. Status = NtTerminateProcess (NtCurrentProcess(), STATUS_UNSUCCESSFUL);
  273. if (!NT_SUCCESS(Status)) {
  274. DbgPrint ("AVRF: Terminate process after verifier stop failed with %X \n", Status);
  275. DbgBreakPoint ();
  276. }
  277. }
  278. }
  279. /////////////////////////////////////////////////////////////////////
  280. ///////////////////////////////////////////////////////// Logging API
  281. /////////////////////////////////////////////////////////////////////
  282. NTSTATUS
  283. VerifierLogMessage (
  284. PCHAR Format,
  285. ...
  286. )
  287. /*++
  288. Routine description:
  289. This routine tries to open (non-shareable) the verifier log file
  290. associated with the current process. If it cannot do it because it is
  291. opened for someone else it will retry a few times with a delay in between.
  292. This way it will effectively wait for some other thread that is currently
  293. logging. Other tools that try to look at the log while a process is running
  294. will have to do it quickly if they do not want to affect the logging. Since
  295. logging is a rare event this scheme seems to me solid enough. The function
  296. is designed to survive the situation where someone keeps the file open for
  297. too long by just skipping log messages.
  298. Parameters:
  299. Format: string format parameters a la printf.
  300. ...: rest of the prinf-like parameters.
  301. Return value:
  302. None. All errors encountered in the function are supposed to be continuable.
  303. --*/
  304. {
  305. va_list Params;
  306. OBJECT_ATTRIBUTES ObjectAttributes;
  307. NTSTATUS Status;
  308. HANDLE LogHandle;
  309. IO_STATUS_BLOCK IoStatusBlock;
  310. LARGE_INTEGER Offset;
  311. LONG MessageSize;
  312. ULONG OpenFlags;
  313. ULONG RetryCount;
  314. LARGE_INTEGER SleepTime;
  315. va_start (Params, Format);
  316. if (AVrfpLoggingInitialized == FALSE) {
  317. return STATUS_UNSUCCESSFUL;
  318. }
  319. OpenFlags = FILE_OPEN;
  320. SleepTime.QuadPart = - (10 * 1000 * 1000 * 1); // 1 sec.
  321. //
  322. // Attempt to get a handle to our log file.
  323. //
  324. InitializeObjectAttributes (&ObjectAttributes,
  325. &AVrfpLoggingNtPath,
  326. OBJ_CASE_INSENSITIVE,
  327. NULL,
  328. NULL);
  329. RetryCount = 0;
  330. //
  331. // If somebody is actively logging into the file we will keep
  332. // looping for a while until the handle is closed or we tried enough
  333. // and did not succeed. This offers synchronization between competing
  334. // threads logging simultaneously.
  335. //
  336. do {
  337. Status = NtCreateFile (&LogHandle,
  338. FILE_APPEND_DATA | SYNCHRONIZE,
  339. &ObjectAttributes,
  340. &IoStatusBlock,
  341. NULL,
  342. FILE_ATTRIBUTE_NORMAL,
  343. 0,
  344. OpenFlags,
  345. 0,
  346. NULL,
  347. 0);
  348. if (Status == STATUS_SHARING_VIOLATION) {
  349. NtDelayExecution (FALSE, &SleepTime);
  350. RetryCount += 1;
  351. }
  352. } while (Status == STATUS_SHARING_VIOLATION && RetryCount < 5);
  353. if (! NT_SUCCESS(Status)) {
  354. if (Status == STATUS_SHARING_VIOLATION) {
  355. DbgPrint ("AVRF: verifier log file %ws kept open for too long (status %X)\n",
  356. AVrfpLoggingNtPath.Buffer,
  357. Status);
  358. }
  359. else {
  360. DbgPrint ("AVRF: failed to open verifier log file %ws (status %X)\n",
  361. AVrfpLoggingNtPath.Buffer,
  362. Status);
  363. }
  364. AVrfpLoggingFailures += 1;
  365. return Status;
  366. }
  367. //
  368. // Prepare and write the message. Write the data out to the file.
  369. // Synchronization to the preparation buffer is assured by the log file
  370. // handle opened in non-sharable mode which means no one can be in the same
  371. // state (writing into the buffer) right now.
  372. //
  373. IoStatusBlock.Status = 0;
  374. IoStatusBlock.Information = 0;
  375. Offset.LowPart = 0;
  376. Offset.HighPart = 0;
  377. MessageSize = _vsnprintf (AVrfpLoggingMessageBuffer,
  378. MESSAGE_BUFFER_LENGTH,
  379. Format,
  380. Params);
  381. if (MessageSize < 0) {
  382. DbgPrint ("AVRF: failed in _vsnprintf() to prepare log message\n");
  383. AVrfpLoggingFailures += 1;
  384. Status = STATUS_UNSUCCESSFUL;
  385. goto Exit;
  386. }
  387. Status = NtWriteFile (LogHandle,
  388. NULL,
  389. NULL,
  390. NULL,
  391. &IoStatusBlock,
  392. (PVOID)AVrfpLoggingMessageBuffer,
  393. MessageSize,
  394. &Offset,
  395. NULL);
  396. if (Status == STATUS_PENDING) {
  397. //
  398. // We need to wait for the operation to complete.
  399. //
  400. Status = NtWaitForSingleObject (LogHandle, FALSE, NULL);
  401. if (NT_SUCCESS(Status)) {
  402. Status = IoStatusBlock.Status;
  403. }
  404. else {
  405. //
  406. // If this happens we need to debug it.
  407. //
  408. DbgPrint ("AVRF: Wait for pending write I/O operation failed with %X \n", Status);
  409. DbgBreakPoint ();
  410. }
  411. }
  412. if (! NT_SUCCESS(Status)) {
  413. DbgPrint ("AVRF: failed to write into verifier log file %ws (status %X)\n",
  414. AVrfpLoggingNtPath.Buffer,
  415. Status);
  416. AVrfpLoggingFailures += 1;
  417. goto Exit;
  418. }
  419. Exit:
  420. NtClose (LogHandle);
  421. return Status;
  422. }
  423. /////////////////////////////////////////////////////////////////////
  424. ////////////////////////////////////////////////////// Stop disabling
  425. /////////////////////////////////////////////////////////////////////
  426. VOID
  427. AVrfpDisableCurrentStop (
  428. VOID
  429. )
  430. /*++
  431. Routine description:
  432. This routine inserts the values from AVrfpStopData
  433. into the list of disabled stops.
  434. Parameters:
  435. None, using global AVrfpStopData and AVrfpDisabledStopsList.
  436. Return value:
  437. None.
  438. Environment:
  439. User mode, AVrfpStopDataLock held by the caller.
  440. --*/
  441. {
  442. PAVRFP_STOP_DATA StopData;
  443. StopData = AVrfpAllocate (sizeof *StopData);
  444. if (StopData != NULL) {
  445. ASSERT (sizeof (AVrfpStopData) == sizeof (StopData->Data));
  446. RtlCopyMemory (&StopData->Data,
  447. AVrfpStopData,
  448. sizeof AVrfpStopData);
  449. InsertHeadList (&AVrfpDisabledStopsList,
  450. &StopData->ListEntry);
  451. AVrfpNumberOfStopsDisabled += 1;
  452. }
  453. }
  454. LOGICAL
  455. AVrfpIsCurrentStopDisabled (
  456. VOID
  457. )
  458. /*++
  459. Routine description:
  460. This routine is searching for the stop data from AVrfpStopData
  461. in the list of disabled stops.
  462. Parameters:
  463. None, using global AVrfpStopData and AVrfpDisabledStopsList.
  464. Return value:
  465. TRUE if the current stop is disabled, FALSE otherwise.
  466. Environment:
  467. User mode, AVrfpStopDataLock held by the caller.
  468. --*/
  469. {
  470. LOGICAL Disabled;
  471. PAVRFP_STOP_DATA StopData;
  472. PLIST_ENTRY Entry;
  473. ULONG Index;
  474. Disabled = FALSE;
  475. ASSERT (sizeof (AVrfpStopData) == sizeof (StopData->Data));
  476. ASSERT (sizeof (AVrfpStopData[0]) == sizeof (StopData->Data[0]));
  477. for (Entry = AVrfpDisabledStopsList.Flink;
  478. Entry != &AVrfpDisabledStopsList;
  479. Entry = Entry->Flink) {
  480. StopData = CONTAINING_RECORD (Entry,
  481. AVRFP_STOP_DATA,
  482. ListEntry);
  483. Disabled = TRUE;
  484. for (Index = 0; Index < sizeof (AVrfpStopData) / sizeof (AVrfpStopData[0]); Index += 1) {
  485. if (AVrfpStopData[Index] != StopData->Data[Index]) {
  486. Disabled = FALSE;
  487. break;
  488. }
  489. }
  490. if (Disabled != FALSE) {
  491. break;
  492. }
  493. }
  494. return Disabled;
  495. }
  496. /////////////////////////////////////////////////////////////////////
  497. ////////////////////////////////////////////////////// Initialization
  498. /////////////////////////////////////////////////////////////////////
  499. LOGICAL
  500. AVrfpIsDebuggerPresent (
  501. VOID
  502. )
  503. /*++
  504. Routine description:
  505. This routine checks out if we have any kind of debuggers active.
  506. Note that we cannot do this check only once during process
  507. initialization because debuggers can be attached and detached
  508. from a process while the process is running.
  509. Parameters:
  510. None.
  511. Return value:
  512. TRUE if a user mode debugger is attached to the current process or
  513. kernel mode debugger is enabled.
  514. --*/
  515. {
  516. if (NtCurrentPeb()->BeingDebugged) {
  517. return TRUE;
  518. }
  519. if (USER_SHARED_DATA->KdDebuggerEnabled) {
  520. return TRUE;
  521. }
  522. return FALSE;
  523. }
  524. NTSTATUS
  525. AVrfpInitializeVerifierStops (
  526. VOID
  527. )
  528. /*++
  529. Routine description:
  530. This routine initializes verifier stops logic.
  531. Parameters:
  532. None.
  533. Return value:
  534. STATUS_SUCCESS if enabled successfully. Various errors
  535. otherwise.
  536. --*/
  537. {
  538. NTSTATUS Status;
  539. InitializeListHead (&AVrfpDisabledStopsList);
  540. Status = RtlInitializeCriticalSection (&AVrfpStopDataLock);
  541. return Status;
  542. }
  543. NTSTATUS
  544. AVrfpInitializeVerifierLogging (
  545. VOID
  546. )
  547. /*++
  548. Routine description:
  549. This routine initializes verifier structures for logging. It is called
  550. during verifier engine initialization (early process stage).
  551. Stops will happen if a debugger is present and logging was
  552. not requested explicitely. Al other combinations will enable
  553. logging. In addition if no user mode debugger is attached the
  554. stack overflow checking is disabled altogether.
  555. Parameters:
  556. None.
  557. Return value:
  558. STATUS_SUCCESS if logging was enabled successfully. Various errors
  559. otherwise.
  560. --*/
  561. {
  562. NTSTATUS Status;
  563. //
  564. // Create the log file.
  565. //
  566. Status = AVrfpCreateLogFile ();
  567. if (! NT_SUCCESS(Status)) {
  568. return Status;
  569. }
  570. //
  571. // We are done now we can mark the logging initialization as successful.
  572. //
  573. AVrfpLoggingInitialized = TRUE;
  574. //
  575. // Stack overflow checking gets disabled if we no debugger attached because
  576. // it is impossible to recover from the failure and we cannot intercept
  577. // it to present a decent debugging message.
  578. //
  579. if (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_STACK_CHECKS) {
  580. if (AVrfpIsDebuggerPresent() == FALSE) {
  581. VerifierLogMessage (STR_VRF_LOG_STACK_CHECKS_WARN,
  582. RtlGetCurrentProcessId());
  583. }
  584. }
  585. //
  586. // Log startup information.
  587. //
  588. AVrfpLogInitialMessage ();
  589. //
  590. // Logging is always enabled except if the verifier is enabled system-wide.
  591. // For that case this function is not even called.
  592. //
  593. AVrfpLoggingEnabled = TRUE;
  594. return Status;
  595. }
  596. NTSTATUS
  597. AVrfpCreateLogFile (
  598. VOID
  599. )
  600. /*++
  601. Routine description:
  602. This routine tries to create a log file unique for the current process.
  603. The path of the log file is either read from VERIFIER_LOG_PATH environment
  604. variable or the default value `%ALLUSERSPROFILE%\Documents\AppVerifierLogs'
  605. is used. The syntax of the log file name is `IMAGENAME.UNIQUEID.log'. The
  606. IMAGENAME includes the extension since there are executable files that have
  607. extensions different than .exe (e.g. .scr for screensavers).
  608. The routine will keep incrementing an integer ID (starting from zero) until
  609. it manages to create a file that did not exist before.
  610. Parameters:
  611. None.
  612. Return value:
  613. STATUS_SUCCESS if it was successful in creating an unique log file for this
  614. process. Various status errors otherwise.
  615. --*/
  616. {
  617. LOGICAL Success;
  618. OBJECT_ATTRIBUTES ObjectAttributes;
  619. NTSTATUS Status;
  620. HANDLE LogHandle;
  621. IO_STATUS_BLOCK IoStatusBlock;
  622. ULONG OpenFlags;
  623. PWSTR ProcessName;
  624. ULONG FileNameId;
  625. UNICODE_STRING LogPathVariableName;
  626. UNICODE_STRING LogPath;
  627. LOGICAL DefaultLogPath;
  628. PPEB Peb;
  629. OpenFlags = FILE_CREATE;
  630. FileNameId = 0;
  631. Peb = NtCurrentPeb();
  632. {
  633. //
  634. // We need to find out the full path to the image being executed.
  635. // It is safe to read loader structures since this function
  636. // is called from verifier!DllMain and the loader lock is owned
  637. // by the current thread when this happens. This is the lock that
  638. // protects access to the structures.
  639. //
  640. PPEB_LDR_DATA Ldr;
  641. PLIST_ENTRY Head;
  642. PLIST_ENTRY Next;
  643. PLDR_DATA_TABLE_ENTRY Entry;
  644. Ldr = Peb->Ldr;
  645. Head = &Ldr->InLoadOrderModuleList;
  646. Next = Head->Flink;
  647. Entry = CONTAINING_RECORD (Next,
  648. LDR_DATA_TABLE_ENTRY,
  649. InLoadOrderLinks);
  650. ProcessName = Entry->BaseDllName.Buffer;
  651. AVrfpProcessFullName = Entry->FullDllName.Buffer;
  652. }
  653. Status = STATUS_SUCCESS;
  654. DefaultLogPath = FALSE;
  655. //
  656. // Get the value of `VERIFIER_LOG_PATH' environment variable.
  657. //
  658. RtlInitUnicodeString (&LogPathVariableName,
  659. L"VERIFIER_LOG_PATH");
  660. RtlInitEmptyUnicodeString (&LogPath,
  661. AVrfpVariableValueBuffer,
  662. DOS_MAX_PATH_LENGTH);
  663. Status = RtlQueryEnvironmentVariable_U (NULL,
  664. &LogPathVariableName,
  665. &LogPath);
  666. if (! NT_SUCCESS(Status)) {
  667. //
  668. // Get the value of `AllUsersProfile' environment variable.
  669. //
  670. RtlInitUnicodeString (&LogPathVariableName,
  671. L"ALLUSERSPROFILE");
  672. RtlInitEmptyUnicodeString (&LogPath,
  673. AVrfpVariableValueBuffer,
  674. DOS_MAX_PATH_LENGTH);
  675. Status = RtlQueryEnvironmentVariable_U (NULL,
  676. &LogPathVariableName,
  677. &LogPath);
  678. if (! NT_SUCCESS(Status)) {
  679. DbgPrint ("AVRF: Failed to get environment variable (status %X)\n", Status);
  680. return Status;
  681. }
  682. DefaultLogPath = TRUE;
  683. }
  684. //
  685. // We try to create a log file with the proper name (given our convention)
  686. // that is unique for this process. If the file with that name already exists
  687. // we will get an error and we will try a different name.
  688. //
  689. do {
  690. //
  691. // Prepare log path name with unique Id appended.
  692. //
  693. if (DefaultLogPath) {
  694. _snwprintf (AVrfpLoggingPathBuffer,
  695. DOS_MAX_PATH_LENGTH - 1,
  696. L"%ws\\Documents\\AppVerifierLogs\\%ws.%u.log",
  697. AVrfpVariableValueBuffer,
  698. ProcessName,
  699. FileNameId);
  700. }
  701. else {
  702. _snwprintf (AVrfpLoggingPathBuffer,
  703. DOS_MAX_PATH_LENGTH - 1,
  704. L"%ws\\%ws.%u.log",
  705. AVrfpVariableValueBuffer,
  706. ProcessName,
  707. FileNameId);
  708. }
  709. Success = RtlDosPathNameToNtPathName_U (AVrfpLoggingPathBuffer,
  710. &AVrfpLoggingNtPath,
  711. NULL,
  712. NULL);
  713. if (Success == FALSE) {
  714. DbgPrint ("AVRF: Failed to convert to an NT path the verifier log path.\n");
  715. return STATUS_UNSUCCESSFUL;
  716. }
  717. //
  718. // Attempt to get a handle to our log file.
  719. //
  720. InitializeObjectAttributes (&ObjectAttributes,
  721. &AVrfpLoggingNtPath,
  722. OBJ_CASE_INSENSITIVE,
  723. NULL,
  724. NULL);
  725. Status = NtCreateFile (&LogHandle,
  726. FILE_APPEND_DATA,
  727. &ObjectAttributes,
  728. &IoStatusBlock,
  729. NULL,
  730. FILE_ATTRIBUTE_NORMAL,
  731. 0,
  732. OpenFlags,
  733. 0,
  734. NULL,
  735. 0);
  736. if (Status == STATUS_OBJECT_NAME_COLLISION) {
  737. FileNameId += 1;
  738. RtlFreeUnicodeString (&AVrfpLoggingNtPath);
  739. }
  740. } while (Status == STATUS_OBJECT_NAME_COLLISION);
  741. if (! NT_SUCCESS(Status)) {
  742. DbgPrint ("AVRF: failed to create verifier log file %ws (status %X)\n",
  743. AVrfpLoggingNtPath.Buffer,
  744. Status);
  745. return Status;
  746. }
  747. NtClose (LogHandle);
  748. return Status;
  749. }
  750. VOID
  751. AVrfpLogInitialMessage (
  752. VOID
  753. )
  754. {
  755. LARGE_INTEGER SystemTime;
  756. LARGE_INTEGER LocalTime;
  757. TIME_FIELDS TimeFields;
  758. //
  759. // Read system time from shared region.
  760. //
  761. do {
  762. SystemTime.HighPart = USER_SHARED_DATA->SystemTime.High1Time;
  763. SystemTime.LowPart = USER_SHARED_DATA->SystemTime.LowPart;
  764. } while (SystemTime.HighPart != USER_SHARED_DATA->SystemTime.High2Time);
  765. //
  766. // Convert to local time and split into fields.
  767. //
  768. LocalTime.QuadPart = 0;
  769. RtlSystemTimeToLocalTime (&SystemTime, &LocalTime);
  770. RtlZeroMemory (&TimeFields, sizeof TimeFields);
  771. RtlTimeToTimeFields(&LocalTime,&TimeFields);
  772. //
  773. // Dump time and process full path.
  774. //
  775. VerifierLogMessage (STR_VRF_LOG_INITIAL_MESSAGE,
  776. (ULONG)TimeFields.Month,
  777. (ULONG)TimeFields.Day,
  778. (ULONG)TimeFields.Year,
  779. (ULONG)TimeFields.Hour,
  780. (ULONG)TimeFields.Minute,
  781. (ULONG)TimeFields.Second,
  782. (ULONG)TimeFields.Milliseconds,
  783. AVrfpProcessFullName);
  784. //
  785. // Dump settings.
  786. //
  787. VerifierLogMessage (STR_VRF_LOG_INITIAL_SETTINGS,
  788. NtCurrentPeb()->NtGlobalFlag,
  789. AVrfpProvider.VerifierFlags,
  790. (NtCurrentPeb()->BeingDebugged) ? "yes" : "no",
  791. ((USER_SHARED_DATA->KdDebuggerEnabled)) ? "yes" : "no",
  792. AVrfpLoggingPathBuffer);
  793. }