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 /* Check if this isn't the cookie class */
93 if(ProcessInformationClass
!= ProcessCookie
)
95 /* Reference the process */
96 Status
= ObReferenceObjectByHandle(ProcessHandle
,
97 PROCESS_QUERY_INFORMATION
,
102 if (!NT_SUCCESS(Status
)) return Status
;
104 else if(ProcessHandle
!= NtCurrentProcess())
107 * Retreiving the process cookie is only allowed for the calling process
108 * itself! XP only allowes NtCurrentProcess() as process handles even if
109 * a real handle actually represents the current process.
111 return STATUS_INVALID_PARAMETER
;
114 /* Check the information class */
115 switch (ProcessInformationClass
)
117 /* Basic process information */
118 case ProcessBasicInformation
:
120 /* Set return length */
121 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
123 if ( ProcessInformationLength
!= Length
)
125 Status
= STATUS_INFO_LENGTH_MISMATCH
;
128 /* Protect writes with SEH */
131 /* Write all the information from the EPROCESS/KPROCESS */
132 ProcessBasicInfo
->ExitStatus
= Process
->ExitStatus
;
133 ProcessBasicInfo
->PebBaseAddress
= Process
->Peb
;
134 ProcessBasicInfo
->AffinityMask
= Process
->Pcb
.Affinity
;
135 ProcessBasicInfo
->UniqueProcessId
= (ULONG_PTR
)Process
->
137 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
138 (ULONG
)Process
->InheritedFromUniqueProcessId
;
139 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
144 /* Get exception code */
145 Status
= _SEH2_GetExceptionCode();
150 /* Quote limits and I/O Counters: not implemented */
151 case ProcessQuotaLimits
:
152 case ProcessIoCounters
:
154 Length
= sizeof(IO_COUNTERS
);
155 if ( ProcessInformationLength
!= Length
)
157 Status
= STATUS_INFO_LENGTH_MISMATCH
;
161 Status
= STATUS_NOT_IMPLEMENTED
;
167 /* Set the return length */
168 Length
= sizeof(KERNEL_USER_TIMES
);
170 if ( ProcessInformationLength
!= Length
)
172 Status
= STATUS_INFO_LENGTH_MISMATCH
;
176 /* Protect writes with SEH */
179 /* Copy time information from EPROCESS/KPROCESS */
180 ProcessTime
->CreateTime
= Process
->CreateTime
;
181 ProcessTime
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
*
183 ProcessTime
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
*
185 ProcessTime
->ExitTime
= Process
->ExitTime
;
187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
189 /* Get exception code */
190 Status
= _SEH2_GetExceptionCode();
195 /* Process Debug Port */
196 case ProcessDebugPort
:
198 /* Protect write with SEH */
201 /* Return whether or not we have a debug port */
202 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
?
205 /* Set the return length*/
206 Length
= sizeof(HANDLE
);
208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
210 /* Get exception code */
211 Status
= _SEH2_GetExceptionCode();
216 /* LDT, WS and VDM Information: not implemented */
217 case ProcessLdtInformation
:
218 case ProcessWorkingSetWatch
:
219 case ProcessWx86Information
:
220 Status
= STATUS_NOT_IMPLEMENTED
;
223 case ProcessHandleCount
:
225 /* Set the return length*/
226 Length
= sizeof(ULONG
);
228 if ( ProcessInformationLength
!= Length
)
230 Status
= STATUS_INFO_LENGTH_MISMATCH
;
234 /* Count the number of handles this process has */
235 HandleCount
= ObpGetHandleCountByHandleTable(Process
->ObjectTable
);
237 /* Protect write in SEH */
240 /* Return the count of handles */
241 *(PULONG
)ProcessInformation
= HandleCount
;
243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
245 /* Get the exception code */
246 Status
= _SEH2_GetExceptionCode();
251 /* Session ID for the process */
252 case ProcessSessionInformation
:
254 /* Enter SEH for write safety */
257 /* Write back the Session ID */
258 SessionInfo
->SessionId
= Process
->Session
;
260 /* Set the return length */
261 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
263 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
265 /* Get the exception code */
266 Status
= _SEH2_GetExceptionCode();
271 /* WOW64: Not implemented */
272 case ProcessWow64Information
:
273 Status
= STATUS_NOT_IMPLEMENTED
;
276 /* Virtual Memory Statistics */
277 case ProcessVmCounters
:
279 /* Set the return length */
280 Length
= sizeof(VM_COUNTERS
);
282 if ( ProcessInformationLength
!= Length
)
284 Status
= STATUS_INFO_LENGTH_MISMATCH
;
288 /* Enter SEH for write safety */
291 /* Return data from EPROCESS */
292 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
293 VmCounters
->VirtualSize
= Process
->VirtualSize
;
294 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
295 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
296 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
297 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
298 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
299 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
300 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
301 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2];
302 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2];
305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
307 /* Get the exception code */
308 Status
= _SEH2_GetExceptionCode();
313 /* Hard Error Processing Mode */
314 case ProcessDefaultHardErrorMode
:
316 /* Enter SEH for writing back data */
319 /* Write the current processing mode */
320 *(PULONG
)ProcessInformation
= Process
->
321 DefaultHardErrorProcessing
;
323 /* Set the return length */
324 Length
= sizeof(ULONG
);
326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
328 /* Get the exception code */
329 Status
= _SEH2_GetExceptionCode();
334 /* Priority Boosting status */
335 case ProcessPriorityBoost
:
337 /* Enter SEH for writing back data */
340 /* Return boost status */
341 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
344 /* Set the return length */
345 Length
= sizeof(ULONG
);
347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
349 /* Get the exception code */
350 Status
= _SEH2_GetExceptionCode();
356 case ProcessDeviceMap
:
358 /* Query the device map information */
359 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
361 /* Enter SEH for writing back data */
364 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
366 /* Set the return length */
367 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
371 /* Get the exception code */
372 Status
= _SEH2_GetExceptionCode();
378 case ProcessPriorityClass
:
380 /* Enter SEH for writing back data */
383 /* Return current priority class */
384 *(PUSHORT
)ProcessInformation
= Process
->PriorityClass
;
386 /* Set the return length */
387 Length
= sizeof(USHORT
);
389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
391 /* Get the exception code */
392 Status
= _SEH2_GetExceptionCode();
397 case ProcessImageFileName
:
399 /* Get the image path */
400 Status
= SeLocateProcessImageName(Process
, &ImageName
);
401 if (NT_SUCCESS(Status
))
403 /* Set return length */
404 Length
= ImageName
->MaximumLength
+
405 sizeof(OBJECT_NAME_INFORMATION
);
407 /* Make sure it's large enough */
408 if (Length
<= ProcessInformationLength
)
410 /* Enter SEH to protect write */
414 RtlCopyMemory(ProcessInformation
,
419 ((PUNICODE_STRING
)ProcessInformation
)->Buffer
=
420 (PWSTR
)((PUNICODE_STRING
)ProcessInformation
+ 1);
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
424 /* Get the exception code */
425 Status
= _SEH2_GetExceptionCode();
431 /* Buffer too small */
432 Status
= STATUS_INFO_LENGTH_MISMATCH
;
435 /* Free the image path */
436 ExFreePool(ImageName
);
440 /* Per-process security cookie */
443 /* Get the current process and cookie */
444 Process
= PsGetCurrentProcess();
445 Cookie
= Process
->Cookie
;
448 LARGE_INTEGER SystemTime
;
452 /* Generate a new cookie */
453 KeQuerySystemTime(&SystemTime
);
454 Prcb
= KeGetCurrentPrcb();
455 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
456 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
458 /* Set the new cookie or return the current one */
459 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
462 if (!Cookie
) Cookie
= NewCookie
;
464 /* Set return length */
465 Length
= sizeof(ULONG
);
468 /* Enter SEH to protect write */
471 /* Write back the cookie */
472 *(PULONG
)ProcessInformation
= Cookie
;
474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
476 /* Get the exception code */
477 Status
= _SEH2_GetExceptionCode();
482 /* Not yet implemented, or unknown */
483 case ProcessBasePriority
:
484 case ProcessRaisePriority
:
485 case ProcessExceptionPort
:
486 case ProcessAccessToken
:
488 case ProcessIoPortHandlers
:
489 case ProcessUserModeIOPL
:
490 case ProcessEnableAlignmentFaultFixup
:
491 case ProcessAffinityMask
:
492 case ProcessForegroundInformation
:
494 Status
= STATUS_INVALID_INFO_CLASS
;
497 /* Protect write with SEH */
500 /* Check if caller wanted return length */
501 if (ReturnLength
) *ReturnLength
= Length
;
503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
505 /* Get exception code */
506 Status
= _SEH2_GetExceptionCode();
510 /* If we referenced the process, dereference it */
511 if(ProcessInformationClass
!= ProcessCookie
) ObDereferenceObject(Process
);
520 NtSetInformationProcess(IN HANDLE ProcessHandle
,
521 IN PROCESSINFOCLASS ProcessInformationClass
,
522 IN PVOID ProcessInformation
,
523 IN ULONG ProcessInformationLength
)
526 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
529 HANDLE PortHandle
= NULL
;
530 HANDLE TokenHandle
= NULL
;
531 PROCESS_SESSION_INFORMATION SessionInfo
= {0};
535 /* Verify Information Class validity */
537 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
539 RTL_NUMBER_OF(PsProcessInfoClass
),
541 ProcessInformationLength
,
543 if (!NT_SUCCESS(Status
)) return Status
;
546 /* Check what class this is */
547 Access
= PROCESS_SET_INFORMATION
;
548 if (ProcessInformationClass
== ProcessSessionInformation
)
550 /* Setting the Session ID needs a special mask */
551 Access
|= PROCESS_SET_SESSIONID
;
553 else if (ProcessInformationClass
== ProcessExceptionPort
)
555 /* Setting the exception port needs a special mask */
556 Access
|= PROCESS_SUSPEND_RESUME
;
559 /* Reference the process */
560 Status
= ObReferenceObjectByHandle(ProcessHandle
,
566 if (!NT_SUCCESS(Status
)) return Status
;
568 /* Check what kind of information class this is */
569 switch (ProcessInformationClass
)
571 /* Quotas and priorities: not implemented */
572 case ProcessQuotaLimits
:
573 case ProcessBasePriority
:
574 case ProcessRaisePriority
:
575 Status
= STATUS_NOT_IMPLEMENTED
;
578 /* Error/Exception Port */
579 case ProcessExceptionPort
:
581 /* Use SEH for capture */
584 /* Capture the handle */
585 PortHandle
= *(PHANDLE
)ProcessInformation
;
587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
589 /* Get the exception code */
590 Status
= _SEH2_GetExceptionCode();
593 if (!NT_SUCCESS(Status
)) break;
595 /* Get the LPC Port */
596 Status
= ObReferenceObjectByHandle(PortHandle
,
600 (PVOID
)&ExceptionPort
,
602 if (!NT_SUCCESS(Status
)) break;
604 /* Change the pointer */
605 if (InterlockedCompareExchangePointer(&Process
->ExceptionPort
,
609 /* We already had one, fail */
610 ObDereferenceObject(ExceptionPort
);
611 Status
= STATUS_PORT_ALREADY_SET
;
616 case ProcessAccessToken
:
618 /* Use SEH for capture */
621 /* Save the token handle */
622 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->
625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
627 /* Get the exception code */
628 Status
= _SEH2_GetExceptionCode();
631 if (!NT_SUCCESS(Status
)) break;
633 /* Assign the actual token */
634 Status
= PspSetPrimaryToken(Process
, TokenHandle
, NULL
);
637 /* Hard error processing */
638 case ProcessDefaultHardErrorMode
:
640 /* Enter SEH for direct buffer read */
643 /* Update the current mode abd return the previous one */
644 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
645 *(PLONG
)ProcessInformation
);
647 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
649 /* Get exception code */
650 Status
= _SEH2_GetExceptionCode();
656 case ProcessSessionInformation
:
658 /* Enter SEH for capture */
661 /* Capture the caller's buffer */
662 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
666 /* Get the exception code */
667 Status
= _SEH2_GetExceptionCode();
670 if (!NT_SUCCESS(Status
)) break;
672 /* Setting the session id requires the SeTcbPrivilege */
673 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
675 /* Can't set the session ID, bail out. */
676 Status
= STATUS_PRIVILEGE_NOT_HELD
;
680 /* FIXME - update the session id for the process token */
681 //Status = PsLockProcess(Process, FALSE);
682 if (!NT_SUCCESS(Status
)) break;
684 /* Write the session ID in the EPROCESS */
685 Process
->Session
= SessionInfo
.SessionId
;
687 /* Check if the process also has a PEB */
691 * Attach to the process to make sure we're in the right
692 * context to access the PEB structure
694 KeAttachProcess(&Process
->Pcb
);
696 /* Enter SEH for write to user-mode PEB */
699 /* Write the session ID */
700 Process
->Peb
->SessionId
= SessionInfo
.SessionId
;
702 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
704 /* Get exception code */
705 Status
= _SEH2_GetExceptionCode();
709 /* Detach from the process */
713 /* Unlock the process */
714 //PsUnlockProcess(Process);
717 /* Priority class: HACK! */
718 case ProcessPriorityClass
:
721 /* We currently don't implement any of these */
722 case ProcessLdtInformation
:
724 case ProcessIoPortHandlers
:
725 case ProcessWorkingSetWatch
:
726 case ProcessUserModeIOPL
:
727 case ProcessEnableAlignmentFaultFixup
:
728 case ProcessAffinityMask
:
729 Status
= STATUS_NOT_IMPLEMENTED
;
732 /* Supposedly these are invalid...!? verify! */
733 case ProcessBasicInformation
:
734 case ProcessIoCounters
:
736 case ProcessPooledUsageAndLimits
:
737 case ProcessWx86Information
:
738 case ProcessHandleCount
:
739 case ProcessWow64Information
:
740 case ProcessDebugPort
:
742 Status
= STATUS_INVALID_INFO_CLASS
;
745 /* Dereference and return status */
746 ObDereferenceObject(Process
);
755 NtSetInformationThread(IN HANDLE ThreadHandle
,
756 IN THREADINFOCLASS ThreadInformationClass
,
757 IN PVOID ThreadInformation
,
758 IN ULONG ThreadInformationLength
)
762 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
764 HANDLE TokenHandle
= NULL
;
765 KPRIORITY Priority
= 0;
766 KAFFINITY Affinity
= 0, CombinedAffinity
;
767 PVOID Address
= NULL
;
769 ULONG DisableBoost
= 0;
770 ULONG IdealProcessor
= 0;
773 PVOID
*ExpansionSlots
;
777 /* Verify Information Class validity */
779 Status
= DefaultSetInfoBufferCheck(ThreadInformationClass
,
781 RTL_NUMBER_OF(PsThreadInfoClass
),
783 ThreadInformationLength
,
785 if (!NT_SUCCESS(Status
)) return Status
;
788 /* Check what class this is */
789 Access
= THREAD_SET_INFORMATION
;
790 if (ThreadInformationClass
== ThreadImpersonationToken
)
792 /* Setting the impersonation token needs a special mask */
793 Access
= THREAD_SET_THREAD_TOKEN
;
796 /* Reference the process */
797 Status
= ObReferenceObjectByHandle(ThreadHandle
,
803 if (!NT_SUCCESS(Status
)) return Status
;
805 /* Check what kind of information class this is */
806 switch (ThreadInformationClass
)
808 /* Thread priority */
811 /* Use SEH for capture */
814 /* Get the priority */
815 Priority
= *(PLONG
)ThreadInformation
;
817 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
819 /* Get the exception code */
820 Status
= _SEH2_GetExceptionCode();
823 if (!NT_SUCCESS(Status
)) break;
826 if ((Priority
> HIGH_PRIORITY
) ||
827 (Priority
<= LOW_PRIORITY
))
830 Status
= STATUS_INVALID_PARAMETER
;
834 /* Set the priority */
835 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
838 case ThreadBasePriority
:
840 /* Use SEH for capture */
843 /* Get the priority */
844 Priority
= *(PLONG
)ThreadInformation
;
846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
848 /* Get the exception code */
849 Status
= _SEH2_GetExceptionCode();
852 if (!NT_SUCCESS(Status
)) break;
855 if ((Priority
> THREAD_BASE_PRIORITY_MAX
) ||
856 (Priority
< THREAD_BASE_PRIORITY_MIN
))
858 /* These ones are OK */
859 if ((Priority
!= THREAD_BASE_PRIORITY_LOWRT
+ 1) &&
860 (Priority
!= THREAD_BASE_PRIORITY_IDLE
- 1))
862 /* Check if the process is real time */
863 if (PsGetCurrentProcess()->PriorityClass
!=
864 PROCESS_PRIORITY_CLASS_REALTIME
)
867 Status
= STATUS_INVALID_PARAMETER
;
873 /* Set the base priority */
874 KeSetBasePriorityThread(&Thread
->Tcb
, Priority
);
877 case ThreadAffinityMask
:
879 /* Use SEH for capture */
882 /* Get the priority */
883 Affinity
= *(PULONG_PTR
)ThreadInformation
;
885 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
887 /* Get the exception code */
888 Status
= _SEH2_GetExceptionCode();
891 if (!NT_SUCCESS(Status
)) break;
897 Status
= STATUS_INVALID_PARAMETER
;
901 /* Get the process */
902 Process
= Thread
->ThreadsProcess
;
904 /* Try to acquire rundown */
905 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
908 KeEnterCriticalRegion();
909 ExAcquirePushLockShared(&Process
->ProcessLock
);
912 CombinedAffinity
= Affinity
& Process
->Pcb
.Affinity
;
913 if (CombinedAffinity
!= Affinity
)
916 Status
= STATUS_INVALID_PARAMETER
;
920 /* Set the affinity */
921 KeSetAffinityThread(&Thread
->Tcb
, CombinedAffinity
);
924 /* Release the lock and rundown */
925 ExReleasePushLockShared(&Process
->ProcessLock
);
926 KeLeaveCriticalRegion();
927 ExReleaseRundownProtection(&Process
->RundownProtect
);
932 Status
= STATUS_PROCESS_IS_TERMINATING
;
938 case ThreadImpersonationToken
:
940 /* Use SEH for capture */
943 /* Save the token handle */
944 TokenHandle
= *(PHANDLE
)ThreadInformation
;
946 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
948 /* Get the exception code */
949 Status
= _SEH2_GetExceptionCode();
952 if (!NT_SUCCESS(Status
)) break;
954 /* Assign the actual token */
955 Status
= PsAssignImpersonationToken(Thread
, TokenHandle
);
958 case ThreadQuerySetWin32StartAddress
:
960 /* Use SEH for capture */
963 /* Get the priority */
964 Address
= *(PVOID
*)ThreadInformation
;
966 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
968 /* Get the exception code */
969 Status
= _SEH2_GetExceptionCode();
972 if (!NT_SUCCESS(Status
)) break;
974 /* Set the address */
975 Thread
->Win32StartAddress
= Address
;
978 case ThreadIdealProcessor
:
980 /* Use SEH for capture */
983 /* Get the priority */
984 IdealProcessor
= *(PULONG_PTR
)ThreadInformation
;
986 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
988 /* Get the exception code */
989 Status
= _SEH2_GetExceptionCode();
992 if (!NT_SUCCESS(Status
)) break;
995 if (IdealProcessor
> MAXIMUM_PROCESSORS
)
998 Status
= STATUS_INVALID_PARAMETER
;
1003 Status
= KeSetIdealProcessorThread(&Thread
->Tcb
,
1004 (CCHAR
)IdealProcessor
);
1006 /* Get the TEB and protect the thread */
1007 Teb
= Thread
->Tcb
.Teb
;
1008 if ((Teb
) && (ExAcquireRundownProtection(&Thread
->RundownProtect
)))
1010 /* Save the ideal processor */
1011 Teb
->IdealProcessor
= Thread
->Tcb
.IdealProcessor
;
1013 /* Release rundown protection */
1014 ExReleaseRundownProtection(&Thread
->RundownProtect
);
1019 case ThreadPriorityBoost
:
1021 /* Use SEH for capture */
1024 /* Get the priority */
1025 DisableBoost
= *(PULONG_PTR
)ThreadInformation
;
1027 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1029 /* Get the exception code */
1030 Status
= _SEH2_GetExceptionCode();
1033 if (!NT_SUCCESS(Status
)) break;
1035 /* Call the kernel */
1036 KeSetDisableBoostThread(&Thread
->Tcb
, (BOOLEAN
)DisableBoost
);
1039 case ThreadZeroTlsCell
:
1041 /* Use SEH for capture */
1044 /* Get the priority */
1045 TlsIndex
= *(PULONG_PTR
)ThreadInformation
;
1047 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1049 /* Get the exception code */
1050 Status
= _SEH2_GetExceptionCode();
1053 if (!NT_SUCCESS(Status
)) break;
1055 /* This is only valid for the current thread */
1056 if (Thread
!= PsGetCurrentThread())
1059 Status
= STATUS_INVALID_PARAMETER
;
1063 /* Get the process */
1064 Process
= Thread
->ThreadsProcess
;
1066 /* Loop the threads */
1067 ProcThread
= PsGetNextProcessThread(Process
, NULL
);
1070 /* Acquire rundown */
1071 if (ExAcquireRundownProtection(&ProcThread
->RundownProtect
))
1074 Teb
= ProcThread
->Tcb
.Teb
;
1077 /* Check if we're in the expansion range */
1078 if (TlsIndex
> TLS_MINIMUM_AVAILABLE
- 1)
1080 if (TlsIndex
< (TLS_MINIMUM_AVAILABLE
+
1081 TLS_EXPANSION_SLOTS
) - 1)
1083 /* Check if we have expansion slots */
1084 ExpansionSlots
= Teb
->TlsExpansionSlots
;
1087 /* Clear the index */
1088 ExpansionSlots
[TlsIndex
- TLS_MINIMUM_AVAILABLE
] = 0;
1094 /* Clear the index */
1095 Teb
->TlsSlots
[TlsIndex
] = NULL
;
1099 /* Release rundown */
1100 ExReleaseRundownProtection(&ProcThread
->RundownProtect
);
1103 /* Go to the next thread */
1104 ProcThread
= PsGetNextProcessThread(Process
, ProcThread
);
1111 /* We don't implement it yet */
1112 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
1113 Status
= STATUS_NOT_IMPLEMENTED
;
1116 /* Dereference and return status */
1117 ObDereferenceObject(Thread
);
1126 NtQueryInformationThread(IN HANDLE ThreadHandle
,
1127 IN THREADINFOCLASS ThreadInformationClass
,
1128 OUT PVOID ThreadInformation
,
1129 IN ULONG ThreadInformationLength
,
1130 OUT PULONG ReturnLength OPTIONAL
)
1133 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1134 NTSTATUS Status
= STATUS_SUCCESS
;
1137 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
=
1138 (PTHREAD_BASIC_INFORMATION
)ThreadInformation
;
1139 PKERNEL_USER_TIMES ThreadTime
= (PKERNEL_USER_TIMES
)ThreadInformation
;
1143 /* Verify Information Class validity */
1145 Status
= DefaultQueryInfoBufferCheck(ThreadInformationClass
,
1147 RTL_NUMBER_OF(PsThreadInfoClass
),
1149 ThreadInformationLength
,
1152 if (!NT_SUCCESS(Status
)) return Status
;
1155 /* Check what class this is */
1156 Access
= THREAD_QUERY_INFORMATION
;
1158 /* Reference the process */
1159 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1165 if (!NT_SUCCESS(Status
)) return Status
;
1167 /* Check what kind of information class this is */
1168 switch (ThreadInformationClass
)
1170 /* Basic thread information */
1171 case ThreadBasicInformation
:
1173 /* Protect writes with SEH */
1176 /* Write all the information from the ETHREAD/KTHREAD */
1177 ThreadBasicInfo
->ExitStatus
= Thread
->ExitStatus
;
1178 ThreadBasicInfo
->TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
1179 ThreadBasicInfo
->ClientId
= Thread
->Cid
;
1180 ThreadBasicInfo
->AffinityMask
= Thread
->Tcb
.Affinity
;
1181 ThreadBasicInfo
->Priority
= Thread
->Tcb
.Priority
;
1182 ThreadBasicInfo
->BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
1184 /* Set return length */
1185 Length
= sizeof(THREAD_BASIC_INFORMATION
);
1187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1189 /* Get exception code */
1190 Status
= _SEH2_GetExceptionCode();
1195 /* Thread time information */
1198 /* Protect writes with SEH */
1201 /* Copy time information from ETHREAD/KTHREAD */
1202 ThreadTime
->KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
*
1204 ThreadTime
->UserTime
.QuadPart
= Thread
->Tcb
.UserTime
*
1206 ThreadTime
->CreateTime
= Thread
->CreateTime
;
1207 ThreadTime
->ExitTime
= Thread
->ExitTime
;
1209 /* Set the return length */
1210 Length
= sizeof(KERNEL_USER_TIMES
);
1212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1214 /* Get exception code */
1215 Status
= _SEH2_GetExceptionCode();
1220 case ThreadQuerySetWin32StartAddress
:
1222 /* Protect write with SEH */
1225 /* Return the Win32 Start Address */
1226 *(PVOID
*)ThreadInformation
= Thread
->Win32StartAddress
;
1228 /* Set the return length*/
1229 Length
= sizeof(PVOID
);
1231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1233 /* Get exception code */
1234 Status
= _SEH2_GetExceptionCode();
1239 case ThreadPerformanceCount
:
1241 /* Protect write with SEH */
1245 (*(PLARGE_INTEGER
)ThreadInformation
).QuadPart
= 0;
1247 /* Set the return length*/
1248 Length
= sizeof(LARGE_INTEGER
);
1250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1252 /* Get exception code */
1253 Status
= _SEH2_GetExceptionCode();
1258 case ThreadAmILastThread
:
1260 /* Protect write with SEH */
1263 /* Return whether or not we are the last thread */
1264 *(PULONG
)ThreadInformation
= ((Thread
->ThreadsProcess
->
1265 ThreadListHead
.Flink
->Flink
==
1266 &Thread
->ThreadsProcess
->
1270 /* Set the return length*/
1271 Length
= sizeof(ULONG
);
1273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1275 /* Get exception code */
1276 Status
= _SEH2_GetExceptionCode();
1281 case ThreadIsIoPending
:
1283 /* Raise the IRQL to protect the IRP list */
1284 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1286 /* Protect write with SEH */
1289 /* Check if the IRP list is empty or not */
1290 *(PULONG
)ThreadInformation
= !IsListEmpty(&Thread
->IrpList
);
1292 /* Set the return length*/
1293 Length
= sizeof(ULONG
);
1295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1297 /* Get exception code */
1298 Status
= _SEH2_GetExceptionCode();
1302 /* Lower IRQL back */
1303 KeLowerIrql(OldIrql
);
1309 /* Not yet implemented */
1310 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
1311 Status
= STATUS_NOT_IMPLEMENTED
;
1314 /* Protect write with SEH */
1317 /* Check if caller wanted return length */
1318 if (ReturnLength
) *ReturnLength
= Length
;
1320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1322 /* Get exception code */
1323 Status
= _SEH2_GetExceptionCode();
1327 /* Dereference the thread, and return */
1328 ObDereferenceObject(Thread
);