2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Process Manager: Thread/Process Query/Set Information
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
20 ULONG PspTraceLevel
= 0;
22 /* PRIVATE FUNCTIONS *********************************************************/
26 PsReferenceProcessFilePointer(IN PEPROCESS Process
,
27 OUT PFILE_OBJECT
*FileObject
)
32 /* Lock the process */
33 ExAcquireRundownProtection(&Process
->RundownProtect
);
36 Section
= Process
->SectionObject
;
39 /* Get the file object and reference it */
40 *FileObject
= MmGetFileObjectForSection((PVOID
)Section
);
41 ObReferenceObject(*FileObject
);
44 /* Release the protection */
45 ExReleaseRundownProtection(&Process
->RundownProtect
);
48 return Section
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
51 /* PUBLIC FUNCTIONS **********************************************************/
58 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
59 IN PROCESSINFOCLASS ProcessInformationClass
,
60 OUT PVOID ProcessInformation
,
61 IN ULONG ProcessInformationLength
,
62 OUT PULONG ReturnLength OPTIONAL
)
65 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
66 NTSTATUS Status
= STATUS_SUCCESS
;
68 PPROCESS_BASIC_INFORMATION ProcessBasicInfo
=
69 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
70 PKERNEL_USER_TIMES ProcessTime
= (PKERNEL_USER_TIMES
)ProcessInformation
;
72 PPROCESS_SESSION_INFORMATION SessionInfo
=
73 (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
74 PVM_COUNTERS VmCounters
= (PVM_COUNTERS
)ProcessInformation
;
75 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
76 PUNICODE_STRING ImageName
;
80 /* Check validity of Information Class */
82 Status
= DefaultQueryInfoBufferCheck(ProcessInformationClass
,
84 RTL_NUMBER_OF(PsProcessInfoClass
),
86 ProcessInformationLength
,
89 if (!NT_SUCCESS(Status
)) return Status
;
92 if((ProcessInformationClass
== ProcessCookie
) &&
93 (ProcessHandle
!= NtCurrentProcess()))
96 * Retreiving the process cookie is only allowed for the calling process
97 * itself! XP only allowes NtCurrentProcess() as process handles even if
98 * a real handle actually represents the current process.
100 return STATUS_INVALID_PARAMETER
;
103 /* Check the information class */
104 switch (ProcessInformationClass
)
106 /* Basic process information */
107 case ProcessBasicInformation
:
109 /* Set return length */
110 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
112 if (ProcessInformationLength
!= Length
)
114 Status
= STATUS_INFO_LENGTH_MISMATCH
;
118 /* Reference the process */
119 Status
= ObReferenceObjectByHandle(ProcessHandle
,
120 PROCESS_QUERY_INFORMATION
,
125 if (!NT_SUCCESS(Status
)) break;
127 /* Protect writes with SEH */
130 /* Write all the information from the EPROCESS/KPROCESS */
131 ProcessBasicInfo
->ExitStatus
= Process
->ExitStatus
;
132 ProcessBasicInfo
->PebBaseAddress
= Process
->Peb
;
133 ProcessBasicInfo
->AffinityMask
= Process
->Pcb
.Affinity
;
134 ProcessBasicInfo
->UniqueProcessId
= (ULONG_PTR
)Process
->
136 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
137 (ULONG_PTR
)Process
->InheritedFromUniqueProcessId
;
138 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
143 /* Get exception code */
144 Status
= _SEH2_GetExceptionCode();
148 /* Dereference the process */
149 ObDereferenceObject(Process
);
152 /* Quote limits and I/O Counters: not implemented */
153 case ProcessQuotaLimits
:
154 case ProcessIoCounters
:
156 Length
= sizeof(IO_COUNTERS
);
157 if (ProcessInformationLength
!= Length
)
159 Status
= STATUS_INFO_LENGTH_MISMATCH
;
163 /* Reference the process */
164 Status
= ObReferenceObjectByHandle(ProcessHandle
,
165 PROCESS_QUERY_INFORMATION
,
170 if (!NT_SUCCESS(Status
)) break;
172 Status
= STATUS_NOT_IMPLEMENTED
;
173 /* Dereference the process */
174 ObDereferenceObject(Process
);
180 /* Set the return length */
181 Length
= sizeof(KERNEL_USER_TIMES
);
183 if (ProcessInformationLength
!= Length
)
185 Status
= STATUS_INFO_LENGTH_MISMATCH
;
189 /* Reference the process */
190 Status
= ObReferenceObjectByHandle(ProcessHandle
,
191 PROCESS_QUERY_INFORMATION
,
196 if (!NT_SUCCESS(Status
)) break;
198 /* Protect writes with SEH */
201 /* Copy time information from EPROCESS/KPROCESS */
202 ProcessTime
->CreateTime
= Process
->CreateTime
;
203 ProcessTime
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
*
205 ProcessTime
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
*
207 ProcessTime
->ExitTime
= Process
->ExitTime
;
209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
211 /* Get exception code */
212 Status
= _SEH2_GetExceptionCode();
216 /* Dereference the process */
217 ObDereferenceObject(Process
);
220 /* Process Debug Port */
221 case ProcessDebugPort
:
223 /* Set return length */
224 Length
= sizeof(HANDLE
);
226 if (ProcessInformationLength
!= Length
)
228 Status
= STATUS_INFO_LENGTH_MISMATCH
;
232 /* Reference the process */
233 Status
= ObReferenceObjectByHandle(ProcessHandle
,
234 PROCESS_QUERY_INFORMATION
,
239 if (!NT_SUCCESS(Status
)) break;
241 /* Protect write with SEH */
244 /* Return whether or not we have a debug port */
245 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
?
248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
250 /* Get exception code */
251 Status
= _SEH2_GetExceptionCode();
255 /* Dereference the process */
256 ObDereferenceObject(Process
);
259 /* LDT, WS and VDM Information: not implemented */
260 case ProcessLdtInformation
:
261 case ProcessWorkingSetWatch
:
262 case ProcessWx86Information
:
263 Status
= STATUS_NOT_IMPLEMENTED
;
266 case ProcessHandleCount
:
268 /* Set the return length*/
269 Length
= sizeof(ULONG
);
271 if (ProcessInformationLength
!= Length
)
273 Status
= STATUS_INFO_LENGTH_MISMATCH
;
277 /* Reference the process */
278 Status
= ObReferenceObjectByHandle(ProcessHandle
,
279 PROCESS_QUERY_INFORMATION
,
284 if (!NT_SUCCESS(Status
)) break;
286 /* Count the number of handles this process has */
287 HandleCount
= ObGetProcessHandleCount(Process
);
289 /* Protect write in SEH */
292 /* Return the count of handles */
293 *(PULONG
)ProcessInformation
= HandleCount
;
295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
297 /* Get the exception code */
298 Status
= _SEH2_GetExceptionCode();
302 /* Dereference the process */
303 ObDereferenceObject(Process
);
306 /* Session ID for the process */
307 case ProcessSessionInformation
:
309 /* Set the return length*/
310 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
312 if (ProcessInformationLength
!= Length
)
314 Status
= STATUS_INFO_LENGTH_MISMATCH
;
318 /* Reference the process */
319 Status
= ObReferenceObjectByHandle(ProcessHandle
,
320 PROCESS_QUERY_INFORMATION
,
325 if (!NT_SUCCESS(Status
)) break;
327 /* Enter SEH for write safety */
330 /* Write back the Session ID */
331 SessionInfo
->SessionId
= PtrToUlong(Process
->Session
);
333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
335 /* Get the exception code */
336 Status
= _SEH2_GetExceptionCode();
340 /* Dereference the process */
341 ObDereferenceObject(Process
);
344 /* WOW64: Not implemented */
345 case ProcessWow64Information
:
346 Status
= STATUS_NOT_IMPLEMENTED
;
349 /* Virtual Memory Statistics */
350 case ProcessVmCounters
:
352 /* Set the return length */
353 Length
= sizeof(VM_COUNTERS
);
355 if (ProcessInformationLength
!= Length
)
357 Status
= STATUS_INFO_LENGTH_MISMATCH
;
361 /* Reference the process */
362 Status
= ObReferenceObjectByHandle(ProcessHandle
,
363 PROCESS_QUERY_INFORMATION
,
368 if (!NT_SUCCESS(Status
)) break;
370 /* Enter SEH for write safety */
373 /* Return data from EPROCESS */
374 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
375 VmCounters
->VirtualSize
= Process
->VirtualSize
;
376 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
377 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
378 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
379 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
380 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
381 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
382 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
383 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2];
384 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2];
387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
389 /* Get the exception code */
390 Status
= _SEH2_GetExceptionCode();
394 /* Dereference the process */
395 ObDereferenceObject(Process
);
398 /* Hard Error Processing Mode */
399 case ProcessDefaultHardErrorMode
:
401 /* Set the return length*/
402 Length
= sizeof(ULONG
);
404 if (ProcessInformationLength
!= Length
)
406 Status
= STATUS_INFO_LENGTH_MISMATCH
;
410 /* Reference the process */
411 Status
= ObReferenceObjectByHandle(ProcessHandle
,
412 PROCESS_QUERY_INFORMATION
,
417 if (!NT_SUCCESS(Status
)) break;
419 /* Enter SEH for writing back data */
422 /* Write the current processing mode */
423 *(PULONG
)ProcessInformation
= Process
->
424 DefaultHardErrorProcessing
;
426 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
428 /* Get the exception code */
429 Status
= _SEH2_GetExceptionCode();
433 /* Dereference the process */
434 ObDereferenceObject(Process
);
437 /* Priority Boosting status */
438 case ProcessPriorityBoost
:
440 /* Set the return length*/
441 Length
= sizeof(ULONG
);
443 if (ProcessInformationLength
!= Length
)
445 Status
= STATUS_INFO_LENGTH_MISMATCH
;
449 /* Reference the process */
450 Status
= ObReferenceObjectByHandle(ProcessHandle
,
451 PROCESS_QUERY_INFORMATION
,
456 if (!NT_SUCCESS(Status
)) break;
458 /* Enter SEH for writing back data */
461 /* Return boost status */
462 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
467 /* Get the exception code */
468 Status
= _SEH2_GetExceptionCode();
472 /* Dereference the process */
473 ObDereferenceObject(Process
);
477 case ProcessDeviceMap
:
479 /* Set the return length*/
480 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
482 if (ProcessInformationLength
!= Length
)
484 Status
= STATUS_INFO_LENGTH_MISMATCH
;
488 /* Reference the process */
489 Status
= ObReferenceObjectByHandle(ProcessHandle
,
490 PROCESS_QUERY_INFORMATION
,
495 if (!NT_SUCCESS(Status
)) break;
497 /* Query the device map information */
498 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
500 /* Enter SEH for writing back data */
503 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
507 /* Get the exception code */
508 Status
= _SEH2_GetExceptionCode();
512 /* Dereference the process */
513 ObDereferenceObject(Process
);
517 case ProcessPriorityClass
:
519 /* Set the return length*/
520 Length
= sizeof(USHORT
);
522 if (ProcessInformationLength
!= Length
)
524 Status
= STATUS_INFO_LENGTH_MISMATCH
;
528 /* Reference the process */
529 Status
= ObReferenceObjectByHandle(ProcessHandle
,
530 PROCESS_QUERY_INFORMATION
,
535 if (!NT_SUCCESS(Status
)) break;
537 /* Enter SEH for writing back data */
540 /* Return current priority class */
541 *(PUSHORT
)ProcessInformation
= Process
->PriorityClass
;
543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
545 /* Get the exception code */
546 Status
= _SEH2_GetExceptionCode();
550 /* Dereference the process */
551 ObDereferenceObject(Process
);
554 case ProcessImageFileName
:
556 /* Reference the process */
557 Status
= ObReferenceObjectByHandle(ProcessHandle
,
558 PROCESS_QUERY_INFORMATION
,
563 if (!NT_SUCCESS(Status
)) break;
565 /* Get the image path */
566 Status
= SeLocateProcessImageName(Process
, &ImageName
);
567 if (NT_SUCCESS(Status
))
569 /* Set return length */
570 Length
= ImageName
->MaximumLength
+
571 sizeof(OBJECT_NAME_INFORMATION
);
573 /* Make sure it's large enough */
574 if (Length
<= ProcessInformationLength
)
576 /* Enter SEH to protect write */
580 RtlCopyMemory(ProcessInformation
,
585 ((PUNICODE_STRING
)ProcessInformation
)->Buffer
=
586 (PWSTR
)((PUNICODE_STRING
)ProcessInformation
+ 1);
588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
590 /* Get the exception code */
591 Status
= _SEH2_GetExceptionCode();
597 /* Buffer too small */
598 Status
= STATUS_INFO_LENGTH_MISMATCH
;
601 /* Free the image path */
602 ExFreePool(ImageName
);
604 /* Dereference the process */
605 ObDereferenceObject(Process
);
608 /* Per-process security cookie */
611 /* Get the current process and cookie */
612 Process
= PsGetCurrentProcess();
613 Cookie
= Process
->Cookie
;
616 LARGE_INTEGER SystemTime
;
620 /* Generate a new cookie */
621 KeQuerySystemTime(&SystemTime
);
622 Prcb
= KeGetCurrentPrcb();
623 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
624 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
626 /* Set the new cookie or return the current one */
627 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
630 if (!Cookie
) Cookie
= NewCookie
;
632 /* Set return length */
633 Length
= sizeof(ULONG
);
636 /* Enter SEH to protect write */
639 /* Write back the cookie */
640 *(PULONG
)ProcessInformation
= Cookie
;
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
644 /* Get the exception code */
645 Status
= _SEH2_GetExceptionCode();
650 /* Not yet implemented, or unknown */
651 case ProcessBasePriority
:
652 case ProcessRaisePriority
:
653 case ProcessExceptionPort
:
654 case ProcessAccessToken
:
656 case ProcessIoPortHandlers
:
657 case ProcessUserModeIOPL
:
658 case ProcessEnableAlignmentFaultFixup
:
659 case ProcessAffinityMask
:
660 case ProcessForegroundInformation
:
662 Status
= STATUS_INVALID_INFO_CLASS
;
665 /* Protect write with SEH */
668 /* Check if caller wanted return length */
669 if (ReturnLength
) *ReturnLength
= Length
;
671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
673 /* Get exception code */
674 Status
= _SEH2_GetExceptionCode();
686 NtSetInformationProcess(IN HANDLE ProcessHandle
,
687 IN PROCESSINFOCLASS ProcessInformationClass
,
688 IN PVOID ProcessInformation
,
689 IN ULONG ProcessInformationLength
)
692 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
695 HANDLE PortHandle
= NULL
;
696 HANDLE TokenHandle
= NULL
;
697 PROCESS_SESSION_INFORMATION SessionInfo
= {0};
701 /* Verify Information Class validity */
703 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
705 RTL_NUMBER_OF(PsProcessInfoClass
),
707 ProcessInformationLength
,
709 if (!NT_SUCCESS(Status
)) return Status
;
712 /* Check what class this is */
713 Access
= PROCESS_SET_INFORMATION
;
714 if (ProcessInformationClass
== ProcessSessionInformation
)
716 /* Setting the Session ID needs a special mask */
717 Access
|= PROCESS_SET_SESSIONID
;
719 else if (ProcessInformationClass
== ProcessExceptionPort
)
721 /* Setting the exception port needs a special mask */
722 Access
|= PROCESS_SUSPEND_RESUME
;
725 /* Reference the process */
726 Status
= ObReferenceObjectByHandle(ProcessHandle
,
732 if (!NT_SUCCESS(Status
)) return Status
;
734 /* Check what kind of information class this is */
735 switch (ProcessInformationClass
)
737 /* Quotas and priorities: not implemented */
738 case ProcessQuotaLimits
:
739 case ProcessBasePriority
:
740 case ProcessRaisePriority
:
741 Status
= STATUS_NOT_IMPLEMENTED
;
744 /* Error/Exception Port */
745 case ProcessExceptionPort
:
747 /* Use SEH for capture */
750 /* Capture the handle */
751 PortHandle
= *(PHANDLE
)ProcessInformation
;
753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
755 /* Get the exception code */
756 Status
= _SEH2_GetExceptionCode();
759 if (!NT_SUCCESS(Status
)) break;
761 /* Get the LPC Port */
762 Status
= ObReferenceObjectByHandle(PortHandle
,
766 (PVOID
)&ExceptionPort
,
768 if (!NT_SUCCESS(Status
)) break;
770 /* Change the pointer */
771 if (InterlockedCompareExchangePointer(&Process
->ExceptionPort
,
775 /* We already had one, fail */
776 ObDereferenceObject(ExceptionPort
);
777 Status
= STATUS_PORT_ALREADY_SET
;
782 case ProcessAccessToken
:
784 /* Use SEH for capture */
787 /* Save the token handle */
788 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->
791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
793 /* Get the exception code */
794 Status
= _SEH2_GetExceptionCode();
797 if (!NT_SUCCESS(Status
)) break;
799 /* Assign the actual token */
800 Status
= PspSetPrimaryToken(Process
, TokenHandle
, NULL
);
803 /* Hard error processing */
804 case ProcessDefaultHardErrorMode
:
806 /* Enter SEH for direct buffer read */
809 /* Update the current mode abd return the previous one */
810 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
811 *(PLONG
)ProcessInformation
);
813 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
815 /* Get exception code */
816 Status
= _SEH2_GetExceptionCode();
822 case ProcessSessionInformation
:
824 /* Enter SEH for capture */
827 /* Capture the caller's buffer */
828 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
830 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
832 /* Get the exception code */
833 Status
= _SEH2_GetExceptionCode();
836 if (!NT_SUCCESS(Status
)) break;
838 /* Setting the session id requires the SeTcbPrivilege */
839 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
841 /* Can't set the session ID, bail out. */
842 Status
= STATUS_PRIVILEGE_NOT_HELD
;
846 /* FIXME - update the session id for the process token */
847 //Status = PsLockProcess(Process, FALSE);
848 if (!NT_SUCCESS(Status
)) break;
850 /* Write the session ID in the EPROCESS */
851 Process
->Session
= SessionInfo
.SessionId
;
853 /* Check if the process also has a PEB */
857 * Attach to the process to make sure we're in the right
858 * context to access the PEB structure
860 KeAttachProcess(&Process
->Pcb
);
862 /* Enter SEH for write to user-mode PEB */
865 /* Write the session ID */
866 Process
->Peb
->SessionId
= SessionInfo
.SessionId
;
868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
870 /* Get exception code */
871 Status
= _SEH2_GetExceptionCode();
875 /* Detach from the process */
879 /* Unlock the process */
880 //PsUnlockProcess(Process);
883 /* Priority class: HACK! */
884 case ProcessPriorityClass
:
887 /* We currently don't implement any of these */
888 case ProcessLdtInformation
:
890 case ProcessIoPortHandlers
:
891 case ProcessWorkingSetWatch
:
892 case ProcessUserModeIOPL
:
893 case ProcessEnableAlignmentFaultFixup
:
894 case ProcessAffinityMask
:
895 Status
= STATUS_NOT_IMPLEMENTED
;
898 /* Supposedly these are invalid...!? verify! */
899 case ProcessBasicInformation
:
900 case ProcessIoCounters
:
902 case ProcessPooledUsageAndLimits
:
903 case ProcessWx86Information
:
904 case ProcessHandleCount
:
905 case ProcessWow64Information
:
906 case ProcessDebugPort
:
908 Status
= STATUS_INVALID_INFO_CLASS
;
911 /* Dereference and return status */
912 ObDereferenceObject(Process
);
921 NtSetInformationThread(IN HANDLE ThreadHandle
,
922 IN THREADINFOCLASS ThreadInformationClass
,
923 IN PVOID ThreadInformation
,
924 IN ULONG ThreadInformationLength
)
928 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
930 HANDLE TokenHandle
= NULL
;
931 KPRIORITY Priority
= 0;
932 KAFFINITY Affinity
= 0, CombinedAffinity
;
933 PVOID Address
= NULL
;
935 ULONG DisableBoost
= 0;
936 ULONG IdealProcessor
= 0;
939 PVOID
*ExpansionSlots
;
943 /* Verify Information Class validity */
945 Status
= DefaultSetInfoBufferCheck(ThreadInformationClass
,
947 RTL_NUMBER_OF(PsThreadInfoClass
),
949 ThreadInformationLength
,
951 if (!NT_SUCCESS(Status
)) return Status
;
954 /* Check what class this is */
955 Access
= THREAD_SET_INFORMATION
;
956 if (ThreadInformationClass
== ThreadImpersonationToken
)
958 /* Setting the impersonation token needs a special mask */
959 Access
= THREAD_SET_THREAD_TOKEN
;
962 /* Reference the process */
963 Status
= ObReferenceObjectByHandle(ThreadHandle
,
969 if (!NT_SUCCESS(Status
)) return Status
;
971 /* Check what kind of information class this is */
972 switch (ThreadInformationClass
)
974 /* Thread priority */
977 /* Use SEH for capture */
980 /* Get the priority */
981 Priority
= *(PLONG
)ThreadInformation
;
983 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
985 /* Get the exception code */
986 Status
= _SEH2_GetExceptionCode();
989 if (!NT_SUCCESS(Status
)) break;
992 if ((Priority
> HIGH_PRIORITY
) ||
993 (Priority
<= LOW_PRIORITY
))
996 Status
= STATUS_INVALID_PARAMETER
;
1000 /* Set the priority */
1001 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
1004 case ThreadBasePriority
:
1006 /* Use SEH for capture */
1009 /* Get the priority */
1010 Priority
= *(PLONG
)ThreadInformation
;
1012 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1014 /* Get the exception code */
1015 Status
= _SEH2_GetExceptionCode();
1018 if (!NT_SUCCESS(Status
)) break;
1021 if ((Priority
> THREAD_BASE_PRIORITY_MAX
) ||
1022 (Priority
< THREAD_BASE_PRIORITY_MIN
))
1024 /* These ones are OK */
1025 if ((Priority
!= THREAD_BASE_PRIORITY_LOWRT
+ 1) &&
1026 (Priority
!= THREAD_BASE_PRIORITY_IDLE
- 1))
1028 /* Check if the process is real time */
1029 if (PsGetCurrentProcess()->PriorityClass
!=
1030 PROCESS_PRIORITY_CLASS_REALTIME
)
1032 /* It isn't, fail */
1033 Status
= STATUS_INVALID_PARAMETER
;
1039 /* Set the base priority */
1040 KeSetBasePriorityThread(&Thread
->Tcb
, Priority
);
1043 case ThreadAffinityMask
:
1045 /* Use SEH for capture */
1048 /* Get the priority */
1049 Affinity
= *(PULONG_PTR
)ThreadInformation
;
1051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1053 /* Get the exception code */
1054 Status
= _SEH2_GetExceptionCode();
1057 if (!NT_SUCCESS(Status
)) break;
1063 Status
= STATUS_INVALID_PARAMETER
;
1067 /* Get the process */
1068 Process
= Thread
->ThreadsProcess
;
1070 /* Try to acquire rundown */
1071 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1074 KeEnterCriticalRegion();
1075 ExAcquirePushLockShared(&Process
->ProcessLock
);
1078 CombinedAffinity
= Affinity
& Process
->Pcb
.Affinity
;
1079 if (CombinedAffinity
!= Affinity
)
1082 Status
= STATUS_INVALID_PARAMETER
;
1086 /* Set the affinity */
1087 KeSetAffinityThread(&Thread
->Tcb
, CombinedAffinity
);
1090 /* Release the lock and rundown */
1091 ExReleasePushLockShared(&Process
->ProcessLock
);
1092 KeLeaveCriticalRegion();
1093 ExReleaseRundownProtection(&Process
->RundownProtect
);
1098 Status
= STATUS_PROCESS_IS_TERMINATING
;
1104 case ThreadImpersonationToken
:
1106 /* Use SEH for capture */
1109 /* Save the token handle */
1110 TokenHandle
= *(PHANDLE
)ThreadInformation
;
1112 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1114 /* Get the exception code */
1115 Status
= _SEH2_GetExceptionCode();
1118 if (!NT_SUCCESS(Status
)) break;
1120 /* Assign the actual token */
1121 Status
= PsAssignImpersonationToken(Thread
, TokenHandle
);
1124 case ThreadQuerySetWin32StartAddress
:
1126 /* Use SEH for capture */
1129 /* Get the priority */
1130 Address
= *(PVOID
*)ThreadInformation
;
1132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1134 /* Get the exception code */
1135 Status
= _SEH2_GetExceptionCode();
1138 if (!NT_SUCCESS(Status
)) break;
1140 /* Set the address */
1141 Thread
->Win32StartAddress
= Address
;
1144 case ThreadIdealProcessor
:
1146 /* Use SEH for capture */
1149 /* Get the priority */
1150 IdealProcessor
= *(PULONG_PTR
)ThreadInformation
;
1152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1154 /* Get the exception code */
1155 Status
= _SEH2_GetExceptionCode();
1158 if (!NT_SUCCESS(Status
)) break;
1161 if (IdealProcessor
> MAXIMUM_PROCESSORS
)
1164 Status
= STATUS_INVALID_PARAMETER
;
1169 Status
= KeSetIdealProcessorThread(&Thread
->Tcb
,
1170 (CCHAR
)IdealProcessor
);
1172 /* Get the TEB and protect the thread */
1173 Teb
= Thread
->Tcb
.Teb
;
1174 if ((Teb
) && (ExAcquireRundownProtection(&Thread
->RundownProtect
)))
1176 /* Save the ideal processor */
1177 Teb
->IdealProcessor
= Thread
->Tcb
.IdealProcessor
;
1179 /* Release rundown protection */
1180 ExReleaseRundownProtection(&Thread
->RundownProtect
);
1185 case ThreadPriorityBoost
:
1187 /* Use SEH for capture */
1190 /* Get the priority */
1191 DisableBoost
= *(PULONG_PTR
)ThreadInformation
;
1193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1195 /* Get the exception code */
1196 Status
= _SEH2_GetExceptionCode();
1199 if (!NT_SUCCESS(Status
)) break;
1201 /* Call the kernel */
1202 KeSetDisableBoostThread(&Thread
->Tcb
, (BOOLEAN
)DisableBoost
);
1205 case ThreadZeroTlsCell
:
1207 /* Use SEH for capture */
1210 /* Get the priority */
1211 TlsIndex
= *(PULONG_PTR
)ThreadInformation
;
1213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1215 /* Get the exception code */
1216 Status
= _SEH2_GetExceptionCode();
1219 if (!NT_SUCCESS(Status
)) break;
1221 /* This is only valid for the current thread */
1222 if (Thread
!= PsGetCurrentThread())
1225 Status
= STATUS_INVALID_PARAMETER
;
1229 /* Get the process */
1230 Process
= Thread
->ThreadsProcess
;
1232 /* Loop the threads */
1233 ProcThread
= PsGetNextProcessThread(Process
, NULL
);
1236 /* Acquire rundown */
1237 if (ExAcquireRundownProtection(&ProcThread
->RundownProtect
))
1240 Teb
= ProcThread
->Tcb
.Teb
;
1243 /* Check if we're in the expansion range */
1244 if (TlsIndex
> TLS_MINIMUM_AVAILABLE
- 1)
1246 if (TlsIndex
< (TLS_MINIMUM_AVAILABLE
+
1247 TLS_EXPANSION_SLOTS
) - 1)
1249 /* Check if we have expansion slots */
1250 ExpansionSlots
= Teb
->TlsExpansionSlots
;
1253 /* Clear the index */
1254 ExpansionSlots
[TlsIndex
- TLS_MINIMUM_AVAILABLE
] = 0;
1260 /* Clear the index */
1261 Teb
->TlsSlots
[TlsIndex
] = NULL
;
1265 /* Release rundown */
1266 ExReleaseRundownProtection(&ProcThread
->RundownProtect
);
1269 /* Go to the next thread */
1270 ProcThread
= PsGetNextProcessThread(Process
, ProcThread
);
1277 /* We don't implement it yet */
1278 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
1279 Status
= STATUS_NOT_IMPLEMENTED
;
1282 /* Dereference and return status */
1283 ObDereferenceObject(Thread
);
1292 NtQueryInformationThread(IN HANDLE ThreadHandle
,
1293 IN THREADINFOCLASS ThreadInformationClass
,
1294 OUT PVOID ThreadInformation
,
1295 IN ULONG ThreadInformationLength
,
1296 OUT PULONG ReturnLength OPTIONAL
)
1299 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1300 NTSTATUS Status
= STATUS_SUCCESS
;
1303 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
=
1304 (PTHREAD_BASIC_INFORMATION
)ThreadInformation
;
1305 PKERNEL_USER_TIMES ThreadTime
= (PKERNEL_USER_TIMES
)ThreadInformation
;
1309 /* Verify Information Class validity */
1311 Status
= DefaultQueryInfoBufferCheck(ThreadInformationClass
,
1313 RTL_NUMBER_OF(PsThreadInfoClass
),
1315 ThreadInformationLength
,
1318 if (!NT_SUCCESS(Status
)) return Status
;
1321 /* Check what class this is */
1322 Access
= THREAD_QUERY_INFORMATION
;
1324 /* Reference the process */
1325 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1331 if (!NT_SUCCESS(Status
)) return Status
;
1333 /* Check what kind of information class this is */
1334 switch (ThreadInformationClass
)
1336 /* Basic thread information */
1337 case ThreadBasicInformation
:
1339 /* Set return length */
1340 Length
= sizeof(THREAD_BASIC_INFORMATION
);
1342 if (ThreadInformationLength
!= Length
)
1344 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1347 /* Protect writes with SEH */
1350 /* Write all the information from the ETHREAD/KTHREAD */
1351 ThreadBasicInfo
->ExitStatus
= Thread
->ExitStatus
;
1352 ThreadBasicInfo
->TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
1353 ThreadBasicInfo
->ClientId
= Thread
->Cid
;
1354 ThreadBasicInfo
->AffinityMask
= Thread
->Tcb
.Affinity
;
1355 ThreadBasicInfo
->Priority
= Thread
->Tcb
.Priority
;
1356 ThreadBasicInfo
->BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
1358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1360 /* Get exception code */
1361 Status
= _SEH2_GetExceptionCode();
1366 /* Thread time information */
1369 /* Set the return length */
1370 Length
= sizeof(KERNEL_USER_TIMES
);
1372 if (ThreadInformationLength
!= Length
)
1374 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1377 /* Protect writes with SEH */
1380 /* Copy time information from ETHREAD/KTHREAD */
1381 ThreadTime
->KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
*
1383 ThreadTime
->UserTime
.QuadPart
= Thread
->Tcb
.UserTime
*
1385 ThreadTime
->CreateTime
= Thread
->CreateTime
;
1386 ThreadTime
->ExitTime
= Thread
->ExitTime
;
1388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1390 /* Get exception code */
1391 Status
= _SEH2_GetExceptionCode();
1396 case ThreadQuerySetWin32StartAddress
:
1398 /* Set the return length*/
1399 Length
= sizeof(PVOID
);
1401 if (ThreadInformationLength
!= Length
)
1403 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1406 /* Protect write with SEH */
1409 /* Return the Win32 Start Address */
1410 *(PVOID
*)ThreadInformation
= Thread
->Win32StartAddress
;
1412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1414 /* Get exception code */
1415 Status
= _SEH2_GetExceptionCode();
1420 case ThreadPerformanceCount
:
1422 /* Set the return length*/
1423 Length
= sizeof(LARGE_INTEGER
);
1425 if (ThreadInformationLength
!= Length
)
1427 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1430 /* Protect write with SEH */
1434 (*(PLARGE_INTEGER
)ThreadInformation
).QuadPart
= 0;
1436 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1438 /* Get exception code */
1439 Status
= _SEH2_GetExceptionCode();
1444 case ThreadAmILastThread
:
1446 /* Set the return length*/
1447 Length
= sizeof(ULONG
);
1449 if (ThreadInformationLength
!= Length
)
1451 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1454 /* Protect write with SEH */
1457 /* Return whether or not we are the last thread */
1458 *(PULONG
)ThreadInformation
= ((Thread
->ThreadsProcess
->
1459 ThreadListHead
.Flink
->Flink
==
1460 &Thread
->ThreadsProcess
->
1464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1466 /* Get exception code */
1467 Status
= _SEH2_GetExceptionCode();
1472 case ThreadIsIoPending
:
1474 /* Set the return length*/
1475 Length
= sizeof(ULONG
);
1477 if (ThreadInformationLength
!= Length
)
1479 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1482 /* Raise the IRQL to protect the IRP list */
1483 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1485 /* Protect write with SEH */
1488 /* Check if the IRP list is empty or not */
1489 *(PULONG
)ThreadInformation
= !IsListEmpty(&Thread
->IrpList
);
1491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1493 /* Get exception code */
1494 Status
= _SEH2_GetExceptionCode();
1498 /* Lower IRQL back */
1499 KeLowerIrql(OldIrql
);
1505 /* Not yet implemented */
1506 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
1507 Status
= STATUS_NOT_IMPLEMENTED
;
1510 /* Protect write with SEH */
1513 /* Check if caller wanted return length */
1514 if (ReturnLength
) *ReturnLength
= Length
;
1516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1518 /* Get exception code */
1519 Status
= _SEH2_GetExceptionCode();
1523 /* Dereference the thread, and return */
1524 ObDereferenceObject(Thread
);