Source code of Windows XP (NT5)
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.

4233 lines
120 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. psquery.c
  5. Abstract:
  6. This module implements the set and query functions for
  7. process and thread objects.
  8. Author:
  9. Mark Lucovsky (markl) 17-Aug-1989
  10. Revision History:
  11. --*/
  12. #include "psp.h"
  13. #include "winerror.h"
  14. #if defined(_WIN64)
  15. #include <wow64t.h>
  16. #endif
  17. //
  18. // Process Pooled Quota Usage and Limits
  19. // NtQueryInformationProcess using ProcessPooledUsageAndLimits
  20. //
  21. //
  22. // this is the csrss process !
  23. //
  24. extern PEPROCESS ExpDefaultErrorPortProcess;
  25. BOOLEAN PsWatchEnabled = FALSE;
  26. #ifdef ALLOC_DATA_PRAGMA
  27. #pragma const_seg("PAGECONST")
  28. #endif
  29. const KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL+1] = {8,4,8,13,24,6,10};
  30. NTSTATUS
  31. PsConvertToGuiThread(
  32. VOID
  33. );
  34. NTSTATUS
  35. PspQueryWorkingSetWatch(
  36. IN HANDLE ProcessHandle,
  37. IN PROCESSINFOCLASS ProcessInformationClass,
  38. OUT PVOID ProcessInformation,
  39. IN ULONG ProcessInformationLength,
  40. OUT PULONG ReturnLength OPTIONAL,
  41. IN KPROCESSOR_MODE PreviousMode
  42. );
  43. NTSTATUS
  44. PspQueryQuotaLimits(
  45. IN HANDLE ProcessHandle,
  46. IN PROCESSINFOCLASS ProcessInformationClass,
  47. OUT PVOID ProcessInformation,
  48. IN ULONG ProcessInformationLength,
  49. OUT PULONG ReturnLength OPTIONAL,
  50. IN KPROCESSOR_MODE PreviousMode
  51. );
  52. NTSTATUS
  53. PspQueryPooledQuotaLimits(
  54. IN HANDLE ProcessHandle,
  55. IN PROCESSINFOCLASS ProcessInformationClass,
  56. OUT PVOID ProcessInformation,
  57. IN ULONG ProcessInformationLength,
  58. OUT PULONG ReturnLength OPTIONAL,
  59. IN KPROCESSOR_MODE PreviousMode
  60. );
  61. NTSTATUS
  62. PspSetQuotaLimits(
  63. IN HANDLE ProcessHandle,
  64. IN PROCESSINFOCLASS ProcessInformationClass,
  65. IN PVOID ProcessInformation,
  66. IN ULONG ProcessInformationLength,
  67. IN KPROCESSOR_MODE PreviousMode
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text(PAGE, PsEstablishWin32Callouts)
  71. #pragma alloc_text(PAGE, PsConvertToGuiThread)
  72. #pragma alloc_text(PAGE, NtQueryInformationProcess)
  73. #pragma alloc_text(PAGE, NtSetInformationProcess)
  74. #pragma alloc_text(PAGE, NtQueryPortInformationProcess)
  75. #pragma alloc_text(PAGE, NtQueryInformationThread)
  76. #pragma alloc_text(PAGE, NtSetInformationThread)
  77. #pragma alloc_text(PAGE, PsSetProcessPriorityByClass)
  78. #pragma alloc_text(PAGE, PspSetPrimaryToken)
  79. #pragma alloc_text(PAGE, PspSetQuotaLimits)
  80. #pragma alloc_text(PAGE, PspQueryQuotaLimits)
  81. #pragma alloc_text(PAGE, PspQueryPooledQuotaLimits)
  82. #pragma alloc_text(PAGELK, PspQueryWorkingSetWatch)
  83. #endif
  84. NTSTATUS
  85. PspQueryWorkingSetWatch(
  86. IN HANDLE ProcessHandle,
  87. IN PROCESSINFOCLASS ProcessInformationClass,
  88. OUT PVOID ProcessInformation,
  89. IN ULONG ProcessInformationLength,
  90. OUT PULONG ReturnLength OPTIONAL,
  91. IN KPROCESSOR_MODE PreviousMode
  92. )
  93. {
  94. PPAGEFAULT_HISTORY WorkingSetCatcher;
  95. ULONG SpaceNeeded;
  96. PEPROCESS Process;
  97. KIRQL OldIrql;
  98. NTSTATUS st;
  99. UNREFERENCED_PARAMETER (ProcessInformationClass);
  100. st = ObReferenceObjectByHandle (ProcessHandle,
  101. PROCESS_QUERY_INFORMATION,
  102. PsProcessType,
  103. PreviousMode,
  104. (PVOID *)&Process,
  105. NULL);
  106. if (!NT_SUCCESS (st)) {
  107. return st;
  108. }
  109. WorkingSetCatcher = Process->WorkingSetWatch;
  110. if (WorkingSetCatcher == NULL) {
  111. ObDereferenceObject (Process);
  112. return STATUS_UNSUCCESSFUL;
  113. }
  114. MmLockPagableSectionByHandle (ExPageLockHandle);
  115. ExAcquireSpinLock (&WorkingSetCatcher->SpinLock,&OldIrql);
  116. if (WorkingSetCatcher->CurrentIndex) {
  117. //
  118. // Null Terminate the first empty entry in the buffer
  119. //
  120. WorkingSetCatcher->WatchInfo[WorkingSetCatcher->CurrentIndex].FaultingPc = NULL;
  121. //Store a special Va value if the buffer was full and
  122. //page faults could have been lost
  123. if (WorkingSetCatcher->CurrentIndex != WorkingSetCatcher->MaxIndex) {
  124. WorkingSetCatcher->WatchInfo[WorkingSetCatcher->CurrentIndex].FaultingVa = NULL;
  125. } else {
  126. WorkingSetCatcher->WatchInfo[WorkingSetCatcher->CurrentIndex].FaultingVa = (PVOID) 1;
  127. }
  128. SpaceNeeded = (WorkingSetCatcher->CurrentIndex+1) * sizeof(PROCESS_WS_WATCH_INFORMATION);
  129. } else {
  130. ExReleaseSpinLock (&WorkingSetCatcher->SpinLock, OldIrql);
  131. MmUnlockPagableImageSection (ExPageLockHandle);
  132. ObDereferenceObject (Process);
  133. return STATUS_NO_MORE_ENTRIES;
  134. }
  135. if (ProcessInformationLength < SpaceNeeded) {
  136. ExReleaseSpinLock (&WorkingSetCatcher->SpinLock, OldIrql);
  137. MmUnlockPagableImageSection (ExPageLockHandle);
  138. ObDereferenceObject (Process);
  139. return STATUS_BUFFER_TOO_SMALL;
  140. }
  141. //
  142. // Mark the Working Set buffer as full and then drop the lock
  143. // and copy the bytes
  144. //
  145. WorkingSetCatcher->CurrentIndex = MAX_WS_CATCH_INDEX;
  146. ExReleaseSpinLock (&WorkingSetCatcher->SpinLock,OldIrql);
  147. try {
  148. RtlCopyMemory (ProcessInformation, &WorkingSetCatcher->WatchInfo[0], SpaceNeeded);
  149. if (ARGUMENT_PRESENT (ReturnLength) ) {
  150. *ReturnLength = SpaceNeeded;
  151. }
  152. } except (EXCEPTION_EXECUTE_HANDLER) {
  153. st = GetExceptionCode ();
  154. }
  155. ExAcquireSpinLock (&WorkingSetCatcher->SpinLock, &OldIrql);
  156. WorkingSetCatcher->CurrentIndex = 0;
  157. ExReleaseSpinLock (&WorkingSetCatcher->SpinLock, OldIrql);
  158. MmUnlockPagableImageSection (ExPageLockHandle);
  159. ObDereferenceObject (Process);
  160. return st;
  161. }
  162. NTSTATUS
  163. PspQueryQuotaLimits(
  164. IN HANDLE ProcessHandle,
  165. IN PROCESSINFOCLASS ProcessInformationClass,
  166. OUT PVOID ProcessInformation,
  167. IN ULONG ProcessInformationLength,
  168. OUT PULONG ReturnLength OPTIONAL,
  169. IN KPROCESSOR_MODE PreviousMode
  170. )
  171. {
  172. QUOTA_LIMITS QuotaLimits;
  173. PEPROCESS Process;
  174. NTSTATUS st;
  175. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  176. UNREFERENCED_PARAMETER (ProcessInformationClass);
  177. if ( ProcessInformationLength != (ULONG) sizeof(QUOTA_LIMITS) ) {
  178. return STATUS_INFO_LENGTH_MISMATCH;
  179. }
  180. st = ObReferenceObjectByHandle(
  181. ProcessHandle,
  182. PROCESS_QUERY_INFORMATION,
  183. PsProcessType,
  184. PreviousMode,
  185. (PVOID *)&Process,
  186. NULL
  187. );
  188. if ( !NT_SUCCESS(st) ) {
  189. return st;
  190. }
  191. QuotaBlock = Process->QuotaBlock;
  192. if (QuotaBlock != &PspDefaultQuotaBlock) {
  193. QuotaLimits.PagedPoolLimit = QuotaBlock->QuotaEntry[PsPagedPool].Limit;
  194. QuotaLimits.NonPagedPoolLimit = QuotaBlock->QuotaEntry[PsNonPagedPool].Limit;
  195. QuotaLimits.PagefileLimit = QuotaBlock->QuotaEntry[PsPageFile].Limit;
  196. QuotaLimits.TimeLimit.LowPart = 0xffffffff;
  197. QuotaLimits.TimeLimit.HighPart = 0xffffffff;
  198. } else {
  199. QuotaLimits.PagedPoolLimit = (SIZE_T)-1;
  200. QuotaLimits.NonPagedPoolLimit = (SIZE_T)-1;
  201. QuotaLimits.PagefileLimit = (SIZE_T)-1;
  202. QuotaLimits.TimeLimit.LowPart = 0xffffffff;
  203. QuotaLimits.TimeLimit.HighPart = 0xffffffff;
  204. }
  205. QuotaLimits.MinimumWorkingSetSize =
  206. ((SIZE_T) Process->Vm.MinimumWorkingSetSize) << PAGE_SHIFT;
  207. QuotaLimits.MaximumWorkingSetSize =
  208. ((SIZE_T) Process->Vm.MaximumWorkingSetSize) << PAGE_SHIFT;
  209. ObDereferenceObject(Process);
  210. //
  211. // Either of these may cause an access violation. The
  212. // exception handler will return access violation as
  213. // status code.
  214. //
  215. st = STATUS_SUCCESS;
  216. try {
  217. *(PQUOTA_LIMITS) ProcessInformation = QuotaLimits;
  218. if (ARGUMENT_PRESENT(ReturnLength) ) {
  219. *ReturnLength = sizeof(QUOTA_LIMITS);
  220. }
  221. } except (EXCEPTION_EXECUTE_HANDLER) {
  222. st = GetExceptionCode();
  223. }
  224. return st;
  225. }
  226. NTSTATUS
  227. PspQueryPooledQuotaLimits(
  228. IN HANDLE ProcessHandle,
  229. IN PROCESSINFOCLASS ProcessInformationClass,
  230. OUT PVOID ProcessInformation,
  231. IN ULONG ProcessInformationLength,
  232. OUT PULONG ReturnLength OPTIONAL,
  233. IN KPROCESSOR_MODE PreviousMode
  234. )
  235. {
  236. PEPROCESS Process;
  237. NTSTATUS st;
  238. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  239. POOLED_USAGE_AND_LIMITS UsageAndLimits;
  240. UNREFERENCED_PARAMETER (ProcessInformationClass);
  241. if ( ProcessInformationLength != (ULONG) sizeof(POOLED_USAGE_AND_LIMITS) ) {
  242. return STATUS_INFO_LENGTH_MISMATCH;
  243. }
  244. st = ObReferenceObjectByHandle(
  245. ProcessHandle,
  246. PROCESS_QUERY_INFORMATION,
  247. PsProcessType,
  248. PreviousMode,
  249. (PVOID *)&Process,
  250. NULL
  251. );
  252. if ( !NT_SUCCESS(st) ) {
  253. return st;
  254. }
  255. QuotaBlock = Process->QuotaBlock;
  256. UsageAndLimits.PagedPoolLimit = QuotaBlock->QuotaEntry[PsPagedPool].Limit;
  257. UsageAndLimits.NonPagedPoolLimit = QuotaBlock->QuotaEntry[PsNonPagedPool].Limit;
  258. UsageAndLimits.PagefileLimit = QuotaBlock->QuotaEntry[PsPageFile].Limit;
  259. UsageAndLimits.PagedPoolUsage = QuotaBlock->QuotaEntry[PsPagedPool].Usage;
  260. UsageAndLimits.NonPagedPoolUsage = QuotaBlock->QuotaEntry[PsNonPagedPool].Usage;
  261. UsageAndLimits.PagefileUsage = QuotaBlock->QuotaEntry[PsPageFile].Usage;
  262. UsageAndLimits.PeakPagedPoolUsage = QuotaBlock->QuotaEntry[PsPagedPool].Peak;
  263. UsageAndLimits.PeakNonPagedPoolUsage = QuotaBlock->QuotaEntry[PsNonPagedPool].Peak;
  264. UsageAndLimits.PeakPagefileUsage = QuotaBlock->QuotaEntry[PsPageFile].Peak;
  265. //
  266. // Since the quota charge and return are lock free we may see Peak and Limit out of step.
  267. // Usage <= Limit and Usage <= Peak
  268. // Since Limit is adjusted up and down it does not hold that Peak <= Limit.
  269. //
  270. #define PSMAX(a,b) ((a > b)?(a):(b))
  271. UsageAndLimits.PagedPoolLimit = PSMAX (UsageAndLimits.PagedPoolLimit, UsageAndLimits.PagedPoolUsage);
  272. UsageAndLimits.NonPagedPoolLimit = PSMAX (UsageAndLimits.NonPagedPoolLimit, UsageAndLimits.NonPagedPoolUsage);
  273. UsageAndLimits.PagefileLimit = PSMAX (UsageAndLimits.PagefileLimit, UsageAndLimits.PagefileUsage);
  274. UsageAndLimits.PeakPagedPoolUsage = PSMAX (UsageAndLimits.PeakPagedPoolUsage, UsageAndLimits.PagedPoolUsage);
  275. UsageAndLimits.PeakNonPagedPoolUsage = PSMAX (UsageAndLimits.PeakNonPagedPoolUsage, UsageAndLimits.NonPagedPoolUsage);
  276. UsageAndLimits.PeakPagefileUsage = PSMAX (UsageAndLimits.PeakPagefileUsage, UsageAndLimits.PagefileUsage);
  277. ObDereferenceObject(Process);
  278. //
  279. // Either of these may cause an access violation. The
  280. // exception handler will return access violation as
  281. // status code. No further cleanup needs to be done.
  282. //
  283. try {
  284. *(PPOOLED_USAGE_AND_LIMITS) ProcessInformation = UsageAndLimits;
  285. if (ARGUMENT_PRESENT(ReturnLength) ) {
  286. *ReturnLength = sizeof(POOLED_USAGE_AND_LIMITS);
  287. }
  288. } except (EXCEPTION_EXECUTE_HANDLER) {
  289. return GetExceptionCode ();
  290. }
  291. return STATUS_SUCCESS;
  292. }
  293. NTSTATUS
  294. PspSetPrimaryToken(
  295. IN HANDLE ProcessHandle OPTIONAL,
  296. IN PEPROCESS ProcessPointer OPTIONAL,
  297. IN HANDLE TokenHandle OPTIONAL,
  298. IN PACCESS_TOKEN TokenPointer OPTIONAL,
  299. IN BOOLEAN PrivilegeChecked
  300. )
  301. /*++
  302. Sets the primary token for a process.
  303. The token and process supplied can be either by
  304. handle or by pointer.
  305. --*/
  306. {
  307. NTSTATUS Status;
  308. BOOLEAN HasPrivilege;
  309. BOOLEAN IsChildToken;
  310. PEPROCESS Process;
  311. KPROCESSOR_MODE PreviousMode;
  312. //
  313. // Check to see if the supplied token is a child of the caller's
  314. // token. If so, we don't need to do the privilege check.
  315. //
  316. PreviousMode = KeGetPreviousMode ();
  317. if (TokenPointer == NULL) {
  318. //
  319. // Reference the specified token, and make sure it can be assigned
  320. // as a primary token.
  321. //
  322. Status = ObReferenceObjectByHandle (TokenHandle,
  323. TOKEN_ASSIGN_PRIMARY,
  324. SeTokenObjectType,
  325. PreviousMode,
  326. &TokenPointer,
  327. NULL);
  328. if (!NT_SUCCESS (Status)) {
  329. return Status;
  330. }
  331. }
  332. //
  333. // If the privilege check has already been done (when the token was
  334. // assign to a job for example). We don't want to do it here.
  335. //
  336. if (!PrivilegeChecked) {
  337. Status = SeIsChildTokenByPointer (TokenPointer,
  338. &IsChildToken);
  339. if (!NT_SUCCESS (Status)) {
  340. if (TokenHandle != NULL) {
  341. ObDereferenceObject (TokenPointer);
  342. }
  343. return Status;
  344. }
  345. if (!IsChildToken) {
  346. //
  347. // SeCheckPrivilegedObject will perform auditing as appropriate
  348. //
  349. HasPrivilege = SeCheckPrivilegedObject (SeAssignPrimaryTokenPrivilege,
  350. ProcessHandle,
  351. PROCESS_SET_INFORMATION,
  352. PreviousMode);
  353. if (!HasPrivilege) {
  354. if (TokenHandle != NULL) {
  355. ObDereferenceObject (TokenPointer);
  356. }
  357. return STATUS_PRIVILEGE_NOT_HELD;
  358. }
  359. }
  360. }
  361. if (ProcessPointer == NULL) {
  362. Status = ObReferenceObjectByHandle (ProcessHandle,
  363. PROCESS_SET_INFORMATION,
  364. PsProcessType,
  365. PreviousMode,
  366. &Process,
  367. NULL);
  368. if (!NT_SUCCESS (Status)) {
  369. if (TokenHandle != NULL) {
  370. ObDereferenceObject (TokenPointer);
  371. }
  372. return Status;
  373. }
  374. } else {
  375. Process = ProcessPointer;
  376. }
  377. //
  378. // Check for proper access to the token, and assign the primary
  379. // token for the process.
  380. //
  381. Status = PspAssignPrimaryToken (Process, NULL, TokenPointer);
  382. //
  383. // Recompute the process's access to itself for use
  384. // with the CurrentProcess() pseudo handle.
  385. //
  386. if (NT_SUCCESS (Status)) {
  387. NTSTATUS accesst;
  388. BOOLEAN AccessCheck;
  389. BOOLEAN MemoryAllocated;
  390. PSECURITY_DESCRIPTOR SecurityDescriptor;
  391. SECURITY_SUBJECT_CONTEXT SubjectContext;
  392. Status = ObGetObjectSecurity (Process,
  393. &SecurityDescriptor,
  394. &MemoryAllocated);
  395. if (NT_SUCCESS (Status)) {
  396. SubjectContext.ProcessAuditId = Process;
  397. SubjectContext.PrimaryToken = PsReferencePrimaryToken (Process);
  398. SubjectContext.ClientToken = NULL;
  399. AccessCheck = SeAccessCheck (SecurityDescriptor,
  400. &SubjectContext,
  401. FALSE,
  402. MAXIMUM_ALLOWED,
  403. 0,
  404. NULL,
  405. &PsProcessType->TypeInfo.GenericMapping,
  406. PreviousMode,
  407. &Process->GrantedAccess,
  408. &accesst);
  409. PsDereferencePrimaryTokenEx(Process, SubjectContext.PrimaryToken);
  410. ObReleaseObjectSecurity (SecurityDescriptor,
  411. MemoryAllocated);
  412. if (!AccessCheck) {
  413. Process->GrantedAccess = 0;
  414. }
  415. //
  416. // To keep consistency with process creation, grant these
  417. // bits otherwise CreateProcessAsUser messes up really badly for
  418. // restricted tokens and we end up with a process that has no
  419. // access to itself when new token is set on the suspended
  420. // process.
  421. //
  422. Process->GrantedAccess |= (PROCESS_VM_OPERATION | PROCESS_VM_READ |
  423. PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION |
  424. PROCESS_TERMINATE | PROCESS_CREATE_THREAD |
  425. PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS |
  426. PROCESS_SET_INFORMATION);
  427. }
  428. //
  429. // Since the process token is being set,
  430. // Set the device map for process to NULL.
  431. // During the next reference to the process' device map,
  432. // the object manager will set the device map for the process
  433. //
  434. if (ObIsLUIDDeviceMapsEnabled() != 0) {
  435. ObDereferenceDeviceMap( Process );
  436. }
  437. }
  438. if (ProcessHandle != NULL) {
  439. ObDereferenceObject (Process);
  440. }
  441. if (TokenHandle != NULL) {
  442. ObDereferenceObject (TokenPointer);
  443. }
  444. return Status;
  445. }
  446. NTSTATUS
  447. NtQueryInformationProcess(
  448. IN HANDLE ProcessHandle,
  449. IN PROCESSINFOCLASS ProcessInformationClass,
  450. OUT PVOID ProcessInformation,
  451. IN ULONG ProcessInformationLength,
  452. OUT PULONG ReturnLength OPTIONAL
  453. )
  454. {
  455. PEPROCESS Process;
  456. KPROCESSOR_MODE PreviousMode;
  457. NTSTATUS st;
  458. PROCESS_BASIC_INFORMATION BasicInfo;
  459. VM_COUNTERS_EX VmCounters;
  460. IO_COUNTERS IoCounters;
  461. KERNEL_USER_TIMES SysUserTime;
  462. HANDLE DebugPort;
  463. ULONG HandleCount;
  464. ULONG DefaultHardErrorMode;
  465. ULONG DisableBoost;
  466. ULONG BreakOnTerminationEnabled;
  467. PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo;
  468. PROCESS_SESSION_INFORMATION SessionInfo;
  469. PROCESS_PRIORITY_CLASS PriorityClass;
  470. ULONG_PTR Wow64Info;
  471. ULONG Flags;
  472. PUNICODE_STRING pTempNameInfo;
  473. PAGED_CODE();
  474. //
  475. // Get previous processor mode and probe output argument if necessary.
  476. //
  477. PreviousMode = KeGetPreviousMode();
  478. if (PreviousMode != KernelMode) {
  479. try {
  480. ProbeForWrite(ProcessInformation,
  481. ProcessInformationLength,
  482. sizeof(ULONG));
  483. if (ARGUMENT_PRESENT(ReturnLength)) {
  484. ProbeForWriteUlong(ReturnLength);
  485. }
  486. } except(EXCEPTION_EXECUTE_HANDLER) {
  487. return GetExceptionCode();
  488. }
  489. }
  490. //
  491. // Check argument validity.
  492. //
  493. switch ( ProcessInformationClass ) {
  494. case ProcessImageFileName:
  495. {
  496. ULONG LengthNeeded = 0;
  497. st = ObReferenceObjectByHandle(
  498. ProcessHandle,
  499. PROCESS_QUERY_INFORMATION,
  500. PsProcessType,
  501. PreviousMode,
  502. (PVOID *)&Process,
  503. NULL
  504. );
  505. if (!NT_SUCCESS(st)) {
  506. return st;
  507. }
  508. //
  509. // SeLocateProcessImageName will allocate space for a UNICODE_STRING and point pTempNameInfo
  510. // at that string. This memory will be freed later in the routine.
  511. //
  512. st = SeLocateProcessImageName(Process, &pTempNameInfo);
  513. if (!NT_SUCCESS(st)) {
  514. ObDereferenceObject(Process);
  515. return st;
  516. }
  517. LengthNeeded = sizeof(UNICODE_STRING) + pTempNameInfo->MaximumLength;
  518. //
  519. // Either of these may cause an access violation. The
  520. // exception handler will return access violation as
  521. // status code. No further cleanup needs to be done.
  522. //
  523. try {
  524. if (ARGUMENT_PRESENT(ReturnLength) ) {
  525. *ReturnLength = LengthNeeded;
  526. }
  527. if (ProcessInformationLength >= LengthNeeded) {
  528. RtlCopyMemory(
  529. ProcessInformation,
  530. pTempNameInfo,
  531. sizeof(UNICODE_STRING) + pTempNameInfo->MaximumLength
  532. );
  533. ((PUNICODE_STRING) ProcessInformation)->Buffer = (PWSTR)((PUCHAR) ProcessInformation + sizeof(UNICODE_STRING));
  534. } else {
  535. st = STATUS_INFO_LENGTH_MISMATCH;
  536. }
  537. } except(EXCEPTION_EXECUTE_HANDLER) {
  538. st = GetExceptionCode ();
  539. }
  540. ObDereferenceObject(Process);
  541. ExFreePool( pTempNameInfo );
  542. return st;
  543. }
  544. case ProcessWorkingSetWatch:
  545. return PspQueryWorkingSetWatch(
  546. ProcessHandle,
  547. ProcessInformationClass,
  548. ProcessInformation,
  549. ProcessInformationLength,
  550. ReturnLength,
  551. PreviousMode
  552. );
  553. case ProcessBasicInformation:
  554. if ( ProcessInformationLength != (ULONG) sizeof(PROCESS_BASIC_INFORMATION) ) {
  555. return STATUS_INFO_LENGTH_MISMATCH;
  556. }
  557. st = ObReferenceObjectByHandle(
  558. ProcessHandle,
  559. PROCESS_QUERY_INFORMATION,
  560. PsProcessType,
  561. PreviousMode,
  562. (PVOID *)&Process,
  563. NULL
  564. );
  565. if ( !NT_SUCCESS(st) ) {
  566. return st;
  567. }
  568. BasicInfo.ExitStatus = Process->ExitStatus;
  569. BasicInfo.PebBaseAddress = Process->Peb;
  570. BasicInfo.AffinityMask = Process->Pcb.Affinity;
  571. BasicInfo.BasePriority = Process->Pcb.BasePriority;
  572. BasicInfo.UniqueProcessId = (ULONG_PTR)Process->UniqueProcessId;
  573. BasicInfo.InheritedFromUniqueProcessId = (ULONG_PTR)Process->InheritedFromUniqueProcessId;
  574. ObDereferenceObject(Process);
  575. //
  576. // Either of these may cause an access violation. The
  577. // exception handler will return access violation as
  578. // status code. No further cleanup needs to be done.
  579. //
  580. try {
  581. *(PPROCESS_BASIC_INFORMATION) ProcessInformation = BasicInfo;
  582. if (ARGUMENT_PRESENT(ReturnLength) ) {
  583. *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
  584. }
  585. } except (EXCEPTION_EXECUTE_HANDLER) {
  586. return GetExceptionCode ();
  587. }
  588. return STATUS_SUCCESS;
  589. case ProcessDefaultHardErrorMode:
  590. if ( ProcessInformationLength != sizeof(ULONG) ) {
  591. return STATUS_INFO_LENGTH_MISMATCH;
  592. }
  593. st = ObReferenceObjectByHandle(
  594. ProcessHandle,
  595. PROCESS_QUERY_INFORMATION,
  596. PsProcessType,
  597. PreviousMode,
  598. (PVOID *)&Process,
  599. NULL
  600. );
  601. if ( !NT_SUCCESS(st) ) {
  602. return st;
  603. }
  604. DefaultHardErrorMode = Process->DefaultHardErrorProcessing;
  605. ObDereferenceObject(Process);
  606. try {
  607. *(PULONG) ProcessInformation = DefaultHardErrorMode;
  608. if (ARGUMENT_PRESENT(ReturnLength) ) {
  609. *ReturnLength = sizeof(ULONG);
  610. }
  611. } except (EXCEPTION_EXECUTE_HANDLER) {
  612. return GetExceptionCode ();
  613. }
  614. return STATUS_SUCCESS;
  615. case ProcessQuotaLimits:
  616. return PspQueryQuotaLimits(
  617. ProcessHandle,
  618. ProcessInformationClass,
  619. ProcessInformation,
  620. ProcessInformationLength,
  621. ReturnLength,
  622. PreviousMode
  623. );
  624. case ProcessPooledUsageAndLimits:
  625. return PspQueryPooledQuotaLimits(
  626. ProcessHandle,
  627. ProcessInformationClass,
  628. ProcessInformation,
  629. ProcessInformationLength,
  630. ReturnLength,
  631. PreviousMode
  632. );
  633. case ProcessIoCounters:
  634. if ( ProcessInformationLength != (ULONG) sizeof(IO_COUNTERS) ) {
  635. return STATUS_INFO_LENGTH_MISMATCH;
  636. }
  637. st = ObReferenceObjectByHandle(
  638. ProcessHandle,
  639. PROCESS_QUERY_INFORMATION,
  640. PsProcessType,
  641. PreviousMode,
  642. (PVOID *)&Process,
  643. NULL
  644. );
  645. if ( !NT_SUCCESS(st) ) {
  646. return st;
  647. }
  648. IoCounters.ReadOperationCount = Process->ReadOperationCount.QuadPart;
  649. IoCounters.WriteOperationCount = Process->WriteOperationCount.QuadPart;
  650. IoCounters.OtherOperationCount = Process->OtherOperationCount.QuadPart;
  651. IoCounters.ReadTransferCount = Process->ReadTransferCount.QuadPart;
  652. IoCounters.WriteTransferCount = Process->WriteTransferCount.QuadPart;
  653. IoCounters.OtherTransferCount = Process->OtherTransferCount.QuadPart;
  654. ObDereferenceObject(Process);
  655. //
  656. // Either of these may cause an access violation. The
  657. // exception handler will return access violation as
  658. // status code. No further cleanup needs to be done.
  659. //
  660. try {
  661. *(PIO_COUNTERS) ProcessInformation = IoCounters;
  662. if (ARGUMENT_PRESENT(ReturnLength) ) {
  663. *ReturnLength = sizeof(IO_COUNTERS);
  664. }
  665. } except (EXCEPTION_EXECUTE_HANDLER) {
  666. return GetExceptionCode ();
  667. }
  668. return STATUS_SUCCESS;
  669. case ProcessVmCounters:
  670. if (ProcessInformationLength != (ULONG) sizeof (VM_COUNTERS)
  671. && ProcessInformationLength != (ULONG) sizeof (VM_COUNTERS_EX)) {
  672. return STATUS_INFO_LENGTH_MISMATCH;
  673. }
  674. st = ObReferenceObjectByHandle(
  675. ProcessHandle,
  676. PROCESS_QUERY_INFORMATION,
  677. PsProcessType,
  678. PreviousMode,
  679. (PVOID *)&Process,
  680. NULL
  681. );
  682. if ( !NT_SUCCESS(st) ) {
  683. return st;
  684. }
  685. //
  686. // Note: At some point, we might have to grab the statistics
  687. // lock to reliably read this stuff
  688. //
  689. VmCounters.PeakVirtualSize = Process->PeakVirtualSize;
  690. VmCounters.VirtualSize = Process->VirtualSize;
  691. VmCounters.PageFaultCount = Process->Vm.PageFaultCount;
  692. VmCounters.PeakWorkingSetSize = ((SIZE_T) Process->Vm.PeakWorkingSetSize) << PAGE_SHIFT;
  693. VmCounters.WorkingSetSize = ((SIZE_T) Process->Vm.WorkingSetSize) << PAGE_SHIFT;
  694. VmCounters.QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool];
  695. VmCounters.QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool];
  696. VmCounters.QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool];
  697. VmCounters.QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool];
  698. VmCounters.PagefileUsage = ((SIZE_T) Process->QuotaUsage[PsPageFile]) << PAGE_SHIFT;
  699. VmCounters.PeakPagefileUsage = ((SIZE_T) Process->QuotaPeak[PsPageFile]) << PAGE_SHIFT;
  700. VmCounters.PrivateUsage = ((SIZE_T) Process->CommitCharge) << PAGE_SHIFT;
  701. ObDereferenceObject(Process);
  702. //
  703. // Either of these may cause an access violation. The
  704. // exception handler will return access violation as
  705. // status code. No further cleanup needs to be done.
  706. //
  707. try {
  708. RtlCopyMemory(ProcessInformation,
  709. &VmCounters,
  710. ProcessInformationLength);
  711. if (ARGUMENT_PRESENT (ReturnLength) ) {
  712. *ReturnLength = ProcessInformationLength;
  713. }
  714. } except (EXCEPTION_EXECUTE_HANDLER) {
  715. return GetExceptionCode ();
  716. }
  717. return STATUS_SUCCESS;
  718. case ProcessTimes:
  719. if ( ProcessInformationLength != (ULONG) sizeof(KERNEL_USER_TIMES) ) {
  720. return STATUS_INFO_LENGTH_MISMATCH;
  721. }
  722. st = ObReferenceObjectByHandle(
  723. ProcessHandle,
  724. PROCESS_QUERY_INFORMATION,
  725. PsProcessType,
  726. PreviousMode,
  727. (PVOID *)&Process,
  728. NULL
  729. );
  730. if ( !NT_SUCCESS(st) ) {
  731. return st;
  732. }
  733. //
  734. // Need some type of interlock on KiTimeLock
  735. //
  736. SysUserTime.KernelTime.QuadPart = UInt32x32To64(Process->Pcb.KernelTime,
  737. KeMaximumIncrement);
  738. SysUserTime.UserTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,
  739. KeMaximumIncrement);
  740. SysUserTime.CreateTime = Process->CreateTime;
  741. SysUserTime.ExitTime = Process->ExitTime;
  742. ObDereferenceObject(Process);
  743. //
  744. // Either of these may cause an access violation. The
  745. // exception handler will return access violation as
  746. // status code. No further cleanup needs to be done.
  747. //
  748. try {
  749. *(PKERNEL_USER_TIMES) ProcessInformation = SysUserTime;
  750. if (ARGUMENT_PRESENT(ReturnLength) ) {
  751. *ReturnLength = sizeof(KERNEL_USER_TIMES);
  752. }
  753. } except (EXCEPTION_EXECUTE_HANDLER) {
  754. return GetExceptionCode ();
  755. }
  756. return STATUS_SUCCESS;
  757. case ProcessDebugPort :
  758. //
  759. if ( ProcessInformationLength != (ULONG) sizeof(HANDLE) ) {
  760. return STATUS_INFO_LENGTH_MISMATCH;
  761. }
  762. st = ObReferenceObjectByHandle(
  763. ProcessHandle,
  764. PROCESS_QUERY_INFORMATION,
  765. PsProcessType,
  766. PreviousMode,
  767. (PVOID *)&Process,
  768. NULL
  769. );
  770. if ( !NT_SUCCESS(st) ) {
  771. return st;
  772. }
  773. if (Process->DebugPort == NULL) {
  774. DebugPort = NULL;
  775. } else {
  776. DebugPort = (HANDLE)-1;
  777. }
  778. ObDereferenceObject(Process);
  779. //
  780. // Either of these may cause an access violation. The
  781. // exception handler will return access violation as
  782. // status code. No further cleanup needs to be done.
  783. //
  784. try {
  785. *(PHANDLE) ProcessInformation = DebugPort;
  786. if (ARGUMENT_PRESENT(ReturnLength) ) {
  787. *ReturnLength = sizeof(HANDLE);
  788. }
  789. } except (EXCEPTION_EXECUTE_HANDLER) {
  790. return GetExceptionCode ();
  791. }
  792. return STATUS_SUCCESS;
  793. case ProcessDebugObjectHandle :
  794. //
  795. if (ProcessInformationLength != sizeof (HANDLE)) {
  796. return STATUS_INFO_LENGTH_MISMATCH;
  797. }
  798. st = ObReferenceObjectByHandle (ProcessHandle,
  799. PROCESS_QUERY_INFORMATION,
  800. PsProcessType,
  801. PreviousMode,
  802. &Process,
  803. NULL);
  804. if (!NT_SUCCESS (st)) {
  805. return st;
  806. }
  807. st = DbgkOpenProcessDebugPort (Process,
  808. PreviousMode,
  809. &DebugPort);
  810. if (!NT_SUCCESS (st)) {
  811. DebugPort = NULL;
  812. }
  813. ObDereferenceObject (Process);
  814. //
  815. // Either of these may cause an access violation. The
  816. // exception handler will return access violation as
  817. // status code. No further cleanup needs to be done.
  818. //
  819. try {
  820. *(PHANDLE) ProcessInformation = DebugPort;
  821. if (ARGUMENT_PRESENT(ReturnLength) ) {
  822. *ReturnLength = sizeof(HANDLE);
  823. }
  824. } except (EXCEPTION_EXECUTE_HANDLER) {
  825. return GetExceptionCode ();
  826. }
  827. return st;
  828. case ProcessDebugFlags :
  829. if (ProcessInformationLength != sizeof (ULONG)) {
  830. return STATUS_INFO_LENGTH_MISMATCH;
  831. }
  832. st = ObReferenceObjectByHandle (ProcessHandle,
  833. PROCESS_QUERY_INFORMATION,
  834. PsProcessType,
  835. PreviousMode,
  836. &Process,
  837. NULL);
  838. if (!NT_SUCCESS (st)) {
  839. return st;
  840. }
  841. try {
  842. *(PULONG) ProcessInformation = (Process->Flags&PS_PROCESS_FLAGS_NO_DEBUG_INHERIT)?0:PROCESS_DEBUG_INHERIT;
  843. if (ARGUMENT_PRESENT(ReturnLength) ) {
  844. *ReturnLength = sizeof(HANDLE);
  845. }
  846. } except (EXCEPTION_EXECUTE_HANDLER) {
  847. st = GetExceptionCode ();
  848. }
  849. ObDereferenceObject (Process);
  850. return st;
  851. case ProcessHandleCount :
  852. if ( ProcessInformationLength != (ULONG) sizeof(ULONG) ) {
  853. return STATUS_INFO_LENGTH_MISMATCH;
  854. }
  855. st = ObReferenceObjectByHandle(
  856. ProcessHandle,
  857. PROCESS_QUERY_INFORMATION,
  858. PsProcessType,
  859. PreviousMode,
  860. (PVOID *)&Process,
  861. NULL
  862. );
  863. if ( !NT_SUCCESS(st) ) {
  864. return st;
  865. }
  866. HandleCount = ObGetProcessHandleCount (Process);
  867. ObDereferenceObject(Process);
  868. //
  869. // Either of these may cause an access violation. The
  870. // exception handler will return access violation as
  871. // status code. No further cleanup needs to be done.
  872. //
  873. try {
  874. *(PULONG) ProcessInformation = HandleCount;
  875. if (ARGUMENT_PRESENT(ReturnLength) ) {
  876. *ReturnLength = sizeof(ULONG);
  877. }
  878. } except (EXCEPTION_EXECUTE_HANDLER) {
  879. return GetExceptionCode ();
  880. }
  881. return STATUS_SUCCESS;
  882. case ProcessLdtInformation :
  883. st = ObReferenceObjectByHandle(
  884. ProcessHandle,
  885. PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  886. PsProcessType,
  887. PreviousMode,
  888. (PVOID *)&Process,
  889. NULL
  890. );
  891. if ( !NT_SUCCESS(st) ) {
  892. return st;
  893. }
  894. st = PspQueryLdtInformation (Process,
  895. ProcessInformation,
  896. ProcessInformationLength,
  897. ReturnLength);
  898. ObDereferenceObject(Process);
  899. return st;
  900. case ProcessWx86Information :
  901. return STATUS_INVALID_INFO_CLASS;
  902. case ProcessPriorityBoost:
  903. if ( ProcessInformationLength != sizeof(ULONG) ) {
  904. return STATUS_INFO_LENGTH_MISMATCH;
  905. }
  906. st = ObReferenceObjectByHandle(
  907. ProcessHandle,
  908. PROCESS_QUERY_INFORMATION,
  909. PsProcessType,
  910. PreviousMode,
  911. (PVOID *)&Process,
  912. NULL
  913. );
  914. if ( !NT_SUCCESS(st) ) {
  915. return st;
  916. }
  917. DisableBoost = Process->Pcb.DisableBoost ? 1 : 0;
  918. ObDereferenceObject(Process);
  919. try {
  920. *(PULONG)ProcessInformation = DisableBoost;
  921. if (ARGUMENT_PRESENT(ReturnLength) ) {
  922. *ReturnLength = sizeof(ULONG);
  923. }
  924. } except (EXCEPTION_EXECUTE_HANDLER) {
  925. return GetExceptionCode();
  926. }
  927. return st;
  928. case ProcessDeviceMap:
  929. DeviceMapInfo = (PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation;
  930. if ( ProcessInformationLength < sizeof(DeviceMapInfo->Query) ) {
  931. return STATUS_INFO_LENGTH_MISMATCH;
  932. }
  933. if ( ProcessInformationLength == sizeof(PROCESS_DEVICEMAP_INFORMATION_EX) ) {
  934. try {
  935. Flags = ((PPROCESS_DEVICEMAP_INFORMATION_EX)DeviceMapInfo)->Flags;
  936. } except (EXCEPTION_EXECUTE_HANDLER) {
  937. return GetExceptionCode ();
  938. }
  939. if ( (Flags & ~(PROCESS_LUID_DOSDEVICES_ONLY)) ||
  940. (ObIsLUIDDeviceMapsEnabled() == 0) ) {
  941. return STATUS_INVALID_PARAMETER;
  942. }
  943. }
  944. else {
  945. if ( ProcessInformationLength == sizeof(DeviceMapInfo->Query) ) {
  946. Flags = 0;
  947. }
  948. else {
  949. return STATUS_INFO_LENGTH_MISMATCH;
  950. }
  951. }
  952. st = ObReferenceObjectByHandle(
  953. ProcessHandle,
  954. PROCESS_QUERY_INFORMATION,
  955. PsProcessType,
  956. PreviousMode,
  957. (PVOID *)&Process,
  958. NULL
  959. );
  960. if ( !NT_SUCCESS(st) ) {
  961. return st;
  962. }
  963. st = ObQueryDeviceMapInformation( Process, DeviceMapInfo, Flags );
  964. ObDereferenceObject(Process);
  965. return st;
  966. case ProcessSessionInformation :
  967. if ( ProcessInformationLength != (ULONG) sizeof(PROCESS_SESSION_INFORMATION) ) {
  968. return STATUS_INFO_LENGTH_MISMATCH;
  969. }
  970. st = ObReferenceObjectByHandle(
  971. ProcessHandle,
  972. PROCESS_QUERY_INFORMATION,
  973. PsProcessType,
  974. PreviousMode,
  975. (PVOID *)&Process,
  976. NULL
  977. );
  978. if ( !NT_SUCCESS(st) ) {
  979. return st;
  980. }
  981. SessionInfo.SessionId = MmGetSessionId (Process);
  982. ObDereferenceObject(Process);
  983. try {
  984. *(PPROCESS_SESSION_INFORMATION) ProcessInformation = SessionInfo;
  985. if (ARGUMENT_PRESENT(ReturnLength) ) {
  986. *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
  987. }
  988. } except (EXCEPTION_EXECUTE_HANDLER) {
  989. return GetExceptionCode ();
  990. }
  991. return STATUS_SUCCESS;
  992. case ProcessPriorityClass:
  993. if ( ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS) ) {
  994. return STATUS_INFO_LENGTH_MISMATCH;
  995. }
  996. st = ObReferenceObjectByHandle(
  997. ProcessHandle,
  998. PROCESS_QUERY_INFORMATION,
  999. PsProcessType,
  1000. PreviousMode,
  1001. (PVOID *)&Process,
  1002. NULL
  1003. );
  1004. if ( !NT_SUCCESS(st) ) {
  1005. return st;
  1006. }
  1007. PriorityClass.Foreground = FALSE;
  1008. PriorityClass.PriorityClass = Process->PriorityClass;
  1009. ObDereferenceObject(Process);
  1010. try {
  1011. *(PPROCESS_PRIORITY_CLASS) ProcessInformation = PriorityClass;
  1012. if (ARGUMENT_PRESENT(ReturnLength) ) {
  1013. *ReturnLength = sizeof(PROCESS_PRIORITY_CLASS);
  1014. }
  1015. } except (EXCEPTION_EXECUTE_HANDLER) {
  1016. return GetExceptionCode ();
  1017. }
  1018. return STATUS_SUCCESS;
  1019. case ProcessWow64Information:
  1020. if ( ProcessInformationLength != sizeof(ULONG_PTR) ) {
  1021. return STATUS_INFO_LENGTH_MISMATCH;
  1022. }
  1023. st = ObReferenceObjectByHandle(
  1024. ProcessHandle,
  1025. PROCESS_QUERY_INFORMATION,
  1026. PsProcessType,
  1027. PreviousMode,
  1028. (PVOID *)&Process,
  1029. NULL
  1030. );
  1031. if ( !NT_SUCCESS(st) ) {
  1032. return st;
  1033. }
  1034. Wow64Info = 0;
  1035. //
  1036. // Acquire process rundown protection as we are about to look at process structures torn down at
  1037. // process exit.
  1038. //
  1039. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  1040. PWOW64_PROCESS Wow64Process;
  1041. if ((Wow64Process = PS_GET_WOW64_PROCESS (Process)) != NULL) {
  1042. Wow64Info = (ULONG_PTR)(Wow64Process->Wow64);
  1043. }
  1044. ExReleaseRundownProtection (&Process->RundownProtect);
  1045. }
  1046. ObDereferenceObject(Process);
  1047. try {
  1048. *(PULONG_PTR)ProcessInformation = Wow64Info;
  1049. if (ARGUMENT_PRESENT(ReturnLength) ) {
  1050. *ReturnLength = sizeof(ULONG_PTR);
  1051. }
  1052. } except (EXCEPTION_EXECUTE_HANDLER) {
  1053. return GetExceptionCode ();
  1054. }
  1055. return( STATUS_SUCCESS );
  1056. case ProcessLUIDDeviceMapsEnabled:
  1057. if ( ProcessInformationLength != sizeof(ULONG) ) {
  1058. return STATUS_INFO_LENGTH_MISMATCH;
  1059. }
  1060. try {
  1061. *(PULONG)ProcessInformation = ObIsLUIDDeviceMapsEnabled();
  1062. if (ARGUMENT_PRESENT(ReturnLength) ) {
  1063. *ReturnLength = sizeof(ULONG);
  1064. }
  1065. } except (EXCEPTION_EXECUTE_HANDLER) {
  1066. return GetExceptionCode ();
  1067. }
  1068. return( STATUS_SUCCESS );
  1069. case ProcessBreakOnTermination:
  1070. if ( ProcessInformationLength != sizeof(ULONG) ) {
  1071. return STATUS_INFO_LENGTH_MISMATCH;
  1072. }
  1073. st = ObReferenceObjectByHandle(
  1074. ProcessHandle,
  1075. PROCESS_QUERY_INFORMATION,
  1076. PsProcessType,
  1077. PreviousMode,
  1078. (PVOID *)&Process,
  1079. NULL
  1080. );
  1081. if ( !NT_SUCCESS(st) ) {
  1082. return st;
  1083. }
  1084. if (Process->Flags
  1085. & PS_PROCESS_FLAGS_BREAK_ON_TERMINATION) {
  1086. BreakOnTerminationEnabled = 1;
  1087. } else {
  1088. BreakOnTerminationEnabled = 0;
  1089. }
  1090. ObDereferenceObject(Process);
  1091. try {
  1092. *(PULONG)ProcessInformation = BreakOnTerminationEnabled;
  1093. if (ARGUMENT_PRESENT(ReturnLength) ) {
  1094. *ReturnLength = sizeof(ULONG);
  1095. }
  1096. } except(EXCEPTION_EXECUTE_HANDLER) {
  1097. return GetExceptionCode ();
  1098. }
  1099. return STATUS_SUCCESS;
  1100. case ProcessHandleTracing: {
  1101. PPROCESS_HANDLE_TRACING_QUERY Pht;
  1102. PHANDLE_TABLE HandleTable;
  1103. PHANDLE_TRACE_DEBUG_INFO DebugInfo;
  1104. HANDLE_TRACE_DB_ENTRY Trace;
  1105. PPROCESS_HANDLE_TRACING_ENTRY NextTrace;
  1106. ULONG StacksLeft;
  1107. ULONG i, j;
  1108. if (ProcessInformationLength < FIELD_OFFSET (PROCESS_HANDLE_TRACING_QUERY,
  1109. HandleTrace)) {
  1110. return STATUS_INFO_LENGTH_MISMATCH;
  1111. }
  1112. Pht = (PPROCESS_HANDLE_TRACING_QUERY) ProcessInformation;
  1113. StacksLeft = (ProcessInformationLength - FIELD_OFFSET (PROCESS_HANDLE_TRACING_QUERY,
  1114. HandleTrace)) /
  1115. sizeof (Pht->HandleTrace[0]);
  1116. NextTrace = &Pht->HandleTrace[0];
  1117. st = ObReferenceObjectByHandle (ProcessHandle,
  1118. PROCESS_QUERY_INFORMATION,
  1119. PsProcessType,
  1120. PreviousMode,
  1121. &Process,
  1122. NULL);
  1123. if (!NT_SUCCESS (st)) {
  1124. return st;
  1125. }
  1126. HandleTable = ObReferenceProcessHandleTable (Process);
  1127. if (HandleTable != NULL) {
  1128. DebugInfo = HandleTable->DebugInfo;
  1129. if (DebugInfo != 0) {
  1130. try {
  1131. Pht->TotalTraces = 0;
  1132. j = DebugInfo->CurrentStackIndex % HANDLE_TRACE_DB_MAX_STACKS;
  1133. for (i = 0; i < HANDLE_TRACE_DB_MAX_STACKS; i++) {
  1134. RtlCopyMemory (&Trace, &DebugInfo->TraceDb[j], sizeof (Trace));
  1135. if ((Pht->Handle == Trace.Handle || Pht->Handle == 0) && Trace.Type != 0) {
  1136. Pht->TotalTraces++;
  1137. if (StacksLeft > 0) {
  1138. StacksLeft--;
  1139. NextTrace->Handle = Trace.Handle;
  1140. NextTrace->ClientId = Trace.ClientId;
  1141. NextTrace->Type = Trace.Type;
  1142. RtlCopyMemory (NextTrace->Stacks,
  1143. Trace.StackTrace,
  1144. min (sizeof (NextTrace->Stacks),
  1145. sizeof (Trace.StackTrace)));
  1146. NextTrace++;
  1147. } else {
  1148. st = STATUS_INFO_LENGTH_MISMATCH;
  1149. }
  1150. }
  1151. if (j == 0) {
  1152. j = HANDLE_TRACE_DB_MAX_STACKS - 1;
  1153. } else {
  1154. j--;
  1155. }
  1156. }
  1157. if (ARGUMENT_PRESENT (ReturnLength)) {
  1158. *ReturnLength = (ULONG) ((PUCHAR) NextTrace - (PUCHAR) Pht);
  1159. }
  1160. } except (EXCEPTION_EXECUTE_HANDLER) {
  1161. st = GetExceptionCode ();
  1162. }
  1163. } else {
  1164. st = STATUS_INVALID_PARAMETER;
  1165. }
  1166. ObDereferenceProcessHandleTable (Process);
  1167. } else {
  1168. st = STATUS_PROCESS_IS_TERMINATING;
  1169. }
  1170. ObDereferenceObject(Process);
  1171. return st;
  1172. }
  1173. default:
  1174. return STATUS_INVALID_INFO_CLASS;
  1175. }
  1176. }
  1177. NTSTATUS
  1178. NtQueryPortInformationProcess(
  1179. VOID
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. This function tests whether a debug port or an exception port is attached
  1184. to the current process and returns a corresponding value. This function is
  1185. used to bypass raising an exception through the system when no associated
  1186. ports are present.
  1187. N.B. This improves performance considerably with respect to raising
  1188. software exceptions in user mode on AMD64 and IA64 systems.
  1189. Arguments:
  1190. None.
  1191. Return Value:
  1192. A success value of TRUE is returned if either a debug or exception port
  1193. is associated with the current process. Otherwise, a success value of
  1194. FALSE is returned.
  1195. --*/
  1196. {
  1197. PEPROCESS Process;
  1198. PETHREAD Thread;
  1199. //
  1200. // If the process has a debug port and it is not being hidden from the
  1201. // debugger, then return a success status of TRUE. Otherwise, is the
  1202. // process has an exception port, then return a success status of TRUE.
  1203. // Otherwise, return a success status of FALSE.
  1204. //
  1205. Thread = PsGetCurrentThread();
  1206. Process = PsGetCurrentProcessByThread(Thread);
  1207. if ((Process->DebugPort != NULL) &&
  1208. ((Thread->CrossThreadFlags & PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) == 0)) {
  1209. return TRUE;
  1210. } else if (Process->ExceptionPort != NULL) {
  1211. return TRUE;
  1212. } else {
  1213. return FALSE;
  1214. }
  1215. }
  1216. NTSTATUS
  1217. PspSetQuotaLimits(
  1218. IN HANDLE ProcessHandle,
  1219. IN PROCESSINFOCLASS ProcessInformationClass,
  1220. IN PVOID ProcessInformation,
  1221. IN ULONG ProcessInformationLength,
  1222. IN KPROCESSOR_MODE PreviousMode
  1223. )
  1224. {
  1225. PEPROCESS Process;
  1226. PETHREAD CurrentThread;
  1227. QUOTA_LIMITS RequestedLimits;
  1228. PEPROCESS_QUOTA_BLOCK NewQuotaBlock;
  1229. NTSTATUS st, ReturnStatus;
  1230. BOOLEAN OkToIncrease;
  1231. PEJOB Job;
  1232. KAPC_STATE ApcState;
  1233. UNREFERENCED_PARAMETER (ProcessInformationClass);
  1234. if ( ProcessInformationLength != sizeof(QUOTA_LIMITS) ) {
  1235. return STATUS_INFO_LENGTH_MISMATCH;
  1236. }
  1237. try {
  1238. RequestedLimits = *(PQUOTA_LIMITS) ProcessInformation;
  1239. } except (EXCEPTION_EXECUTE_HANDLER) {
  1240. return GetExceptionCode ();
  1241. }
  1242. st = ObReferenceObjectByHandle(
  1243. ProcessHandle,
  1244. PROCESS_SET_QUOTA,
  1245. PsProcessType,
  1246. PreviousMode,
  1247. (PVOID *)&Process,
  1248. NULL
  1249. );
  1250. if ( !NT_SUCCESS(st) ) {
  1251. return st;
  1252. }
  1253. CurrentThread = PsGetCurrentThread ();
  1254. //
  1255. // Now we are ready to set the quota limits for the process
  1256. //
  1257. // If the process already has a quota block, then all we allow
  1258. // is working set changes.
  1259. //
  1260. // If the process has no quota block, all that can be done is a
  1261. // quota set operation. The quotas must be high enough that the
  1262. // current usage can be charged without causing a quota overflow.
  1263. //
  1264. // If a quota field is zero, we pick the value.
  1265. //
  1266. // Setting quotas requires the SeIncreaseQuotaPrivilege (except for
  1267. // working set size since this is only advisory).
  1268. //
  1269. ReturnStatus = STATUS_SUCCESS;
  1270. if (Process->QuotaBlock == &PspDefaultQuotaBlock) {
  1271. if (RequestedLimits.MinimumWorkingSetSize &&
  1272. RequestedLimits.MaximumWorkingSetSize) {
  1273. if (RequestedLimits.MinimumWorkingSetSize != (SIZE_T)-1 &&
  1274. RequestedLimits.MaximumWorkingSetSize != (SIZE_T)-1) {
  1275. Job = Process->Job;
  1276. if (Job != NULL) {
  1277. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  1278. ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
  1279. if (Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET) {
  1280. RequestedLimits.MinimumWorkingSetSize = Job->MinimumWorkingSetSize;
  1281. RequestedLimits.MaximumWorkingSetSize = Job->MaximumWorkingSetSize;
  1282. }
  1283. ExReleaseResourceLite (&Job->JobLock);
  1284. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  1285. }
  1286. }
  1287. if (SeSinglePrivilegeCheck (SeIncreaseBasePriorityPrivilege,
  1288. PreviousMode)) {
  1289. OkToIncrease = TRUE;
  1290. } else {
  1291. OkToIncrease = FALSE;
  1292. }
  1293. KeStackAttachProcess (&Process->Pcb, &ApcState);
  1294. ReturnStatus = MmAdjustWorkingSetSize (
  1295. RequestedLimits.MinimumWorkingSetSize,
  1296. RequestedLimits.MaximumWorkingSetSize,
  1297. FALSE,
  1298. OkToIncrease);
  1299. KeUnstackDetachProcess (&ApcState);
  1300. } else {
  1301. //
  1302. // You must have a privilege to assign quotas
  1303. //
  1304. if (!SeSinglePrivilegeCheck (SeIncreaseQuotaPrivilege, PreviousMode)) {
  1305. ObDereferenceObject (Process);
  1306. return STATUS_PRIVILEGE_NOT_HELD;
  1307. }
  1308. NewQuotaBlock = ExAllocatePoolWithTag (NonPagedPool, sizeof(*NewQuotaBlock), 'bQsP');
  1309. if (NewQuotaBlock == NULL) {
  1310. ObDereferenceObject (Process);
  1311. return STATUS_NO_MEMORY;
  1312. }
  1313. RtlZeroMemory (NewQuotaBlock, sizeof (*NewQuotaBlock));
  1314. //
  1315. // Initialize the quota block
  1316. //
  1317. NewQuotaBlock->ReferenceCount = 1;
  1318. NewQuotaBlock->ProcessCount = 1;
  1319. NewQuotaBlock->QuotaEntry[PsNonPagedPool].Peak = Process->QuotaPeak[PsNonPagedPool];
  1320. NewQuotaBlock->QuotaEntry[PsPagedPool].Peak = Process->QuotaPeak[PsPagedPool];
  1321. NewQuotaBlock->QuotaEntry[PsPageFile].Peak = Process->QuotaPeak[PsPageFile];
  1322. //
  1323. // Now compute limits
  1324. //
  1325. //
  1326. // Get the defaults that the system would pick.
  1327. //
  1328. NewQuotaBlock->QuotaEntry[PsPagedPool].Limit = PspDefaultPagedLimit;
  1329. NewQuotaBlock->QuotaEntry[PsNonPagedPool].Limit = PspDefaultNonPagedLimit;
  1330. NewQuotaBlock->QuotaEntry[PsPageFile].Limit = PspDefaultPagefileLimit;
  1331. // Everything is set. Now double check to quota block field
  1332. // If we still have no quota block then assign and succeed.
  1333. // Otherwise punt.
  1334. //
  1335. if (InterlockedCompareExchangePointer (&Process->QuotaBlock,
  1336. NewQuotaBlock,
  1337. &PspDefaultQuotaBlock) != &PspDefaultQuotaBlock) {
  1338. ExFreePool (NewQuotaBlock);
  1339. } else {
  1340. PspInsertQuotaBlock (NewQuotaBlock);
  1341. }
  1342. ReturnStatus = STATUS_SUCCESS;
  1343. }
  1344. } else {
  1345. //
  1346. // Only allow a working set size change
  1347. //
  1348. if (RequestedLimits.MinimumWorkingSetSize &&
  1349. RequestedLimits.MaximumWorkingSetSize) {
  1350. if (RequestedLimits.MinimumWorkingSetSize != (SIZE_T)-1 &&
  1351. RequestedLimits.MaximumWorkingSetSize != (SIZE_T)-1) {
  1352. Job = Process->Job;
  1353. if (Job != NULL) {
  1354. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  1355. ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
  1356. if (Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET) {
  1357. RequestedLimits.MinimumWorkingSetSize = Job->MinimumWorkingSetSize;
  1358. RequestedLimits.MaximumWorkingSetSize = Job->MaximumWorkingSetSize;
  1359. }
  1360. ExReleaseResourceLite (&Job->JobLock);
  1361. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  1362. }
  1363. }
  1364. if (SeSinglePrivilegeCheck (SeIncreaseBasePriorityPrivilege,
  1365. PreviousMode)) {
  1366. OkToIncrease = TRUE;
  1367. } else {
  1368. OkToIncrease = FALSE;
  1369. }
  1370. KeStackAttachProcess (&Process->Pcb, &ApcState);
  1371. ReturnStatus = MmAdjustWorkingSetSize (
  1372. RequestedLimits.MinimumWorkingSetSize,
  1373. RequestedLimits.MaximumWorkingSetSize,
  1374. FALSE,
  1375. OkToIncrease
  1376. );
  1377. KeUnstackDetachProcess (&ApcState);
  1378. }
  1379. }
  1380. ObDereferenceObject(Process);
  1381. return ReturnStatus;
  1382. }
  1383. NTSTATUS
  1384. NtSetInformationProcess(
  1385. IN HANDLE ProcessHandle,
  1386. IN PROCESSINFOCLASS ProcessInformationClass,
  1387. IN PVOID ProcessInformation,
  1388. IN ULONG ProcessInformationLength
  1389. )
  1390. /*++
  1391. Routine Description:
  1392. This function sets the state of a process object.
  1393. Arguments:
  1394. ProcessHandle - Supplies a handle to a process object.
  1395. ProcessInformationClass - Supplies the class of information being
  1396. set.
  1397. ProcessInformation - Supplies a pointer to a record that contains the
  1398. information to set.
  1399. ProcessInformationLength - Supplies the length of the record that contains
  1400. the information to set.
  1401. Return Value:
  1402. TBS
  1403. --*/
  1404. {
  1405. PEPROCESS Process;
  1406. PETHREAD Thread;
  1407. PETHREAD CurrentThread;
  1408. KPROCESSOR_MODE PreviousMode;
  1409. NTSTATUS st;
  1410. KPRIORITY BasePriority;
  1411. ULONG BoostValue;
  1412. ULONG DefaultHardErrorMode;
  1413. PVOID ExceptionPort;
  1414. BOOLEAN EnableAlignmentFaultFixup;
  1415. HANDLE ExceptionPortHandle;
  1416. ULONG ProbeAlignment;
  1417. HANDLE PrimaryTokenHandle;
  1418. BOOLEAN HasPrivilege = FALSE;
  1419. UCHAR MemoryPriority;
  1420. PROCESS_PRIORITY_CLASS LocalPriorityClass;
  1421. PROCESS_FOREGROUND_BACKGROUND LocalForeground;
  1422. KAFFINITY Affinity, AffinityWithMasks;
  1423. ULONG DisableBoost;
  1424. BOOLEAN bDisableBoost;
  1425. PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo;
  1426. HANDLE DirectoryHandle;
  1427. PROCESS_SESSION_INFORMATION SessionInfo;
  1428. ULONG EnableBreakOnTermination;
  1429. PEJOB Job;
  1430. PAGED_CODE();
  1431. //
  1432. // Get previous processor mode and probe input argument if necessary.
  1433. //
  1434. CurrentThread = PsGetCurrentThread ();
  1435. PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  1436. if (PreviousMode != KernelMode) {
  1437. if (ProcessInformationClass == ProcessBasePriority) {
  1438. ProbeAlignment = sizeof(KPRIORITY);
  1439. } else if (ProcessInformationClass == ProcessEnableAlignmentFaultFixup) {
  1440. ProbeAlignment = sizeof(BOOLEAN);
  1441. } else if (ProcessInformationClass == ProcessForegroundInformation) {
  1442. ProbeAlignment = sizeof(PROCESS_FOREGROUND_BACKGROUND);
  1443. } else if (ProcessInformationClass == ProcessPriorityClass) {
  1444. ProbeAlignment = sizeof(BOOLEAN);
  1445. } else if (ProcessInformationClass == ProcessAffinityMask) {
  1446. ProbeAlignment = sizeof (ULONG_PTR);
  1447. } else {
  1448. ProbeAlignment = sizeof(ULONG);
  1449. }
  1450. try {
  1451. ProbeForRead(
  1452. ProcessInformation,
  1453. ProcessInformationLength,
  1454. ProbeAlignment
  1455. );
  1456. } except (EXCEPTION_EXECUTE_HANDLER) {
  1457. return GetExceptionCode();
  1458. }
  1459. }
  1460. //
  1461. // Check argument validity.
  1462. //
  1463. switch ( ProcessInformationClass ) {
  1464. case ProcessWorkingSetWatch: {
  1465. PPAGEFAULT_HISTORY WorkingSetCatcher;
  1466. st = ObReferenceObjectByHandle(
  1467. ProcessHandle,
  1468. PROCESS_SET_INFORMATION,
  1469. PsProcessType,
  1470. PreviousMode,
  1471. (PVOID *)&Process,
  1472. NULL
  1473. );
  1474. if ( !NT_SUCCESS(st) ) {
  1475. return st;
  1476. }
  1477. st = PsChargeProcessNonPagedPoolQuota (Process, WS_CATCH_SIZE);
  1478. if (NT_SUCCESS(st)) {
  1479. WorkingSetCatcher = ExAllocatePoolWithTag (NonPagedPool, WS_CATCH_SIZE, 'sWsP');
  1480. if (!WorkingSetCatcher) {
  1481. st = STATUS_NO_MEMORY;
  1482. } else {
  1483. PsWatchEnabled = TRUE;
  1484. WorkingSetCatcher->CurrentIndex = 0;
  1485. WorkingSetCatcher->MaxIndex = MAX_WS_CATCH_INDEX;
  1486. KeInitializeSpinLock (&WorkingSetCatcher->SpinLock);
  1487. //
  1488. // This only ever goes on the process and isn't removed till process object deletion.
  1489. // We just need to protect against multiple callers here.
  1490. //
  1491. if (InterlockedCompareExchangePointer (&Process->WorkingSetWatch,
  1492. WorkingSetCatcher, NULL) == NULL) {
  1493. st = STATUS_SUCCESS;
  1494. } else {
  1495. ExFreePool (WorkingSetCatcher);
  1496. st = STATUS_PORT_ALREADY_SET;
  1497. }
  1498. }
  1499. if (!NT_SUCCESS (st)) {
  1500. PsReturnProcessNonPagedPoolQuota (Process, WS_CATCH_SIZE);
  1501. }
  1502. }
  1503. ObDereferenceObject(Process);
  1504. return st;
  1505. }
  1506. case ProcessBasePriority: {
  1507. //
  1508. // THIS ITEM CODE IS OBSOLETE !
  1509. //
  1510. if ( ProcessInformationLength != sizeof(KPRIORITY) ) {
  1511. return STATUS_INFO_LENGTH_MISMATCH;
  1512. }
  1513. try {
  1514. BasePriority = *(KPRIORITY *)ProcessInformation;
  1515. } except (EXCEPTION_EXECUTE_HANDLER) {
  1516. return GetExceptionCode();
  1517. }
  1518. if (BasePriority & 0x80000000) {
  1519. MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
  1520. BasePriority &= ~0x80000000;
  1521. } else {
  1522. MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
  1523. }
  1524. if ( BasePriority > HIGH_PRIORITY ||
  1525. BasePriority <= LOW_PRIORITY ) {
  1526. return STATUS_INVALID_PARAMETER;
  1527. }
  1528. st = ObReferenceObjectByHandle(
  1529. ProcessHandle,
  1530. PROCESS_SET_INFORMATION,
  1531. PsProcessType,
  1532. PreviousMode,
  1533. (PVOID *)&Process,
  1534. NULL
  1535. );
  1536. if (!NT_SUCCESS (st)) {
  1537. return st;
  1538. }
  1539. if ( BasePriority > Process->Pcb.BasePriority ) {
  1540. //
  1541. // Increasing the base priority of a process is a
  1542. // privileged operation. Check for the privilege
  1543. // here.
  1544. //
  1545. HasPrivilege = SeCheckPrivilegedObject(
  1546. SeIncreaseBasePriorityPrivilege,
  1547. ProcessHandle,
  1548. PROCESS_SET_INFORMATION,
  1549. PreviousMode
  1550. );
  1551. if (!HasPrivilege) {
  1552. ObDereferenceObject(Process);
  1553. return STATUS_PRIVILEGE_NOT_HELD;
  1554. }
  1555. }
  1556. KeSetPriorityProcess (&Process->Pcb,BasePriority);
  1557. MmSetMemoryPriorityProcess (Process, MemoryPriority);
  1558. ObDereferenceObject (Process);
  1559. return STATUS_SUCCESS;
  1560. }
  1561. case ProcessPriorityClass: {
  1562. if ( ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS) ) {
  1563. return STATUS_INFO_LENGTH_MISMATCH;
  1564. }
  1565. try {
  1566. LocalPriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
  1567. } except(EXCEPTION_EXECUTE_HANDLER) {
  1568. return GetExceptionCode();
  1569. }
  1570. if (LocalPriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL) {
  1571. return STATUS_INVALID_PARAMETER;
  1572. }
  1573. st = ObReferenceObjectByHandle(
  1574. ProcessHandle,
  1575. PROCESS_SET_INFORMATION,
  1576. PsProcessType,
  1577. PreviousMode,
  1578. (PVOID *)&Process,
  1579. NULL
  1580. );
  1581. if ( !NT_SUCCESS(st) ) {
  1582. return st;
  1583. }
  1584. if (LocalPriorityClass.PriorityClass != Process->PriorityClass &&
  1585. LocalPriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME) {
  1586. //
  1587. // Increasing the base priority of a process is a
  1588. // privileged operation. Check for the privilege
  1589. // here.
  1590. //
  1591. HasPrivilege = SeCheckPrivilegedObject (SeIncreaseBasePriorityPrivilege,
  1592. ProcessHandle,
  1593. PROCESS_SET_INFORMATION,
  1594. PreviousMode);
  1595. if (!HasPrivilege) {
  1596. ObDereferenceObject(Process);
  1597. return STATUS_PRIVILEGE_NOT_HELD;
  1598. }
  1599. }
  1600. //
  1601. // If the process has a job object, override whatever the process
  1602. // is calling with with the value from the job object
  1603. //
  1604. Job = Process->Job;
  1605. if (Job != NULL) {
  1606. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  1607. ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
  1608. if (Job->LimitFlags & JOB_OBJECT_LIMIT_PRIORITY_CLASS) {
  1609. LocalPriorityClass.PriorityClass = Job->PriorityClass;
  1610. }
  1611. ExReleaseResourceLite (&Job->JobLock);
  1612. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  1613. }
  1614. Process->PriorityClass = LocalPriorityClass.PriorityClass;
  1615. PsSetProcessPriorityByClass(Process, LocalPriorityClass.Foreground ?
  1616. PsProcessPriorityForeground : PsProcessPriorityBackground);
  1617. ObDereferenceObject(Process);
  1618. return STATUS_SUCCESS;
  1619. }
  1620. case ProcessForegroundInformation:
  1621. {
  1622. if ( ProcessInformationLength != sizeof(PROCESS_FOREGROUND_BACKGROUND) ) {
  1623. return STATUS_INFO_LENGTH_MISMATCH;
  1624. }
  1625. try {
  1626. LocalForeground = *(PPROCESS_FOREGROUND_BACKGROUND)ProcessInformation;
  1627. } except (EXCEPTION_EXECUTE_HANDLER) {
  1628. return GetExceptionCode();
  1629. }
  1630. st = ObReferenceObjectByHandle(
  1631. ProcessHandle,
  1632. PROCESS_SET_INFORMATION,
  1633. PsProcessType,
  1634. PreviousMode,
  1635. (PVOID *)&Process,
  1636. NULL
  1637. );
  1638. if ( !NT_SUCCESS(st) ) {
  1639. return st;
  1640. }
  1641. PsSetProcessPriorityByClass(Process, LocalForeground.Foreground ?
  1642. PsProcessPriorityForeground : PsProcessPriorityBackground);
  1643. ObDereferenceObject(Process);
  1644. return STATUS_SUCCESS;
  1645. }
  1646. case ProcessRaisePriority:
  1647. {
  1648. //
  1649. // This code is used to boost the priority of all threads
  1650. // within a process. It cannot be used to change a thread into
  1651. // a realtime class, or to lower the priority of a thread. The
  1652. // argument is a boost value that is added to the base priority
  1653. // of the specified process.
  1654. //
  1655. if ( ProcessInformationLength != sizeof(ULONG) ) {
  1656. return STATUS_INFO_LENGTH_MISMATCH;
  1657. }
  1658. try {
  1659. BoostValue = *(PULONG)ProcessInformation;
  1660. } except (EXCEPTION_EXECUTE_HANDLER) {
  1661. return GetExceptionCode();
  1662. }
  1663. st = ObReferenceObjectByHandle(
  1664. ProcessHandle,
  1665. PROCESS_SET_INFORMATION,
  1666. PsProcessType,
  1667. PreviousMode,
  1668. (PVOID *)&Process,
  1669. NULL
  1670. );
  1671. if ( !NT_SUCCESS(st) ) {
  1672. return st;
  1673. }
  1674. //
  1675. // Get the process create/delete lock and walk through the
  1676. // thread list boosting each thread.
  1677. //
  1678. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  1679. for (Thread = PsGetNextProcessThread (Process, NULL);
  1680. Thread != NULL;
  1681. Thread = PsGetNextProcessThread (Process, Thread)) {
  1682. KeBoostPriorityThread(&Thread->Tcb,(KPRIORITY)BoostValue);
  1683. }
  1684. ExReleaseRundownProtection (&Process->RundownProtect);
  1685. } else {
  1686. st = STATUS_PROCESS_IS_TERMINATING;
  1687. }
  1688. ObDereferenceObject(Process);
  1689. return st;
  1690. }
  1691. case ProcessDefaultHardErrorMode:
  1692. {
  1693. if ( ProcessInformationLength != sizeof(ULONG) ) {
  1694. return STATUS_INFO_LENGTH_MISMATCH;
  1695. }
  1696. try {
  1697. DefaultHardErrorMode = *(PULONG)ProcessInformation;
  1698. } except (EXCEPTION_EXECUTE_HANDLER) {
  1699. return GetExceptionCode();
  1700. }
  1701. st = ObReferenceObjectByHandle(
  1702. ProcessHandle,
  1703. PROCESS_SET_INFORMATION,
  1704. PsProcessType,
  1705. PreviousMode,
  1706. (PVOID *)&Process,
  1707. NULL
  1708. );
  1709. if ( !NT_SUCCESS(st) ) {
  1710. return st;
  1711. }
  1712. Process->DefaultHardErrorProcessing = DefaultHardErrorMode;
  1713. if (DefaultHardErrorMode & PROCESS_HARDERROR_ALIGNMENT_BIT) {
  1714. KeSetAutoAlignmentProcess(&Process->Pcb,TRUE);
  1715. } else {
  1716. KeSetAutoAlignmentProcess(&Process->Pcb,FALSE);
  1717. }
  1718. ObDereferenceObject(Process);
  1719. return STATUS_SUCCESS;
  1720. }
  1721. case ProcessQuotaLimits: {
  1722. return PspSetQuotaLimits (ProcessHandle,
  1723. ProcessInformationClass,
  1724. ProcessInformation,
  1725. ProcessInformationLength,
  1726. PreviousMode);
  1727. }
  1728. case ProcessExceptionPort : {
  1729. if ( ProcessInformationLength != sizeof(HANDLE) ) {
  1730. return STATUS_INFO_LENGTH_MISMATCH;
  1731. }
  1732. try {
  1733. ExceptionPortHandle = *(PHANDLE) ProcessInformation;
  1734. } except (EXCEPTION_EXECUTE_HANDLER) {
  1735. return GetExceptionCode ();
  1736. }
  1737. st = ObReferenceObjectByHandle (ExceptionPortHandle,
  1738. 0,
  1739. LpcPortObjectType,
  1740. PreviousMode,
  1741. &ExceptionPort,
  1742. NULL);
  1743. if (!NT_SUCCESS (st)) {
  1744. return st;
  1745. }
  1746. st = ObReferenceObjectByHandle (ProcessHandle,
  1747. PROCESS_SET_PORT,
  1748. PsProcessType,
  1749. PreviousMode,
  1750. &Process,
  1751. NULL);
  1752. if (!NT_SUCCESS (st)) {
  1753. ObDereferenceObject (ExceptionPort);
  1754. return st;
  1755. }
  1756. //
  1757. // We are only allowed to put the exception port on. It doesn't get remoted till process delete.
  1758. //
  1759. if (InterlockedCompareExchangePointer (&Process->ExceptionPort, ExceptionPort, NULL) == NULL) {
  1760. st = STATUS_SUCCESS;
  1761. } else {
  1762. ObDereferenceObject (ExceptionPort);
  1763. st = STATUS_PORT_ALREADY_SET;
  1764. }
  1765. ObDereferenceObject(Process);
  1766. return st;
  1767. }
  1768. case ProcessAccessToken : {
  1769. if ( ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN) ) {
  1770. return STATUS_INFO_LENGTH_MISMATCH;
  1771. }
  1772. try {
  1773. PrimaryTokenHandle = ((PROCESS_ACCESS_TOKEN *)ProcessInformation)->Token;
  1774. } except(EXCEPTION_EXECUTE_HANDLER) {
  1775. return GetExceptionCode();
  1776. }
  1777. st = PspSetPrimaryToken (ProcessHandle,
  1778. NULL,
  1779. PrimaryTokenHandle,
  1780. NULL,
  1781. FALSE);
  1782. return st;
  1783. }
  1784. case ProcessLdtInformation:
  1785. st = ObReferenceObjectByHandle (ProcessHandle,
  1786. PROCESS_SET_INFORMATION | PROCESS_VM_WRITE,
  1787. PsProcessType,
  1788. PreviousMode,
  1789. &Process,
  1790. NULL);
  1791. if (!NT_SUCCESS (st)) {
  1792. return st;
  1793. }
  1794. st = PspSetLdtInformation (Process,
  1795. ProcessInformation,
  1796. ProcessInformationLength);
  1797. ObDereferenceObject(Process);
  1798. return st;
  1799. case ProcessLdtSize:
  1800. st = ObReferenceObjectByHandle (ProcessHandle,
  1801. PROCESS_SET_INFORMATION | PROCESS_VM_WRITE,
  1802. PsProcessType,
  1803. PreviousMode,
  1804. &Process,
  1805. NULL);
  1806. if (!NT_SUCCESS (st)) {
  1807. return st;
  1808. }
  1809. st = PspSetLdtSize (Process,
  1810. ProcessInformation,
  1811. ProcessInformationLength);
  1812. ObDereferenceObject(Process);
  1813. return st;
  1814. case ProcessIoPortHandlers:
  1815. st = ObReferenceObjectByHandle(
  1816. ProcessHandle,
  1817. PROCESS_SET_INFORMATION,
  1818. PsProcessType,
  1819. PreviousMode,
  1820. (PVOID *)&Process,
  1821. NULL);
  1822. if (!NT_SUCCESS (st)) {
  1823. return st;
  1824. }
  1825. st = PspSetProcessIoHandlers (Process,
  1826. ProcessInformation,
  1827. ProcessInformationLength);
  1828. ObDereferenceObject(Process);
  1829. return st;
  1830. case ProcessUserModeIOPL:
  1831. //
  1832. // Must make sure the caller is a trusted subsystem with the
  1833. // appropriate privilege level before executing this call.
  1834. // If the calls returns FALSE we must return an error code.
  1835. //
  1836. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  1837. SE_TCB_PRIVILEGE),
  1838. PreviousMode )) {
  1839. return STATUS_PRIVILEGE_NOT_HELD;
  1840. }
  1841. st = ObReferenceObjectByHandle(
  1842. ProcessHandle,
  1843. PROCESS_SET_INFORMATION,
  1844. PsProcessType,
  1845. PreviousMode,
  1846. (PVOID *)&Process,
  1847. NULL
  1848. );
  1849. if ( NT_SUCCESS(st) ) {
  1850. #if defined(_X86_) && !defined(_AMD64_)
  1851. Ke386SetIOPL(&Process->Pcb);
  1852. #endif
  1853. ObDereferenceObject(Process);
  1854. }
  1855. return st;
  1856. //
  1857. // Enable/disable auto-alignment fixup for a process and all its threads.
  1858. //
  1859. case ProcessEnableAlignmentFaultFixup:
  1860. if ( ProcessInformationLength != sizeof(BOOLEAN) ) {
  1861. return STATUS_INFO_LENGTH_MISMATCH;
  1862. }
  1863. try {
  1864. EnableAlignmentFaultFixup = *(PBOOLEAN)ProcessInformation;
  1865. } except (EXCEPTION_EXECUTE_HANDLER) {
  1866. return GetExceptionCode();
  1867. }
  1868. st = ObReferenceObjectByHandle(
  1869. ProcessHandle,
  1870. PROCESS_SET_INFORMATION,
  1871. PsProcessType,
  1872. PreviousMode,
  1873. (PVOID *)&Process,
  1874. NULL
  1875. );
  1876. if ( !NT_SUCCESS(st) ) {
  1877. return st;
  1878. }
  1879. if ( EnableAlignmentFaultFixup ) {
  1880. Process->DefaultHardErrorProcessing |= PROCESS_HARDERROR_ALIGNMENT_BIT;
  1881. }
  1882. else {
  1883. Process->DefaultHardErrorProcessing &= ~PROCESS_HARDERROR_ALIGNMENT_BIT;
  1884. }
  1885. KeSetAutoAlignmentProcess( &(Process->Pcb), EnableAlignmentFaultFixup );
  1886. ObDereferenceObject(Process);
  1887. return STATUS_SUCCESS;
  1888. case ProcessWx86Information :
  1889. return STATUS_INVALID_INFO_CLASS;
  1890. case ProcessAffinityMask:
  1891. if (ProcessInformationLength != sizeof (KAFFINITY)) {
  1892. return STATUS_INFO_LENGTH_MISMATCH;
  1893. }
  1894. try {
  1895. Affinity = *(PKAFFINITY)ProcessInformation;
  1896. } except (EXCEPTION_EXECUTE_HANDLER) {
  1897. return GetExceptionCode();
  1898. }
  1899. AffinityWithMasks = Affinity & KeActiveProcessors;
  1900. if (!Affinity || (AffinityWithMasks != Affinity)) {
  1901. return STATUS_INVALID_PARAMETER;
  1902. }
  1903. st = ObReferenceObjectByHandle(
  1904. ProcessHandle,
  1905. PROCESS_SET_INFORMATION,
  1906. PsProcessType,
  1907. PreviousMode,
  1908. (PVOID *)&Process,
  1909. NULL
  1910. );
  1911. if (!NT_SUCCESS (st)) {
  1912. return st;
  1913. }
  1914. //
  1915. // If the process has a job object, override whatever the process
  1916. // is calling with with the value from the job object
  1917. //
  1918. Job = Process->Job;
  1919. if (Job != NULL) {
  1920. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  1921. ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
  1922. if (Job->LimitFlags & JOB_OBJECT_LIMIT_AFFINITY) {
  1923. AffinityWithMasks = Job->Affinity;
  1924. }
  1925. ExReleaseResourceLite (&Job->JobLock);
  1926. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  1927. }
  1928. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  1929. PspLockProcessExclusive (Process, CurrentThread);
  1930. KeSetAffinityProcess (&Process->Pcb, AffinityWithMasks);
  1931. PspUnlockProcessExclusive (Process, CurrentThread);
  1932. ExReleaseRundownProtection (&Process->RundownProtect);
  1933. st = STATUS_SUCCESS;
  1934. } else {
  1935. st = STATUS_PROCESS_IS_TERMINATING;
  1936. }
  1937. ObDereferenceObject(Process);
  1938. return st;
  1939. case ProcessPriorityBoost:
  1940. if ( ProcessInformationLength != sizeof(ULONG) ) {
  1941. return STATUS_INFO_LENGTH_MISMATCH;
  1942. }
  1943. try {
  1944. DisableBoost = *(PULONG)ProcessInformation;
  1945. } except(EXCEPTION_EXECUTE_HANDLER) {
  1946. return GetExceptionCode();
  1947. }
  1948. bDisableBoost = (DisableBoost ? TRUE : FALSE);
  1949. st = ObReferenceObjectByHandle(
  1950. ProcessHandle,
  1951. PROCESS_SET_INFORMATION,
  1952. PsProcessType,
  1953. PreviousMode,
  1954. (PVOID *)&Process,
  1955. NULL
  1956. );
  1957. if (!NT_SUCCESS (st)) {
  1958. return st;
  1959. }
  1960. //
  1961. // the following allows this api to properly if
  1962. // called while the exiting process is blocked holding the
  1963. // createdeletelock. This can happen during debugger/server
  1964. // lpc transactions that occur in pspexitthread
  1965. //
  1966. if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
  1967. st = STATUS_PROCESS_IS_TERMINATING;
  1968. } else {
  1969. PLIST_ENTRY Next;
  1970. PspLockProcessExclusive (Process, CurrentThread);
  1971. Process->Pcb.DisableBoost = bDisableBoost;
  1972. for (Next = Process->ThreadListHead.Flink;
  1973. Next != &Process->ThreadListHead;
  1974. Next = Next->Flink) {
  1975. Thread = (PETHREAD)(CONTAINING_RECORD(Next,ETHREAD,ThreadListEntry));
  1976. KeSetDisableBoostThread(&Thread->Tcb,bDisableBoost);
  1977. }
  1978. PspUnlockProcessExclusive (Process, CurrentThread);
  1979. ExReleaseRundownProtection (&Process->RundownProtect);
  1980. }
  1981. ObDereferenceObject(Process);
  1982. return st;
  1983. case ProcessDebugFlags : {
  1984. ULONG Flags;
  1985. if (ProcessInformationLength != sizeof (ULONG)) {
  1986. return STATUS_INFO_LENGTH_MISMATCH;
  1987. }
  1988. st = ObReferenceObjectByHandle (ProcessHandle,
  1989. PROCESS_SET_INFORMATION,
  1990. PsProcessType,
  1991. PreviousMode,
  1992. &Process,
  1993. NULL);
  1994. if (!NT_SUCCESS (st)) {
  1995. return st;
  1996. }
  1997. try {
  1998. Flags = *(PULONG) ProcessInformation;
  1999. } except (EXCEPTION_EXECUTE_HANDLER) {
  2000. Flags = 0;
  2001. st = GetExceptionCode ();
  2002. }
  2003. if (NT_SUCCESS (st)) {
  2004. if (Flags & ~PROCESS_DEBUG_INHERIT) {
  2005. st = STATUS_INVALID_PARAMETER;
  2006. } else {
  2007. if (Flags&PROCESS_DEBUG_INHERIT) {
  2008. PS_CLEAR_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
  2009. } else {
  2010. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
  2011. }
  2012. }
  2013. }
  2014. ObDereferenceObject (Process);
  2015. return st;
  2016. }
  2017. case ProcessDeviceMap:
  2018. DeviceMapInfo = (PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation;
  2019. if ( ProcessInformationLength != sizeof(DeviceMapInfo->Set) ) {
  2020. return STATUS_INFO_LENGTH_MISMATCH;
  2021. }
  2022. try {
  2023. DirectoryHandle = DeviceMapInfo->Set.DirectoryHandle;
  2024. } except (EXCEPTION_EXECUTE_HANDLER) {
  2025. return GetExceptionCode();
  2026. }
  2027. st = ObReferenceObjectByHandle(
  2028. ProcessHandle,
  2029. PROCESS_SET_INFORMATION,
  2030. PsProcessType,
  2031. PreviousMode,
  2032. (PVOID *)&Process,
  2033. NULL
  2034. );
  2035. if ( !NT_SUCCESS(st) ) {
  2036. return st;
  2037. }
  2038. //
  2039. // The devmap fields here are synchronized using a private ob spinlock. We don't need to protect with a
  2040. // lock at this level.
  2041. //
  2042. st = ObSetDeviceMap( Process, DirectoryHandle );
  2043. ObDereferenceObject(Process);
  2044. return st;
  2045. case ProcessSessionInformation :
  2046. //
  2047. // Update Multi-User session specific process information
  2048. //
  2049. if ( ProcessInformationLength != (ULONG) sizeof(PROCESS_SESSION_INFORMATION) ) {
  2050. return STATUS_INFO_LENGTH_MISMATCH;
  2051. }
  2052. try {
  2053. SessionInfo = *(PPROCESS_SESSION_INFORMATION) ProcessInformation;
  2054. } except (EXCEPTION_EXECUTE_HANDLER) {
  2055. return GetExceptionCode();
  2056. }
  2057. //
  2058. // We only allow TCB to set SessionId's
  2059. //
  2060. if ( !SeSinglePrivilegeCheck(SeTcbPrivilege,PreviousMode) ) {
  2061. return( STATUS_PRIVILEGE_NOT_HELD );
  2062. }
  2063. //
  2064. // Reference process object
  2065. //
  2066. st = ObReferenceObjectByHandle(
  2067. ProcessHandle,
  2068. PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID,
  2069. PsProcessType,
  2070. PreviousMode,
  2071. (PVOID *)&Process,
  2072. NULL
  2073. );
  2074. if ( !NT_SUCCESS(st) ) {
  2075. return st;
  2076. }
  2077. //
  2078. // Update SessionId in the Token
  2079. //
  2080. if (SessionInfo.SessionId != MmGetSessionId (Process)) {
  2081. st = STATUS_ACCESS_DENIED;
  2082. } else {
  2083. st = STATUS_SUCCESS;
  2084. }
  2085. ObDereferenceObject(Process);
  2086. return( st );
  2087. case ProcessBreakOnTermination:
  2088. if ( ProcessInformationLength != sizeof(ULONG) ) {
  2089. return STATUS_INFO_LENGTH_MISMATCH;
  2090. }
  2091. try {
  2092. EnableBreakOnTermination = *(PULONG)ProcessInformation;
  2093. } except (EXCEPTION_EXECUTE_HANDLER) {
  2094. return GetExceptionCode();
  2095. }
  2096. if (!SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)) {
  2097. return STATUS_PRIVILEGE_NOT_HELD;
  2098. }
  2099. st = ObReferenceObjectByHandle(
  2100. ProcessHandle,
  2101. PROCESS_SET_INFORMATION,
  2102. PsProcessType,
  2103. PreviousMode,
  2104. (PVOID *)&Process,
  2105. NULL
  2106. );
  2107. if ( !NT_SUCCESS(st) ) {
  2108. return st;
  2109. }
  2110. if ( EnableBreakOnTermination ) {
  2111. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_BREAK_ON_TERMINATION);
  2112. } else {
  2113. PS_CLEAR_BITS (&Process->Flags, PS_PROCESS_FLAGS_BREAK_ON_TERMINATION);
  2114. }
  2115. ObDereferenceObject(Process);
  2116. return STATUS_SUCCESS;
  2117. case ProcessHandleTracing: {
  2118. PPROCESS_HANDLE_TRACING_ENABLE Pht;
  2119. PHANDLE_TABLE HandleTable;
  2120. if (ProcessInformationLength != sizeof (PROCESS_HANDLE_TRACING_ENABLE)) {
  2121. return STATUS_INFO_LENGTH_MISMATCH;
  2122. }
  2123. Pht = (PPROCESS_HANDLE_TRACING_ENABLE) ProcessInformation;
  2124. try {
  2125. if (Pht->Flags != 0) {
  2126. return STATUS_INVALID_PARAMETER;
  2127. }
  2128. } except (EXCEPTION_EXECUTE_HANDLER) {
  2129. return GetExceptionCode ();
  2130. }
  2131. st = ObReferenceObjectByHandle (ProcessHandle,
  2132. PROCESS_SET_INFORMATION,
  2133. PsProcessType,
  2134. PreviousMode,
  2135. &Process,
  2136. NULL);
  2137. if (!NT_SUCCESS (st)) {
  2138. return st;
  2139. }
  2140. HandleTable = ObReferenceProcessHandleTable (Process);
  2141. if (HandleTable != NULL) {
  2142. st = ExEnableHandleTracing (HandleTable);
  2143. ObDereferenceProcessHandleTable (Process);
  2144. } else {
  2145. st = STATUS_PROCESS_IS_TERMINATING;
  2146. }
  2147. ObDereferenceObject(Process);
  2148. return st;
  2149. }
  2150. default:
  2151. return STATUS_INVALID_INFO_CLASS;
  2152. }
  2153. }
  2154. NTSTATUS
  2155. NtQueryInformationThread(
  2156. IN HANDLE ThreadHandle,
  2157. IN THREADINFOCLASS ThreadInformationClass,
  2158. OUT PVOID ThreadInformation,
  2159. IN ULONG ThreadInformationLength,
  2160. OUT PULONG ReturnLength OPTIONAL
  2161. )
  2162. /*++
  2163. Routine Description:
  2164. This function queries the state of a thread object and returns the
  2165. requested information in the specified record structure.
  2166. Arguments:
  2167. ThreadHandle - Supplies a handle to a thread object.
  2168. ThreadInformationClass - Supplies the class of information being
  2169. requested.
  2170. ThreadInformation - Supplies a pointer to a record that is to
  2171. receive the requested information.
  2172. ThreadInformationLength - Supplies the length of the record that is
  2173. to receive the requested information.
  2174. ReturnLength - Supplies an optional pointer to a variable that is to
  2175. receive the actual length of information that is returned.
  2176. Return Value:
  2177. TBS
  2178. --*/
  2179. {
  2180. LARGE_INTEGER PerformanceCount;
  2181. PETHREAD Thread;
  2182. PEPROCESS Process;
  2183. ULONG LastThread;
  2184. KPROCESSOR_MODE PreviousMode;
  2185. NTSTATUS st;
  2186. THREAD_BASIC_INFORMATION BasicInfo;
  2187. KERNEL_USER_TIMES SysUserTime;
  2188. PVOID Win32StartAddressValue;
  2189. ULONG DisableBoost;
  2190. ULONG IoPending ;
  2191. ULONG BreakOnTerminationEnabled;
  2192. PETHREAD CurrentThread;
  2193. //
  2194. // Get previous processor mode and probe output argument if necessary.
  2195. //
  2196. PAGED_CODE();
  2197. CurrentThread = PsGetCurrentThread ();
  2198. PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  2199. if (PreviousMode != KernelMode) {
  2200. try {
  2201. ProbeForWrite(ThreadInformation,
  2202. ThreadInformationLength,
  2203. sizeof(ULONG));
  2204. if (ARGUMENT_PRESENT(ReturnLength)) {
  2205. ProbeForWriteUlong(ReturnLength);
  2206. }
  2207. } except (EXCEPTION_EXECUTE_HANDLER) {
  2208. return GetExceptionCode();
  2209. }
  2210. }
  2211. //
  2212. // Check argument validity.
  2213. //
  2214. switch ( ThreadInformationClass ) {
  2215. case ThreadBasicInformation:
  2216. if ( ThreadInformationLength != (ULONG) sizeof(THREAD_BASIC_INFORMATION) ) {
  2217. return STATUS_INFO_LENGTH_MISMATCH;
  2218. }
  2219. st = ObReferenceObjectByHandle(
  2220. ThreadHandle,
  2221. THREAD_QUERY_INFORMATION,
  2222. PsThreadType,
  2223. PreviousMode,
  2224. (PVOID *)&Thread,
  2225. NULL
  2226. );
  2227. if ( !NT_SUCCESS(st) ) {
  2228. return st;
  2229. }
  2230. if (KeReadStateThread(&Thread->Tcb)) {
  2231. BasicInfo.ExitStatus = Thread->ExitStatus;
  2232. } else {
  2233. BasicInfo.ExitStatus = STATUS_PENDING;
  2234. }
  2235. BasicInfo.TebBaseAddress = (PTEB) Thread->Tcb.Teb;
  2236. BasicInfo.ClientId = Thread->Cid;
  2237. BasicInfo.AffinityMask = Thread->Tcb.Affinity;
  2238. BasicInfo.Priority = Thread->Tcb.Priority;
  2239. BasicInfo.BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
  2240. ObDereferenceObject(Thread);
  2241. //
  2242. // Either of these may cause an access violation. The
  2243. // exception handler will return access violation as
  2244. // status code. No further cleanup needs to be done.
  2245. //
  2246. try {
  2247. *(PTHREAD_BASIC_INFORMATION) ThreadInformation = BasicInfo;
  2248. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2249. *ReturnLength = sizeof(THREAD_BASIC_INFORMATION);
  2250. }
  2251. } except (EXCEPTION_EXECUTE_HANDLER) {
  2252. return STATUS_SUCCESS;
  2253. }
  2254. return STATUS_SUCCESS;
  2255. case ThreadTimes:
  2256. if ( ThreadInformationLength != (ULONG) sizeof(KERNEL_USER_TIMES) ) {
  2257. return STATUS_INFO_LENGTH_MISMATCH;
  2258. }
  2259. st = ObReferenceObjectByHandle(
  2260. ThreadHandle,
  2261. THREAD_QUERY_INFORMATION,
  2262. PsThreadType,
  2263. PreviousMode,
  2264. (PVOID *)&Thread,
  2265. NULL
  2266. );
  2267. if ( !NT_SUCCESS(st) ) {
  2268. return st;
  2269. }
  2270. SysUserTime.KernelTime.QuadPart = UInt32x32To64(Thread->Tcb.KernelTime,
  2271. KeMaximumIncrement);
  2272. SysUserTime.UserTime.QuadPart = UInt32x32To64(Thread->Tcb.UserTime,
  2273. KeMaximumIncrement);
  2274. SysUserTime.CreateTime.QuadPart = PS_GET_THREAD_CREATE_TIME(Thread);
  2275. if (KeReadStateThread(&Thread->Tcb)) {
  2276. SysUserTime.ExitTime = Thread->ExitTime;
  2277. } else {
  2278. SysUserTime.ExitTime.QuadPart = 0;
  2279. }
  2280. ObDereferenceObject(Thread);
  2281. //
  2282. // Either of these may cause an access violation. The
  2283. // exception handler will return access violation as
  2284. // status code. No further cleanup needs to be done.
  2285. //
  2286. try {
  2287. *(PKERNEL_USER_TIMES) ThreadInformation = SysUserTime;
  2288. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2289. *ReturnLength = sizeof(KERNEL_USER_TIMES);
  2290. }
  2291. } except (EXCEPTION_EXECUTE_HANDLER) {
  2292. return GetExceptionCode ();
  2293. }
  2294. return STATUS_SUCCESS;
  2295. case ThreadDescriptorTableEntry :
  2296. st = ObReferenceObjectByHandle(
  2297. ThreadHandle,
  2298. THREAD_QUERY_INFORMATION,
  2299. PsThreadType,
  2300. PreviousMode,
  2301. (PVOID *)&Thread,
  2302. NULL
  2303. );
  2304. if ( !NT_SUCCESS(st) ) {
  2305. return st;
  2306. }
  2307. st = PspQueryDescriptorThread (Thread,
  2308. ThreadInformation,
  2309. ThreadInformationLength,
  2310. ReturnLength);
  2311. ObDereferenceObject(Thread);
  2312. return st;
  2313. case ThreadQuerySetWin32StartAddress:
  2314. if ( ThreadInformationLength != sizeof(ULONG_PTR) ) {
  2315. return STATUS_INFO_LENGTH_MISMATCH;
  2316. }
  2317. st = ObReferenceObjectByHandle(
  2318. ThreadHandle,
  2319. THREAD_QUERY_INFORMATION,
  2320. PsThreadType,
  2321. PreviousMode,
  2322. (PVOID *)&Thread,
  2323. NULL
  2324. );
  2325. if ( !NT_SUCCESS(st) ) {
  2326. return st;
  2327. }
  2328. Win32StartAddressValue = Thread->Win32StartAddress;
  2329. ObDereferenceObject(Thread);
  2330. try {
  2331. *(PVOID *) ThreadInformation = Win32StartAddressValue;
  2332. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2333. *ReturnLength = sizeof(ULONG_PTR);
  2334. }
  2335. } except (EXCEPTION_EXECUTE_HANDLER) {
  2336. return GetExceptionCode();
  2337. }
  2338. return st;
  2339. //
  2340. // Query thread cycle counter.
  2341. //
  2342. case ThreadPerformanceCount:
  2343. if ( ThreadInformationLength != sizeof(LARGE_INTEGER) ) {
  2344. return STATUS_INFO_LENGTH_MISMATCH;
  2345. }
  2346. st = ObReferenceObjectByHandle(
  2347. ThreadHandle,
  2348. THREAD_QUERY_INFORMATION,
  2349. PsThreadType,
  2350. PreviousMode,
  2351. (PVOID *)&Thread,
  2352. NULL
  2353. );
  2354. if ( !NT_SUCCESS(st) ) {
  2355. return st;
  2356. }
  2357. #if defined (PERF_DATA)
  2358. PerformanceCount.LowPart = Thread->PerformanceCountLow;
  2359. PerformanceCount.HighPart = Thread->PerformanceCountHigh;
  2360. #else
  2361. PerformanceCount.QuadPart = 0;
  2362. #endif
  2363. ObDereferenceObject(Thread);
  2364. try {
  2365. *(PLARGE_INTEGER)ThreadInformation = PerformanceCount;
  2366. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2367. *ReturnLength = sizeof(LARGE_INTEGER);
  2368. }
  2369. } except (EXCEPTION_EXECUTE_HANDLER) {
  2370. return GetExceptionCode();
  2371. }
  2372. return st;
  2373. case ThreadAmILastThread:
  2374. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2375. return STATUS_INFO_LENGTH_MISMATCH;
  2376. }
  2377. Process = THREAD_TO_PROCESS (CurrentThread);
  2378. if (Process->ActiveThreads == 1) {
  2379. LastThread = 1;
  2380. } else {
  2381. LastThread = 0;
  2382. }
  2383. try {
  2384. *(PULONG)ThreadInformation = LastThread;
  2385. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2386. *ReturnLength = sizeof(ULONG);
  2387. }
  2388. } except (EXCEPTION_EXECUTE_HANDLER) {
  2389. return GetExceptionCode();
  2390. }
  2391. return STATUS_SUCCESS;
  2392. case ThreadPriorityBoost:
  2393. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2394. return STATUS_INFO_LENGTH_MISMATCH;
  2395. }
  2396. st = ObReferenceObjectByHandle(
  2397. ThreadHandle,
  2398. THREAD_QUERY_INFORMATION,
  2399. PsThreadType,
  2400. PreviousMode,
  2401. (PVOID *)&Thread,
  2402. NULL
  2403. );
  2404. if ( !NT_SUCCESS(st) ) {
  2405. return st;
  2406. }
  2407. DisableBoost = Thread->Tcb.DisableBoost ? 1 : 0;
  2408. ObDereferenceObject(Thread);
  2409. try {
  2410. *(PULONG)ThreadInformation = DisableBoost;
  2411. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2412. *ReturnLength = sizeof(ULONG);
  2413. }
  2414. } except (EXCEPTION_EXECUTE_HANDLER) {
  2415. return GetExceptionCode();
  2416. }
  2417. return st;
  2418. case ThreadIsIoPending:
  2419. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2420. return STATUS_INFO_LENGTH_MISMATCH;
  2421. }
  2422. st = ObReferenceObjectByHandle (ThreadHandle,
  2423. THREAD_QUERY_INFORMATION,
  2424. PsThreadType,
  2425. PreviousMode,
  2426. &Thread,
  2427. NULL);
  2428. if (!NT_SUCCESS (st)) {
  2429. return st;
  2430. }
  2431. //
  2432. // Its impossible to synchronize this cross thread.
  2433. // Since the result is worthless the second its fetched
  2434. // this isn't a problem.
  2435. //
  2436. IoPending = !IsListEmpty (&Thread->IrpList);
  2437. ObDereferenceObject (Thread);
  2438. try {
  2439. *(PULONG)ThreadInformation = IoPending ;
  2440. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2441. *ReturnLength = sizeof(ULONG);
  2442. }
  2443. } except (EXCEPTION_EXECUTE_HANDLER) {
  2444. return GetExceptionCode();
  2445. }
  2446. return STATUS_SUCCESS ;
  2447. case ThreadBreakOnTermination:
  2448. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2449. return STATUS_INFO_LENGTH_MISMATCH;
  2450. }
  2451. st = ObReferenceObjectByHandle(
  2452. ThreadHandle,
  2453. THREAD_QUERY_INFORMATION,
  2454. PsThreadType,
  2455. PreviousMode,
  2456. (PVOID *)&Thread,
  2457. NULL
  2458. );
  2459. if ( !NT_SUCCESS(st) ) {
  2460. return st;
  2461. }
  2462. if (Thread->CrossThreadFlags
  2463. & PS_CROSS_THREAD_FLAGS_BREAK_ON_TERMINATION) {
  2464. BreakOnTerminationEnabled = 1;
  2465. } else {
  2466. BreakOnTerminationEnabled = 0;
  2467. }
  2468. ObDereferenceObject(Thread);
  2469. try {
  2470. *(PULONG) ThreadInformation = BreakOnTerminationEnabled;
  2471. if (ARGUMENT_PRESENT(ReturnLength) ) {
  2472. *ReturnLength = sizeof(ULONG);
  2473. }
  2474. } except (EXCEPTION_EXECUTE_HANDLER) {
  2475. return GetExceptionCode ();
  2476. }
  2477. return STATUS_SUCCESS;
  2478. default:
  2479. return STATUS_INVALID_INFO_CLASS;
  2480. }
  2481. }
  2482. NTSTATUS
  2483. NtSetInformationThread(
  2484. IN HANDLE ThreadHandle,
  2485. IN THREADINFOCLASS ThreadInformationClass,
  2486. IN PVOID ThreadInformation,
  2487. IN ULONG ThreadInformationLength
  2488. )
  2489. /*++
  2490. Routine Description:
  2491. This function sets the state of a thread object.
  2492. Arguments:
  2493. ThreadHandle - Supplies a handle to a thread object.
  2494. ThreadInformationClass - Supplies the class of information being
  2495. set.
  2496. ThreadInformation - Supplies a pointer to a record that contains the
  2497. information to set.
  2498. ThreadInformationLength - Supplies the length of the record that contains
  2499. the information to set.
  2500. Return Value:
  2501. TBS
  2502. --*/
  2503. {
  2504. PETHREAD Thread;
  2505. PETHREAD CurrentThread;
  2506. PEPROCESS Process;
  2507. KPROCESSOR_MODE PreviousMode;
  2508. NTSTATUS st;
  2509. KAFFINITY Affinity, AffinityWithMasks;
  2510. KPRIORITY Priority;
  2511. LONG BasePriority;
  2512. ULONG TlsIndex;
  2513. PVOID TlsArrayAddress;
  2514. PVOID Win32StartAddressValue;
  2515. ULONG ProbeAlignment;
  2516. BOOLEAN EnableAlignmentFaultFixup;
  2517. ULONG EnableBreakOnTermination;
  2518. ULONG IdealProcessor;
  2519. ULONG DisableBoost;
  2520. PVOID *ExpansionSlots;
  2521. HANDLE ImpersonationTokenHandle;
  2522. BOOLEAN HasPrivilege;
  2523. PEJOB Job;
  2524. PTEB Teb;
  2525. PAGED_CODE();
  2526. //
  2527. // Get previous processor mode and probe input argument if necessary.
  2528. //
  2529. CurrentThread = PsGetCurrentThread ();
  2530. PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  2531. if (PreviousMode != KernelMode) {
  2532. try {
  2533. switch (ThreadInformationClass) {
  2534. case ThreadPriority :
  2535. ProbeAlignment = sizeof(KPRIORITY);
  2536. break;
  2537. case ThreadAffinityMask :
  2538. case ThreadQuerySetWin32StartAddress :
  2539. ProbeAlignment = sizeof (ULONG_PTR);
  2540. break;
  2541. case ThreadEnableAlignmentFaultFixup :
  2542. ProbeAlignment = sizeof (BOOLEAN);
  2543. break;
  2544. default :
  2545. ProbeAlignment = sizeof(ULONG);
  2546. }
  2547. ProbeForRead(
  2548. ThreadInformation,
  2549. ThreadInformationLength,
  2550. ProbeAlignment
  2551. );
  2552. } except (EXCEPTION_EXECUTE_HANDLER) {
  2553. return GetExceptionCode();
  2554. }
  2555. }
  2556. //
  2557. // Check argument validity.
  2558. //
  2559. switch ( ThreadInformationClass ) {
  2560. case ThreadPriority:
  2561. if ( ThreadInformationLength != sizeof(KPRIORITY) ) {
  2562. return STATUS_INFO_LENGTH_MISMATCH;
  2563. }
  2564. try {
  2565. Priority = *(KPRIORITY *)ThreadInformation;
  2566. } except (EXCEPTION_EXECUTE_HANDLER) {
  2567. return GetExceptionCode();
  2568. }
  2569. if ( Priority > HIGH_PRIORITY ||
  2570. Priority <= LOW_PRIORITY ) {
  2571. return STATUS_INVALID_PARAMETER;
  2572. }
  2573. if ( Priority >= LOW_REALTIME_PRIORITY ) {
  2574. //
  2575. // Increasing the priority of a thread beyond
  2576. // LOW_REALTIME_PRIORITY is a privileged operation.
  2577. //
  2578. HasPrivilege = SeCheckPrivilegedObject(
  2579. SeIncreaseBasePriorityPrivilege,
  2580. ThreadHandle,
  2581. THREAD_SET_INFORMATION,
  2582. PreviousMode
  2583. );
  2584. if (!HasPrivilege) {
  2585. return STATUS_PRIVILEGE_NOT_HELD;
  2586. }
  2587. }
  2588. st = ObReferenceObjectByHandle(
  2589. ThreadHandle,
  2590. THREAD_SET_INFORMATION,
  2591. PsThreadType,
  2592. PreviousMode,
  2593. (PVOID *)&Thread,
  2594. NULL
  2595. );
  2596. if ( !NT_SUCCESS(st) ) {
  2597. return st;
  2598. }
  2599. KeSetPriorityThread(&Thread->Tcb,Priority);
  2600. ObDereferenceObject(Thread);
  2601. return STATUS_SUCCESS;
  2602. case ThreadBasePriority:
  2603. if (ThreadInformationLength != sizeof (LONG)) {
  2604. return STATUS_INFO_LENGTH_MISMATCH;
  2605. }
  2606. try {
  2607. BasePriority = *(PLONG)ThreadInformation;
  2608. } except (EXCEPTION_EXECUTE_HANDLER) {
  2609. return GetExceptionCode ();
  2610. }
  2611. st = ObReferenceObjectByHandle(
  2612. ThreadHandle,
  2613. THREAD_SET_INFORMATION,
  2614. PsThreadType,
  2615. PreviousMode,
  2616. (PVOID *)&Thread,
  2617. NULL
  2618. );
  2619. if (!NT_SUCCESS(st)) {
  2620. return st;
  2621. }
  2622. Process = THREAD_TO_PROCESS(Thread);
  2623. if (BasePriority > THREAD_BASE_PRIORITY_MAX ||
  2624. BasePriority < THREAD_BASE_PRIORITY_MIN) {
  2625. if (BasePriority == THREAD_BASE_PRIORITY_LOWRT+1 ||
  2626. BasePriority == THREAD_BASE_PRIORITY_IDLE-1) {
  2627. ;
  2628. } else {
  2629. //
  2630. // Allow csrss, or realtime processes to select any
  2631. // priority
  2632. //
  2633. if (PsGetCurrentProcessByThread (CurrentThread) == ExpDefaultErrorPortProcess ||
  2634. Process->PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME) {
  2635. ;
  2636. } else {
  2637. ObDereferenceObject(Thread);
  2638. return STATUS_INVALID_PARAMETER;
  2639. }
  2640. }
  2641. }
  2642. //
  2643. // If the thread is running within a job object, and the job
  2644. // object has a priority class limit, do not allow
  2645. // priority adjustments that raise the thread's priority, unless
  2646. // the priority class is realtime
  2647. //
  2648. Job = Process->Job;
  2649. if (Job != NULL && (Job->LimitFlags & JOB_OBJECT_LIMIT_PRIORITY_CLASS)) {
  2650. if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_REALTIME){
  2651. if (BasePriority > 0) {
  2652. ObDereferenceObject(Thread);
  2653. return STATUS_SUCCESS;
  2654. }
  2655. }
  2656. }
  2657. KeSetBasePriorityThread(&Thread->Tcb,BasePriority);
  2658. ObDereferenceObject(Thread);
  2659. return STATUS_SUCCESS;
  2660. case ThreadEnableAlignmentFaultFixup:
  2661. if ( ThreadInformationLength != sizeof(BOOLEAN) ) {
  2662. return STATUS_INFO_LENGTH_MISMATCH;
  2663. }
  2664. try {
  2665. EnableAlignmentFaultFixup = *(PBOOLEAN)ThreadInformation;
  2666. } except (EXCEPTION_EXECUTE_HANDLER) {
  2667. return GetExceptionCode();
  2668. }
  2669. st = ObReferenceObjectByHandle(
  2670. ThreadHandle,
  2671. THREAD_SET_INFORMATION,
  2672. PsThreadType,
  2673. PreviousMode,
  2674. (PVOID *)&Thread,
  2675. NULL
  2676. );
  2677. if ( !NT_SUCCESS(st) ) {
  2678. return st;
  2679. }
  2680. KeSetAutoAlignmentThread (&(Thread->Tcb), EnableAlignmentFaultFixup);
  2681. ObDereferenceObject(Thread);
  2682. return STATUS_SUCCESS;
  2683. case ThreadAffinityMask:
  2684. if ( ThreadInformationLength != sizeof(KAFFINITY) ) {
  2685. return STATUS_INFO_LENGTH_MISMATCH;
  2686. }
  2687. try {
  2688. Affinity = *(PKAFFINITY)ThreadInformation;
  2689. } except (EXCEPTION_EXECUTE_HANDLER) {
  2690. return GetExceptionCode();
  2691. }
  2692. if (!Affinity) {
  2693. return STATUS_INVALID_PARAMETER;
  2694. }
  2695. st = ObReferenceObjectByHandle(
  2696. ThreadHandle,
  2697. THREAD_SET_INFORMATION,
  2698. PsThreadType,
  2699. PreviousMode,
  2700. (PVOID *)&Thread,
  2701. NULL
  2702. );
  2703. if ( !NT_SUCCESS(st) ) {
  2704. return st;
  2705. }
  2706. Process = THREAD_TO_PROCESS(Thread);
  2707. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  2708. PspLockProcessShared (Process, CurrentThread);
  2709. AffinityWithMasks = Affinity & Process->Pcb.Affinity;
  2710. if (AffinityWithMasks != Affinity) {
  2711. st = STATUS_INVALID_PARAMETER;
  2712. } else {
  2713. KeSetAffinityThread (&Thread->Tcb,
  2714. AffinityWithMasks);
  2715. st = STATUS_SUCCESS;
  2716. }
  2717. PspUnlockProcessShared (Process, CurrentThread);
  2718. ExReleaseRundownProtection (&Process->RundownProtect);
  2719. } else {
  2720. st = STATUS_PROCESS_IS_TERMINATING;
  2721. }
  2722. ObDereferenceObject(Thread);
  2723. return st;
  2724. case ThreadImpersonationToken:
  2725. if ( ThreadInformationLength != sizeof(HANDLE) ) {
  2726. return STATUS_INFO_LENGTH_MISMATCH;
  2727. }
  2728. try {
  2729. ImpersonationTokenHandle = *(PHANDLE) ThreadInformation;
  2730. } except (EXCEPTION_EXECUTE_HANDLER) {
  2731. return GetExceptionCode();
  2732. }
  2733. st = ObReferenceObjectByHandle(
  2734. ThreadHandle,
  2735. THREAD_SET_THREAD_TOKEN,
  2736. PsThreadType,
  2737. PreviousMode,
  2738. (PVOID *)&Thread,
  2739. NULL
  2740. );
  2741. if ( !NT_SUCCESS(st) ) {
  2742. return st;
  2743. }
  2744. //
  2745. // Check for proper access to (and type of) the token, and assign
  2746. // it as the thread's impersonation token.
  2747. //
  2748. st = PsAssignImpersonationToken( Thread, ImpersonationTokenHandle );
  2749. ObDereferenceObject(Thread);
  2750. return st;
  2751. case ThreadQuerySetWin32StartAddress:
  2752. if ( ThreadInformationLength != sizeof(ULONG_PTR) ) {
  2753. return STATUS_INFO_LENGTH_MISMATCH;
  2754. }
  2755. try {
  2756. Win32StartAddressValue = *(PVOID *) ThreadInformation;
  2757. } except (EXCEPTION_EXECUTE_HANDLER) {
  2758. return GetExceptionCode();
  2759. }
  2760. st = ObReferenceObjectByHandle(
  2761. ThreadHandle,
  2762. THREAD_SET_INFORMATION,
  2763. PsThreadType,
  2764. PreviousMode,
  2765. (PVOID *)&Thread,
  2766. NULL
  2767. );
  2768. if ( !NT_SUCCESS(st) ) {
  2769. return st;
  2770. }
  2771. Thread->Win32StartAddress = (PVOID)Win32StartAddressValue;
  2772. ObDereferenceObject(Thread);
  2773. return st;
  2774. case ThreadIdealProcessor:
  2775. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2776. return STATUS_INFO_LENGTH_MISMATCH;
  2777. }
  2778. try {
  2779. IdealProcessor = *(PULONG)ThreadInformation;
  2780. } except (EXCEPTION_EXECUTE_HANDLER) {
  2781. return GetExceptionCode();
  2782. }
  2783. if ( IdealProcessor > MAXIMUM_PROCESSORS ) {
  2784. return STATUS_INVALID_PARAMETER;
  2785. }
  2786. st = ObReferenceObjectByHandle (ThreadHandle,
  2787. THREAD_SET_INFORMATION,
  2788. PsThreadType,
  2789. PreviousMode,
  2790. &Thread,
  2791. NULL);
  2792. if (!NT_SUCCESS (st)) {
  2793. return st;
  2794. }
  2795. //
  2796. // this is sort of a slimey way of returning info from this set only
  2797. // api
  2798. //
  2799. st = (NTSTATUS)KeSetIdealProcessorThread (&Thread->Tcb, (CCHAR)IdealProcessor);
  2800. //
  2801. // We could be making cross process and/or cross thread references here.
  2802. // Acquire rundown protection to make sure the teb can't go away.
  2803. //
  2804. Teb = Thread->Tcb.Teb;
  2805. if (Teb != NULL && ExAcquireRundownProtection (&Thread->RundownProtect)) {
  2806. PEPROCESS TargetProcess;
  2807. BOOLEAN Attached;
  2808. KAPC_STATE ApcState;
  2809. Attached = FALSE;
  2810. //
  2811. // See if we are crossing process boundaries and if so attach to the target
  2812. //
  2813. TargetProcess = THREAD_TO_PROCESS (Thread);
  2814. if (TargetProcess != PsGetCurrentProcessByThread (CurrentThread)) {
  2815. KeStackAttachProcess (&TargetProcess->Pcb, &ApcState);
  2816. Attached = TRUE;
  2817. }
  2818. try {
  2819. Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
  2820. } except (EXCEPTION_EXECUTE_HANDLER) {
  2821. }
  2822. if (Attached) {
  2823. KeUnstackDetachProcess (&ApcState);
  2824. }
  2825. ExReleaseRundownProtection (&Thread->RundownProtect);
  2826. }
  2827. ObDereferenceObject (Thread);
  2828. return st;
  2829. case ThreadPriorityBoost:
  2830. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2831. return STATUS_INFO_LENGTH_MISMATCH;
  2832. }
  2833. try {
  2834. DisableBoost = *(PULONG)ThreadInformation;
  2835. } except (EXCEPTION_EXECUTE_HANDLER) {
  2836. return GetExceptionCode();
  2837. }
  2838. st = ObReferenceObjectByHandle(
  2839. ThreadHandle,
  2840. THREAD_SET_INFORMATION,
  2841. PsThreadType,
  2842. PreviousMode,
  2843. (PVOID *)&Thread,
  2844. NULL
  2845. );
  2846. if ( !NT_SUCCESS(st) ) {
  2847. return st;
  2848. }
  2849. KeSetDisableBoostThread(&Thread->Tcb,DisableBoost ? TRUE : FALSE);
  2850. ObDereferenceObject(Thread);
  2851. return st;
  2852. case ThreadZeroTlsCell:
  2853. if ( ThreadInformationLength != sizeof(ULONG) ) {
  2854. return STATUS_INFO_LENGTH_MISMATCH;
  2855. }
  2856. try {
  2857. TlsIndex = *(PULONG) ThreadInformation;
  2858. } except (EXCEPTION_EXECUTE_HANDLER) {
  2859. return GetExceptionCode();
  2860. }
  2861. st = ObReferenceObjectByHandle(
  2862. ThreadHandle,
  2863. THREAD_SET_INFORMATION,
  2864. PsThreadType,
  2865. PreviousMode,
  2866. (PVOID *)&Thread,
  2867. NULL
  2868. );
  2869. if ( !NT_SUCCESS(st) ) {
  2870. return st;
  2871. }
  2872. ObDereferenceObject (Thread);
  2873. if (Thread != CurrentThread) {
  2874. return STATUS_INVALID_PARAMETER;
  2875. }
  2876. {
  2877. PTEB Teb;
  2878. Process = THREAD_TO_PROCESS (Thread);
  2879. // The 32bit TEB needs to be set if this is a WOW64 process on a 64BIT system.
  2880. // This code isn't 100% correct since threads have a conversion state where they
  2881. // are chaning from 64 to 32 and they don't have a TEB32 yet. Fortunatly, the slots
  2882. // will be zero when the thread is created so no damage is done by not clearing it here.
  2883. // Note that the test for the process type is inside the inner loop. This
  2884. // is bad programming, but this function is hardly time constrained and
  2885. // fixing this with complex macros would not be worth it due to the loss of clairity.
  2886. for (Thread = PsGetNextProcessThread (Process, NULL);
  2887. Thread != NULL;
  2888. Thread = PsGetNextProcessThread (Process, Thread)) {
  2889. //
  2890. // We are doing cross thread TEB references and need to prevent TEB deletion.
  2891. //
  2892. if (ExAcquireRundownProtection (&Thread->RundownProtect)) {
  2893. Teb = Thread->Tcb.Teb;
  2894. if (Teb != NULL) {
  2895. try {
  2896. #if defined(_WIN64)
  2897. PTEB32 Teb32 = NULL;
  2898. PLONG ExpansionSlots32;
  2899. if (Process->Wow64Process) { //wow64 process
  2900. Teb32 = WOW64_GET_TEB32(Teb); //No probing needed on regular TEB.
  2901. }
  2902. #endif
  2903. if ( TlsIndex > TLS_MINIMUM_AVAILABLE-1 ) {
  2904. if ( TlsIndex < (TLS_MINIMUM_AVAILABLE+TLS_EXPANSION_SLOTS) - 1 ) {
  2905. //
  2906. // This is an expansion slot, so see if the thread
  2907. // has an expansion cell
  2908. //
  2909. #if defined(_WIN64)
  2910. if (Process->Wow64Process) { //Wow64 process.
  2911. if (Teb32) {
  2912. ExpansionSlots32 = ULongToPtr(ProbeAndReadUlong(&(Teb32->TlsExpansionSlots)));
  2913. if (ExpansionSlots32) {
  2914. ProbeAndWriteLong(ExpansionSlots32 + TlsIndex - TLS_MINIMUM_AVAILABLE, 0);
  2915. }
  2916. }
  2917. }
  2918. else
  2919. #endif
  2920. {
  2921. ExpansionSlots = Teb->TlsExpansionSlots;
  2922. ProbeForReadSmallStructure (ExpansionSlots, TLS_EXPANSION_SLOTS*4, 8);
  2923. if ( ExpansionSlots ) {
  2924. ExpansionSlots[TlsIndex-TLS_MINIMUM_AVAILABLE] = 0;
  2925. }
  2926. }
  2927. }
  2928. } else {
  2929. #if defined(_WIN64)
  2930. if (Process->Wow64Process) { //wow64 process
  2931. if(Teb32) {
  2932. ProbeAndWriteUlong(Teb32->TlsSlots + TlsIndex, 0);
  2933. }
  2934. }
  2935. else
  2936. #endif
  2937. {
  2938. Teb->TlsSlots[TlsIndex] = NULL;
  2939. }
  2940. }
  2941. } except (EXCEPTION_EXECUTE_HANDLER) {
  2942. }
  2943. }
  2944. ExReleaseRundownProtection (&Thread->RundownProtect);
  2945. }
  2946. }
  2947. }
  2948. return st;
  2949. break;
  2950. case ThreadSetTlsArrayAddress:
  2951. if ( ThreadInformationLength != sizeof(PVOID) ) {
  2952. return STATUS_INFO_LENGTH_MISMATCH;
  2953. }
  2954. try {
  2955. TlsArrayAddress = *(PVOID *)ThreadInformation;
  2956. } except (EXCEPTION_EXECUTE_HANDLER) {
  2957. return GetExceptionCode();
  2958. }
  2959. st = ObReferenceObjectByHandle(
  2960. ThreadHandle,
  2961. THREAD_SET_INFORMATION,
  2962. PsThreadType,
  2963. PreviousMode,
  2964. (PVOID *)&Thread,
  2965. NULL
  2966. );
  2967. if ( !NT_SUCCESS(st) ) {
  2968. return st;
  2969. }
  2970. Thread->Tcb.TlsArray = TlsArrayAddress;
  2971. ObDereferenceObject(Thread);
  2972. return st;
  2973. break;
  2974. case ThreadHideFromDebugger:
  2975. if (ThreadInformationLength != 0) {
  2976. return STATUS_INFO_LENGTH_MISMATCH;
  2977. }
  2978. st = ObReferenceObjectByHandle (ThreadHandle,
  2979. THREAD_SET_INFORMATION,
  2980. PsThreadType,
  2981. PreviousMode,
  2982. &Thread,
  2983. NULL);
  2984. if (!NT_SUCCESS (st)) {
  2985. return st;
  2986. }
  2987. PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_HIDEFROMDBG);
  2988. ObDereferenceObject(Thread);
  2989. return st;
  2990. break;
  2991. case ThreadBreakOnTermination:
  2992. if (ThreadInformationLength != sizeof (ULONG)) {
  2993. return STATUS_INFO_LENGTH_MISMATCH;
  2994. }
  2995. try {
  2996. EnableBreakOnTermination = *(PULONG)ThreadInformation;
  2997. } except (EXCEPTION_EXECUTE_HANDLER) {
  2998. return GetExceptionCode();
  2999. }
  3000. if (!SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)) {
  3001. return STATUS_PRIVILEGE_NOT_HELD;
  3002. }
  3003. st = ObReferenceObjectByHandle(
  3004. ThreadHandle,
  3005. THREAD_SET_INFORMATION,
  3006. PsThreadType,
  3007. PreviousMode,
  3008. (PVOID *)&Thread,
  3009. NULL
  3010. );
  3011. if (!NT_SUCCESS (st)) {
  3012. return st;
  3013. }
  3014. if ( EnableBreakOnTermination ) {
  3015. PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_BREAK_ON_TERMINATION);
  3016. } else {
  3017. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_BREAK_ON_TERMINATION);
  3018. }
  3019. ObDereferenceObject(Thread);
  3020. return STATUS_SUCCESS;
  3021. default:
  3022. return STATUS_INVALID_INFO_CLASS;
  3023. }
  3024. }
  3025. VOID
  3026. PsWatchWorkingSet(
  3027. IN NTSTATUS Status,
  3028. IN PVOID PcValue,
  3029. IN PVOID Va
  3030. )
  3031. /*++
  3032. Routine Description:
  3033. This function collects data about page faults and stores information
  3034. about the page fault in the current process's data structure.
  3035. Arguments:
  3036. Status - Supplies the success completion status.
  3037. PcValue - Supplies the instruction address that caused the page fault.
  3038. Va - Supplies the virtual address that caused the page fault.
  3039. --*/
  3040. {
  3041. PEPROCESS Process;
  3042. PPAGEFAULT_HISTORY WorkingSetCatcher;
  3043. KIRQL OldIrql;
  3044. BOOLEAN TransitionFault = FALSE;
  3045. //
  3046. // Both transition and demand zero faults count as soft faults. Only disk
  3047. // reads count as hard faults.
  3048. //
  3049. if ( Status <= STATUS_PAGE_FAULT_DEMAND_ZERO ) {
  3050. TransitionFault = TRUE;
  3051. }
  3052. Process = PsGetCurrentProcess();
  3053. WorkingSetCatcher = Process->WorkingSetWatch;
  3054. if (WorkingSetCatcher == NULL) {
  3055. return;
  3056. }
  3057. ExAcquireSpinLock(&WorkingSetCatcher->SpinLock,&OldIrql);
  3058. if (WorkingSetCatcher->CurrentIndex >= WorkingSetCatcher->MaxIndex) {
  3059. ExReleaseSpinLock(&WorkingSetCatcher->SpinLock,OldIrql);
  3060. return;
  3061. }
  3062. //
  3063. // Store the Pc and Va values in the buffer. Use the least sig. bit
  3064. // of the Va to store whether it was a soft or hard fault
  3065. //
  3066. WorkingSetCatcher->WatchInfo[WorkingSetCatcher->CurrentIndex].FaultingPc = PcValue;
  3067. WorkingSetCatcher->WatchInfo[WorkingSetCatcher->CurrentIndex].FaultingVa = TransitionFault ? (PVOID)((ULONG_PTR)Va | 1) : (PVOID)((ULONG_PTR)Va & 0xfffffffe) ;
  3068. WorkingSetCatcher->CurrentIndex++;
  3069. ExReleaseSpinLock(&WorkingSetCatcher->SpinLock,OldIrql);
  3070. return;
  3071. }
  3072. #ifdef ALLOC_DATA_PRAGMA
  3073. #pragma data_seg("PAGEDATA")
  3074. #endif
  3075. PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout = NULL;
  3076. PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL;
  3077. PKWIN32_JOB_CALLOUT PspW32JobCallout = NULL;
  3078. #ifdef ALLOC_DATA_PRAGMA
  3079. #pragma data_seg()
  3080. #endif
  3081. extern PKWIN32_POWEREVENT_CALLOUT PopEventCallout;
  3082. extern PKWIN32_POWERSTATE_CALLOUT PopStateCallout;
  3083. NTKERNELAPI
  3084. VOID
  3085. PsEstablishWin32Callouts(
  3086. IN PKWIN32_CALLOUTS_FPNS pWin32Callouts )
  3087. /*++
  3088. Routine Description:
  3089. This function is used by the Win32 kernel mode component to
  3090. register callout functions for process/thread init/deinit functions
  3091. and to report the sizes of the structures.
  3092. Arguments:
  3093. ProcessCallout - Supplies the address of the function to be called when
  3094. a process is either created or deleted.
  3095. ThreadCallout - Supplies the address of the function to be called when
  3096. a thread is either created or deleted.
  3097. GlobalAtomTableCallout - Supplies the address of the function to be called
  3098. to get the correct global atom table for the current process
  3099. PowerEventCallout - Supplies the address of a function to be called when
  3100. a power event occurs.
  3101. PowerStateCallout - Supplies the address of a function to be called when
  3102. the power state changes.
  3103. JobCallout - Supplies the address of a function to be called when
  3104. the job state changes or a process is assigned to a job.
  3105. BatchFlushRoutine - Supplies the address of the function to be called
  3106. Return Value:
  3107. None.
  3108. --*/
  3109. {
  3110. PAGED_CODE();
  3111. PspW32ProcessCallout = pWin32Callouts->ProcessCallout;
  3112. PspW32ThreadCallout = pWin32Callouts->ThreadCallout;
  3113. ExGlobalAtomTableCallout = pWin32Callouts->GlobalAtomTableCallout;
  3114. KeGdiFlushUserBatch = (PGDI_BATCHFLUSH_ROUTINE)pWin32Callouts->BatchFlushRoutine;
  3115. PopEventCallout = pWin32Callouts->PowerEventCallout;
  3116. PopStateCallout = pWin32Callouts->PowerStateCallout;
  3117. PspW32JobCallout = pWin32Callouts->JobCallout;
  3118. // PoSetSystemState(ES_SYSTEM_REQUIRED);
  3119. ExDesktopOpenProcedureCallout = pWin32Callouts->DesktopOpenProcedure;
  3120. ExDesktopOkToCloseProcedureCallout = pWin32Callouts->DesktopOkToCloseProcedure;
  3121. ExDesktopCloseProcedureCallout = pWin32Callouts->DesktopCloseProcedure;
  3122. ExDesktopDeleteProcedureCallout = pWin32Callouts->DesktopDeleteProcedure;
  3123. ExWindowStationOkToCloseProcedureCallout = pWin32Callouts->WindowStationOkToCloseProcedure;
  3124. ExWindowStationCloseProcedureCallout = pWin32Callouts->WindowStationCloseProcedure;
  3125. ExWindowStationDeleteProcedureCallout = pWin32Callouts->WindowStationDeleteProcedure;
  3126. ExWindowStationParseProcedureCallout = pWin32Callouts->WindowStationParseProcedure;
  3127. ExWindowStationOpenProcedureCallout = pWin32Callouts->WindowStationOpenProcedure;
  3128. }
  3129. VOID
  3130. PsSetProcessPriorityByClass(
  3131. IN PEPROCESS Process,
  3132. IN PSPROCESSPRIORITYMODE PriorityMode
  3133. )
  3134. {
  3135. KPRIORITY BasePriority;
  3136. UCHAR MemoryPriority;
  3137. ULONG QuantumIndex;
  3138. PEJOB Job;
  3139. PAGED_CODE();
  3140. BasePriority = PspPriorityTable[Process->PriorityClass];
  3141. if (PriorityMode == PsProcessPriorityForeground ) {
  3142. QuantumIndex = PsPrioritySeperation;
  3143. MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
  3144. } else {
  3145. QuantumIndex = 0;
  3146. MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
  3147. }
  3148. if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE) {
  3149. Job = Process->Job;
  3150. if (Job != NULL && PspUseJobSchedulingClasses ) {
  3151. Process->Pcb.ThreadQuantum = PspJobSchedulingClasses[Job->SchedulingClass];
  3152. } else {
  3153. Process->Pcb.ThreadQuantum = PspForegroundQuantum[QuantumIndex];
  3154. }
  3155. } else {
  3156. Process->Pcb.ThreadQuantum = THREAD_QUANTUM;
  3157. }
  3158. KeSetPriorityProcess (&Process->Pcb,BasePriority);
  3159. if (PriorityMode != PsProcessPrioritySpinning ) {
  3160. MmSetMemoryPriorityProcess(Process, MemoryPriority);
  3161. }
  3162. }
  3163. #if defined(_X86_)
  3164. #pragma optimize ("y",off)
  3165. #endif
  3166. NTSTATUS
  3167. PsConvertToGuiThread(
  3168. VOID
  3169. )
  3170. /*++
  3171. Routine Description:
  3172. This function converts a thread to a GUI thread. This involves giving the
  3173. thread a larger variable sized stack, and allocating appropriate w32
  3174. thread and process objects.
  3175. Arguments:
  3176. None.
  3177. Environment:
  3178. On x86 this function needs to build an EBP frame. The function
  3179. KeSwitchKernelStack depends on this fact. The '#pragma optimize
  3180. ("y",off)' below disables frame pointer omission for all builds.
  3181. Return Value:
  3182. TBD
  3183. --*/
  3184. {
  3185. PVOID NewStack;
  3186. PVOID OldStack;
  3187. PETHREAD Thread;
  3188. PEPROCESS Process;
  3189. NTSTATUS Status;
  3190. PAGED_CODE();
  3191. Thread = PsGetCurrentThread();
  3192. if (KeGetPreviousModeByThread(&Thread->Tcb) == KernelMode) {
  3193. return STATUS_INVALID_PARAMETER;
  3194. }
  3195. if (!PspW32ProcessCallout) {
  3196. return STATUS_ACCESS_DENIED;
  3197. }
  3198. //
  3199. // If the thread is using the shadow service table, then an attempt is
  3200. // being made to convert a thread that has already been converted, or
  3201. // a limit violation has occured on the Win32k system service table.
  3202. //
  3203. if (Thread->Tcb.ServiceTable != (PVOID)&KeServiceDescriptorTable[0]) {
  3204. return STATUS_ALREADY_WIN32;
  3205. }
  3206. Process = PsGetCurrentProcessByThread (Thread);
  3207. //
  3208. // Get a larger kernel stack if we haven't already.
  3209. //
  3210. if (!Thread->Tcb.LargeStack) {
  3211. NewStack = MmCreateKernelStack(TRUE, Thread->Tcb.InitialNode);
  3212. if ( !NewStack ) {
  3213. try {
  3214. NtCurrentTeb()->LastErrorValue = (LONG)ERROR_NOT_ENOUGH_MEMORY;
  3215. } except (EXCEPTION_EXECUTE_HANDLER) {
  3216. }
  3217. return STATUS_NO_MEMORY;
  3218. }
  3219. #if defined(_IA64_)
  3220. OldStack = KeSwitchKernelStack(NewStack,
  3221. (UCHAR *)NewStack - KERNEL_LARGE_STACK_COMMIT,
  3222. (UCHAR *)NewStack + KERNEL_LARGE_BSTORE_COMMIT);
  3223. #else
  3224. OldStack = KeSwitchKernelStack(NewStack,
  3225. (UCHAR *)NewStack - KERNEL_LARGE_STACK_COMMIT);
  3226. #endif // defined(_IA64_)
  3227. MmDeleteKernelStack(OldStack, FALSE);
  3228. }
  3229. PERFINFO_CONVERT_TO_GUI_THREAD(Thread);
  3230. //
  3231. // We are all clean on the stack, now call out and then link the Win32 structures
  3232. // to the base exec structures
  3233. //
  3234. Status = (PspW32ProcessCallout) (Process, TRUE);
  3235. if (!NT_SUCCESS (Status)) {
  3236. return Status;
  3237. }
  3238. //
  3239. // Switch the thread to use the shadow system serive table which will
  3240. // enable it to execute Win32k services.
  3241. //
  3242. Thread->Tcb.ServiceTable = (PVOID)&KeServiceDescriptorTableShadow[0];
  3243. ASSERT (Thread->Tcb.Win32Thread == 0);
  3244. //
  3245. // Make the thread callout.
  3246. //
  3247. Status = (PspW32ThreadCallout)(Thread,PsW32ThreadCalloutInitialize);
  3248. if (!NT_SUCCESS (Status)) {
  3249. Thread->Tcb.ServiceTable = (PVOID)&KeServiceDescriptorTable[0];
  3250. }
  3251. return Status;
  3252. }
  3253. #if defined(_X86_)
  3254. #pragma optimize ("y",on)
  3255. #endif