2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Set/Query Process/Thread Information APIs
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 static const INFORMATION_CLASS_INFO PsProcessInfoClass
[] =
21 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessBasicInformation */
22 ICI_SQ_SAME( sizeof(QUOTA_LIMITS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessQuotaLimits */
23 ICI_SQ_SAME( sizeof(IO_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessIoCounters */
24 ICI_SQ_SAME( sizeof(VM_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessVmCounters */
25 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessTimes */
26 ICI_SQ_SAME( sizeof(KPRIORITY
), sizeof(ULONG
), ICIF_SET
), /* ProcessBasePriority */
27 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_SET
), /* ProcessRaisePriority */
28 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessDebugPort */
29 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_SET
), /* ProcessExceptionPort */
30 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN
), sizeof(ULONG
), ICIF_SET
), /* ProcessAccessToken */
31 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessLdtInformation */
32 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessLdtSize */
33 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessDefaultHardErrorMode */
34 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessIoPortHandlers */
35 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessPooledUsageAndLimits */
36 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessWorkingSetWatch */
37 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessUserModeIOPL */
38 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(ULONG
), ICIF_SET
), /* ProcessEnableAlignmentFaultFixup */
39 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS
), sizeof(USHORT
), ICIF_QUERY
| ICIF_SET
), /* ProcessPriorityClass */
40 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWx86Information */
41 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessHandleCount */
42 ICI_SQ_SAME( sizeof(KAFFINITY
), sizeof(ULONG
), ICIF_SET
), /* ProcessAffinityMask */
43 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessPriorityBoost */
45 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Query
), /* ProcessDeviceMap */
46 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Set
),
49 ICIF_QUERY
| ICIF_SET
),
51 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessSessionInformation */
52 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(ULONG
), ICIF_SET
), /* ProcessForegroundInformation */
53 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWow64Information */
54 ICI_SQ_SAME( sizeof(UNICODE_STRING
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SIZE_VARIABLE
), /* ProcessImageFileName */
57 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
58 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
59 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
60 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
61 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
62 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
63 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
64 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
66 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessCookie */
71 * Remove the Implemented value if all functions are implemented.
78 } QueryInformationData
[MaxThreadInfoClass
+ 1] =
80 {TRUE
, sizeof(THREAD_BASIC_INFORMATION
)}, // ThreadBasicInformation
81 {TRUE
, sizeof(KERNEL_USER_TIMES
)}, // ThreadTimes
82 {TRUE
, 0}, // ThreadPriority
83 {TRUE
, 0}, // ThreadBasePriority
84 {TRUE
, 0}, // ThreadAffinityMask
85 {TRUE
, 0}, // ThreadImpersonationToken
86 {FALSE
, 0}, // ThreadDescriptorTableEntry
87 {TRUE
, 0}, // ThreadEnableAlignmentFaultFixup
88 {TRUE
, 0}, // ThreadEventPair
89 {TRUE
, sizeof(PVOID
)}, // ThreadQuerySetWin32StartAddress
90 {TRUE
, 0}, // ThreadZeroTlsCell
91 {TRUE
, sizeof(LARGE_INTEGER
)}, // ThreadPerformanceCount
92 {TRUE
, sizeof(BOOLEAN
)}, // ThreadAmILastThread
93 {TRUE
, 0}, // ThreadIdealProcessor
94 {FALSE
, 0}, // ThreadPriorityBoost
95 {TRUE
, 0}, // ThreadSetTlsArrayAddress
96 {FALSE
, 0}, // ThreadIsIoPending
97 {TRUE
, 0} // ThreadHideFromDebugger
104 } SetInformationData
[MaxThreadInfoClass
+ 1] =
106 {TRUE
, 0}, // ThreadBasicInformation
107 {TRUE
, 0}, // ThreadTimes
108 {TRUE
, sizeof(KPRIORITY
)}, // ThreadPriority
109 {TRUE
, sizeof(LONG
)}, // ThreadBasePriority
110 {TRUE
, sizeof(KAFFINITY
)}, // ThreadAffinityMask
111 {TRUE
, sizeof(HANDLE
)}, // ThreadImpersonationToken
112 {TRUE
, 0}, // ThreadDescriptorTableEntry
113 {FALSE
, 0}, // ThreadEnableAlignmentFaultFixup
114 {FALSE
, 0}, // ThreadEventPair
115 {TRUE
, sizeof(PVOID
)}, // ThreadQuerySetWin32StartAddress
116 {FALSE
, 0}, // ThreadZeroTlsCell
117 {TRUE
, 0}, // ThreadPerformanceCount
118 {TRUE
, 0}, // ThreadAmILastThread
119 {FALSE
, 0}, // ThreadIdealProcessor
120 {FALSE
, 0}, // ThreadPriorityBoost
121 {FALSE
, 0}, // ThreadSetTlsArrayAddress
122 {TRUE
, 0}, // ThreadIsIoPending
123 {FALSE
, 0} // ThreadHideFromDebugger
126 /* FUNCTIONS *****************************************************************/
132 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
133 IN PROCESSINFOCLASS ProcessInformationClass
,
134 OUT PVOID ProcessInformation
,
135 IN ULONG ProcessInformationLength
,
136 OUT PULONG ReturnLength OPTIONAL
)
139 KPROCESSOR_MODE PreviousMode
;
140 NTSTATUS Status
= STATUS_SUCCESS
;
144 PreviousMode
= ExGetPreviousMode();
146 Status
= DefaultQueryInfoBufferCheck(ProcessInformationClass
,
148 sizeof(PsProcessInfoClass
) / sizeof(PsProcessInfoClass
[0]),
150 ProcessInformationLength
,
153 if(!NT_SUCCESS(Status
))
155 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status
);
159 if(ProcessInformationClass
!= ProcessCookie
)
161 Status
= ObReferenceObjectByHandle(ProcessHandle
,
162 PROCESS_QUERY_INFORMATION
,
167 if (!NT_SUCCESS(Status
))
172 else if(ProcessHandle
!= NtCurrentProcess())
174 /* retreiving the process cookie is only allowed for the calling process
175 itself! XP only allowes NtCurrentProcess() as process handles even if a
176 real handle actually represents the current process. */
177 return STATUS_INVALID_PARAMETER
;
180 switch (ProcessInformationClass
)
182 case ProcessBasicInformation
:
184 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
=
185 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
189 ProcessBasicInformationP
->ExitStatus
= Process
->ExitStatus
;
190 ProcessBasicInformationP
->PebBaseAddress
= Process
->Peb
;
191 ProcessBasicInformationP
->AffinityMask
= Process
->Pcb
.Affinity
;
192 ProcessBasicInformationP
->UniqueProcessId
=
193 (ULONG
)Process
->UniqueProcessId
;
194 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
195 (ULONG
)Process
->InheritedFromUniqueProcessId
;
196 ProcessBasicInformationP
->BasePriority
=
197 Process
->Pcb
.BasePriority
;
201 *ReturnLength
= sizeof(PROCESS_BASIC_INFORMATION
);
206 Status
= _SEH_GetExceptionCode();
212 case ProcessQuotaLimits
:
213 case ProcessIoCounters
:
214 Status
= STATUS_NOT_IMPLEMENTED
;
219 PKERNEL_USER_TIMES ProcessTimeP
= (PKERNEL_USER_TIMES
)ProcessInformation
;
222 ProcessTimeP
->CreateTime
= Process
->CreateTime
;
223 ProcessTimeP
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
* 100000LL;
224 ProcessTimeP
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
* 100000LL;
225 ProcessTimeP
->ExitTime
= Process
->ExitTime
;
229 *ReturnLength
= sizeof(KERNEL_USER_TIMES
);
234 Status
= _SEH_GetExceptionCode();
240 case ProcessDebugPort
:
244 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
!= NULL
? (HANDLE
)-1 : NULL
);
247 *ReturnLength
= sizeof(HANDLE
);
252 Status
= _SEH_GetExceptionCode();
258 case ProcessLdtInformation
:
259 case ProcessWorkingSetWatch
:
260 case ProcessWx86Information
:
261 Status
= STATUS_NOT_IMPLEMENTED
;
264 case ProcessHandleCount
:
266 ULONG HandleCount
= ObpGetHandleCountByHandleTable(Process
->ObjectTable
);
270 *(PULONG
)ProcessInformation
= HandleCount
;
273 *ReturnLength
= sizeof(ULONG
);
278 Status
= _SEH_GetExceptionCode();
284 case ProcessSessionInformation
:
286 PPROCESS_SESSION_INFORMATION SessionInfo
= (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
290 SessionInfo
->SessionId
= Process
->Session
;
293 *ReturnLength
= sizeof(PROCESS_SESSION_INFORMATION
);
298 Status
= _SEH_GetExceptionCode();
304 case ProcessWow64Information
:
305 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
306 Status
= STATUS_NOT_IMPLEMENTED
;
309 case ProcessVmCounters
:
311 PVM_COUNTERS pOut
= (PVM_COUNTERS
)ProcessInformation
;
315 pOut
->PeakVirtualSize
= Process
->PeakVirtualSize
;
317 * Here we should probably use VirtualSize.LowPart, but due to
318 * incompatibilities in current headers (no unnamed union),
321 pOut
->VirtualSize
= (ULONG
)Process
->VirtualSize
;
322 pOut
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
323 pOut
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
324 pOut
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
325 pOut
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0]; // TODO: Verify!
326 pOut
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0]; // TODO: Verify!
327 pOut
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1]; // TODO: Verify!
328 pOut
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1]; // TODO: Verify!
329 pOut
->PagefileUsage
= Process
->QuotaUsage
[2];
330 pOut
->PeakPagefileUsage
= Process
->QuotaPeak
[2];
334 *ReturnLength
= sizeof(VM_COUNTERS
);
339 Status
= _SEH_GetExceptionCode();
345 case ProcessDefaultHardErrorMode
:
347 PULONG HardErrMode
= (PULONG
)ProcessInformation
;
350 *HardErrMode
= Process
->DefaultHardErrorProcessing
;
353 *ReturnLength
= sizeof(ULONG
);
358 Status
= _SEH_GetExceptionCode();
364 case ProcessPriorityBoost
:
366 PULONG BoostEnabled
= (PULONG
)ProcessInformation
;
370 *BoostEnabled
= Process
->Pcb
.DisableBoost
? FALSE
: TRUE
;
374 *ReturnLength
= sizeof(ULONG
);
379 Status
= _SEH_GetExceptionCode();
385 case ProcessDeviceMap
:
387 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
389 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
393 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
396 *ReturnLength
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
401 Status
= _SEH_GetExceptionCode();
407 case ProcessPriorityClass
:
409 PUSHORT Priority
= (PUSHORT
)ProcessInformation
;
413 *Priority
= Process
->PriorityClass
;
417 *ReturnLength
= sizeof(USHORT
);
422 Status
= _SEH_GetExceptionCode();
428 case ProcessImageFileName
:
430 ULONG ImagePathLen
= 0;
431 PROS_SECTION_OBJECT Section
;
432 PUNICODE_STRING DstPath
= (PUNICODE_STRING
)ProcessInformation
;
433 PWSTR SrcBuffer
= NULL
, DstBuffer
= (PWSTR
)(DstPath
+ 1);
435 Section
= (PROS_SECTION_OBJECT
)Process
->SectionObject
;
437 if (Section
!= NULL
&& Section
->FileObject
!= NULL
)
439 /* FIXME - check for SEC_IMAGE and/or SEC_FILE instead
440 of relying on FileObject being != NULL? */
441 SrcBuffer
= Section
->FileObject
->FileName
.Buffer
;
442 if (SrcBuffer
!= NULL
)
444 ImagePathLen
= Section
->FileObject
->FileName
.Length
;
448 if(ProcessInformationLength
< sizeof(UNICODE_STRING
) + ImagePathLen
+ sizeof(WCHAR
))
450 Status
= STATUS_INFO_LENGTH_MISMATCH
;
456 /* copy the string manually, don't use RtlCopyUnicodeString with DstPath! */
457 DstPath
->Length
= ImagePathLen
;
458 DstPath
->MaximumLength
= ImagePathLen
+ sizeof(WCHAR
);
459 DstPath
->Buffer
= DstBuffer
;
460 if (ImagePathLen
!= 0)
462 RtlCopyMemory(DstBuffer
,
466 DstBuffer
[ImagePathLen
/ sizeof(WCHAR
)] = L
'\0';
468 Status
= STATUS_SUCCESS
;
472 Status
= _SEH_GetExceptionCode();
483 /* receive the process cookie, this is only allowed for the current
486 Process
= PsGetCurrentProcess();
488 Cookie
= Process
->Cookie
;
491 LARGE_INTEGER SystemTime
;
495 /* generate a new cookie */
497 KeQuerySystemTime(&SystemTime
);
499 Prcb
= KeGetCurrentPrcb();
501 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
502 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
504 /* try to set the new cookie, return the current one if another thread
505 set it in the meanwhile */
506 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
511 /* successfully set the cookie */
518 *(PULONG
)ProcessInformation
= Cookie
;
521 *ReturnLength
= sizeof(ULONG
);
526 Status
= _SEH_GetExceptionCode();
534 * Note: The following 10 information classes are verified to not be
535 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
537 case ProcessBasePriority
:
538 case ProcessRaisePriority
:
539 case ProcessExceptionPort
:
540 case ProcessAccessToken
:
542 case ProcessIoPortHandlers
:
543 case ProcessUserModeIOPL
:
544 case ProcessEnableAlignmentFaultFixup
:
545 case ProcessAffinityMask
:
546 case ProcessForegroundInformation
:
548 Status
= STATUS_INVALID_INFO_CLASS
;
551 if(ProcessInformationClass
!= ProcessCookie
)
553 ObDereferenceObject(Process
);
563 NtSetInformationProcess(IN HANDLE ProcessHandle
,
564 IN PROCESSINFOCLASS ProcessInformationClass
,
565 IN PVOID ProcessInformation
,
566 IN ULONG ProcessInformationLength
)
569 KPROCESSOR_MODE PreviousMode
;
571 NTSTATUS Status
= STATUS_SUCCESS
;
575 PreviousMode
= ExGetPreviousMode();
577 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
579 sizeof(PsProcessInfoClass
) / sizeof(PsProcessInfoClass
[0]),
581 ProcessInformationLength
,
583 if(!NT_SUCCESS(Status
))
585 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass
, ProcessInformation
, ProcessInformationLength
);
586 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status
);
590 switch(ProcessInformationClass
)
592 case ProcessSessionInformation
:
593 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_SESSIONID
;
595 case ProcessExceptionPort
:
596 Access
= PROCESS_SET_INFORMATION
| PROCESS_SUSPEND_RESUME
;
600 Access
= PROCESS_SET_INFORMATION
;
604 Status
= ObReferenceObjectByHandle(ProcessHandle
,
610 if (!NT_SUCCESS(Status
))
615 switch (ProcessInformationClass
)
617 case ProcessQuotaLimits
:
618 case ProcessBasePriority
:
619 case ProcessRaisePriority
:
620 Status
= STATUS_NOT_IMPLEMENTED
;
623 case ProcessExceptionPort
:
625 HANDLE PortHandle
= NULL
;
627 /* make a safe copy of the buffer on the stack */
630 PortHandle
= *(PHANDLE
)ProcessInformation
;
631 Status
= STATUS_SUCCESS
;
635 Status
= _SEH_GetExceptionCode();
639 if(NT_SUCCESS(Status
))
641 PEPORT ExceptionPort
;
643 /* in case we had success reading from the buffer, verify the provided
646 Status
= ObReferenceObjectByHandle(PortHandle
,
650 (PVOID
)&ExceptionPort
,
652 if(NT_SUCCESS(Status
))
654 /* lock the process to be thread-safe! */
656 Status
= PsLockProcess((PROS_EPROCESS
)Process
, FALSE
);
657 if(NT_SUCCESS(Status
))
660 * according to "NT Native API" documentation, setting the exception
661 * port is only permitted once!
663 if(Process
->ExceptionPort
== NULL
)
665 /* keep the reference to the handle! */
666 Process
->ExceptionPort
= ExceptionPort
;
667 Status
= STATUS_SUCCESS
;
671 ObDereferenceObject(ExceptionPort
);
672 Status
= STATUS_PORT_ALREADY_SET
;
674 PsUnlockProcess((PROS_EPROCESS
)Process
);
678 ObDereferenceObject(ExceptionPort
);
685 case ProcessAccessToken
:
687 HANDLE TokenHandle
= NULL
;
689 /* make a safe copy of the buffer on the stack */
692 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->Token
;
693 Status
= STATUS_SUCCESS
;
697 Status
= _SEH_GetExceptionCode();
701 if(NT_SUCCESS(Status
))
703 /* in case we had success reading from the buffer, perform the actual task */
704 Status
= PspAssignPrimaryToken(Process
, TokenHandle
);
709 case ProcessDefaultHardErrorMode
:
713 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
714 *(PLONG
)ProcessInformation
);
715 Status
= STATUS_SUCCESS
;
719 Status
= _SEH_GetExceptionCode();
725 case ProcessSessionInformation
:
727 PROCESS_SESSION_INFORMATION SessionInfo
;
728 Status
= STATUS_SUCCESS
;
730 RtlZeroMemory(&SessionInfo
, sizeof(SessionInfo
));
734 /* copy the structure to the stack */
735 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
739 Status
= _SEH_GetExceptionCode();
743 if(NT_SUCCESS(Status
))
745 /* we successfully copied the structure to the stack, continue processing */
748 * setting the session id requires the SeTcbPrivilege!
750 if(!SeSinglePrivilegeCheck(SeTcbPrivilege
,
753 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
754 /* can't set the session id, bail! */
755 Status
= STATUS_PRIVILEGE_NOT_HELD
;
759 /* FIXME - update the session id for the process token */
761 Status
= PsLockProcess((PROS_EPROCESS
)Process
, FALSE
);
762 if(NT_SUCCESS(Status
))
764 Process
->Session
= SessionInfo
.SessionId
;
766 /* Update the session id in the PEB structure */
767 if(Process
->Peb
!= NULL
)
769 /* we need to attach to the process to make sure we're in the right
770 context to access the PEB structure */
771 KeAttachProcess(&Process
->Pcb
);
775 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
777 Status
= STATUS_SUCCESS
;
781 Status
= _SEH_GetExceptionCode();
788 PsUnlockProcess((PROS_EPROCESS
)Process
);
794 case ProcessPriorityClass
:
796 PROCESS_PRIORITY_CLASS ppc
;
800 ppc
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
804 Status
= _SEH_GetExceptionCode();
808 if(NT_SUCCESS(Status
))
815 case ProcessLdtInformation
:
817 case ProcessIoPortHandlers
:
818 case ProcessWorkingSetWatch
:
819 case ProcessUserModeIOPL
:
820 case ProcessEnableAlignmentFaultFixup
:
821 case ProcessAffinityMask
:
822 Status
= STATUS_NOT_IMPLEMENTED
;
825 case ProcessBasicInformation
:
826 case ProcessIoCounters
:
828 case ProcessPooledUsageAndLimits
:
829 case ProcessWx86Information
:
830 case ProcessHandleCount
:
831 case ProcessWow64Information
:
832 case ProcessDebugPort
:
834 Status
= STATUS_INVALID_INFO_CLASS
;
836 ObDereferenceObject(Process
);
841 /**********************************************************************
843 * PiQuerySystemProcessInformation
846 * Compute the size of a process+thread snapshot as
847 * expected by NtQuerySystemInformation.
850 * 0 on error; otherwise the size, in bytes of the buffer
851 * required to write a full snapshot.
854 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
857 PiQuerySystemProcessInformation(PVOID Buffer
,
861 return STATUS_NOT_IMPLEMENTED
;
864 PLIST_ENTRY CurrentEntryP
;
866 PLIST_ENTRY CurrentEntryT
;
869 ULONG RequiredSize
= 0L;
870 BOOLEAN SizeOnly
= FALSE
;
874 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
875 PSYSTEM_PROCESS_INFORMATION pInfoPLast
= NULL
;
876 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
879 /* Lock the process list. */
880 ExAcquireFastMutex(&PspActiveProcessMutex
);
883 * Scan the process list. Since the
884 * list is circular, the guard is false
885 * after the last process.
887 for ( CurrentEntryP
= PsActiveProcessHead
.Flink
;
888 (CurrentEntryP
!= & PsActiveProcessHead
);
889 CurrentEntryP
= CurrentEntryP
->Flink
893 * Compute how much space is
894 * occupied in the snapshot
895 * by adding this process info.
896 * (at least one thread).
898 SpiSizeCurrent
= sizeof (SYSTEM_PROCESS_INFORMATION
);
899 RequiredSize
+= SpiSizeCurrent
;
901 * Do not write process data in the
902 * buffer if it is too small.
904 if (TRUE
== SizeOnly
) continue;
906 * Check if the buffer can contain
909 if (Size
< RequiredSize
)
915 * Get a reference to the
916 * process descriptor we are
919 CurrentP
= CONTAINING_RECORD(
925 * Write process data in the buffer.
927 RtlZeroMemory (pInfoP
, sizeof (SYSTEM_PROCESS_INFORMATION
));
929 pInfoP
->ThreadCount
= 0L;
930 pInfoP
->ProcessId
= CurrentP
->UniqueProcessId
;
931 RtlInitUnicodeString (
933 CurrentP
->ImageFileName
936 for ( pInfoT
= & CurrentP
->ThreadSysInfo
[0],
937 CurrentEntryT
= CurrentP
->ThreadListHead
.Flink
;
939 (CurrentEntryT
!= & CurrentP
->ThreadListHead
);
941 pInfoT
= & CurrentP
->ThreadSysInfo
[pInfoP
->ThreadCount
],
942 CurrentEntryT
= CurrentEntryT
->Flink
946 * Recalculate the size of the
949 if (0 < pInfoP
->ThreadCount
)
951 RequiredSize
+= sizeof (SYSTEM_THREAD_INFORMATION
);
954 * Do not write thread data in the
955 * buffer if it is too small.
957 if (TRUE
== SizeOnly
) continue;
959 * Check if the buffer can contain
962 if (Size
< RequiredSize
)
968 * Get a reference to the
969 * thread descriptor we are
972 CurrentT
= CONTAINING_RECORD(
982 sizeof (SYSTEM_THREAD_INFORMATION
)
984 pInfoT
->KernelTime
= CurrentT
-> ; /* TIME */
985 pInfoT
->UserTime
= CurrentT
-> ; /* TIME */
986 pInfoT
->CreateTime
= CurrentT
-> ; /* TIME */
987 pInfoT
->TickCount
= CurrentT
-> ; /* ULONG */
988 pInfoT
->StartEIP
= CurrentT
-> ; /* ULONG */
989 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
990 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
991 pInfoT
->DynamicPriority
= CurrentT
-> ; /* ULONG */
992 pInfoT
->BasePriority
= CurrentT
-> ; /* ULONG */
993 pInfoT
->nSwitches
= CurrentT
-> ; /* ULONG */
994 pInfoT
->State
= CurrentT
-> ; /* DWORD */
995 pInfoT
->WaitReason
= CurrentT
-> ; /* KWAIT_REASON */
997 * Count the number of threads
1000 ++ pInfoP
->ThreadCount
;
1003 * Save the size of information
1004 * stored in the buffer for the
1007 pInfoP
->RelativeOffset
= SpiSize
;
1009 * Save a reference to the last
1010 * valid information block.
1012 pInfoPLast
= pInfoP
;
1014 * Compute the offset of the
1015 * SYSTEM_PROCESS_INFORMATION
1016 * descriptor in the snapshot
1017 * buffer for the next process.
1019 (ULONG
) pInfoP
+= SpiSize
;
1022 * Unlock the process list.
1024 ExReleaseFastMutex (
1025 & PspActiveProcessMutex
1028 * Return the proper error status code,
1029 * if the buffer was too small.
1031 if (TRUE
== SizeOnly
)
1033 if (NULL
!= RequiredSize
)
1035 *pRequiredSize
= RequiredSize
;
1037 return STATUS_INFO_LENGTH_MISMATCH
;
1040 * Mark the end of the snapshot.
1042 pInfoP
->RelativeOffset
= 0L;
1044 return STATUS_SUCCESS
;
1052 NtSetInformationThread (IN HANDLE ThreadHandle
,
1053 IN THREADINFOCLASS ThreadInformationClass
,
1054 IN PVOID ThreadInformation
,
1055 IN ULONG ThreadInformationLength
)
1066 KPROCESSOR_MODE PreviousMode
;
1067 NTSTATUS Status
= STATUS_SUCCESS
;
1071 PreviousMode
= ExGetPreviousMode();
1073 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1074 !SetInformationData
[ThreadInformationClass
].Implemented
)
1076 return STATUS_NOT_IMPLEMENTED
;
1078 if (ThreadInformationClass
> MaxThreadInfoClass
||
1079 SetInformationData
[ThreadInformationClass
].Size
== 0)
1081 return STATUS_INVALID_INFO_CLASS
;
1083 if (ThreadInformationLength
!= SetInformationData
[ThreadInformationClass
].Size
)
1085 return STATUS_INFO_LENGTH_MISMATCH
;
1088 if (PreviousMode
!= KernelMode
)
1092 ProbeForRead(ThreadInformation
,
1093 SetInformationData
[ThreadInformationClass
].Size
,
1095 RtlCopyMemory(&u
.Priority
,
1097 SetInformationData
[ThreadInformationClass
].Size
);
1101 Status
= _SEH_GetExceptionCode();
1105 if (!NT_SUCCESS(Status
))
1112 RtlCopyMemory(&u
.Priority
,
1114 SetInformationData
[ThreadInformationClass
].Size
);
1117 /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
1118 /* FIXME: We should also check for certain things before doing the reference */
1119 Status
= ObReferenceObjectByHandle (ThreadHandle
,
1120 THREAD_SET_INFORMATION
,
1122 ExGetPreviousMode (),
1125 if (NT_SUCCESS(Status
))
1127 switch (ThreadInformationClass
)
1129 case ThreadPriority
:
1130 if (u
.Priority
< LOW_PRIORITY
|| u
.Priority
>= MAXIMUM_PRIORITY
)
1132 Status
= STATUS_INVALID_PARAMETER
;
1135 KeSetPriorityThread(&Thread
->Tcb
, u
.Priority
);
1138 case ThreadBasePriority
:
1139 KeSetBasePriorityThread (&Thread
->Tcb
, u
.Increment
);
1142 case ThreadAffinityMask
:
1144 /* Check if this is valid */
1145 DPRINT1("%lx, %lx\n", Thread
->ThreadsProcess
->Pcb
.Affinity
, u
.Affinity
);
1146 if ((Thread
->ThreadsProcess
->Pcb
.Affinity
& u
.Affinity
) !=
1149 DPRINT1("Wrong affinity given\n");
1150 Status
= STATUS_INVALID_PARAMETER
;
1154 Status
= KeSetAffinityThread(&Thread
->Tcb
, u
.Affinity
);
1158 case ThreadImpersonationToken
:
1159 Status
= PsAssignImpersonationToken (Thread
, u
.Handle
);
1162 case ThreadQuerySetWin32StartAddress
:
1163 Thread
->Win32StartAddress
= u
.Address
;
1167 /* Shoult never occure if the data table is correct */
1170 ObDereferenceObject (Thread
);
1180 NtQueryInformationThread (IN HANDLE ThreadHandle
,
1181 IN THREADINFOCLASS ThreadInformationClass
,
1182 OUT PVOID ThreadInformation
,
1183 IN ULONG ThreadInformationLength
,
1184 OUT PULONG ReturnLength OPTIONAL
)
1189 THREAD_BASIC_INFORMATION TBI
;
1190 KERNEL_USER_TIMES TTI
;
1192 LARGE_INTEGER Count
;
1195 KPROCESSOR_MODE PreviousMode
;
1196 NTSTATUS Status
= STATUS_SUCCESS
;
1200 PreviousMode
= ExGetPreviousMode();
1202 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1203 !QueryInformationData
[ThreadInformationClass
].Implemented
)
1205 return STATUS_NOT_IMPLEMENTED
;
1207 if (ThreadInformationClass
> MaxThreadInfoClass
||
1208 QueryInformationData
[ThreadInformationClass
].Size
== 0)
1210 return STATUS_INVALID_INFO_CLASS
;
1212 if (ThreadInformationLength
!= QueryInformationData
[ThreadInformationClass
].Size
)
1214 return STATUS_INFO_LENGTH_MISMATCH
;
1217 if (PreviousMode
!= KernelMode
)
1221 ProbeForWrite(ThreadInformation
,
1222 QueryInformationData
[ThreadInformationClass
].Size
,
1224 if (ReturnLength
!= NULL
)
1226 ProbeForWriteUlong(ReturnLength
);
1231 Status
= _SEH_GetExceptionCode();
1235 if (!NT_SUCCESS(Status
))
1241 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1242 THREAD_QUERY_INFORMATION
,
1244 ExGetPreviousMode(),
1247 if (!NT_SUCCESS(Status
))
1252 switch (ThreadInformationClass
)
1254 case ThreadBasicInformation
:
1255 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1256 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1257 * 0. So do the conversion here:
1259 u
.TBI
.ExitStatus
= (Thread
->ExitStatus
== 0) ? STATUS_PENDING
: Thread
->ExitStatus
;
1260 u
.TBI
.TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
1261 u
.TBI
.ClientId
= Thread
->Cid
;
1262 u
.TBI
.AffinityMask
= Thread
->Tcb
.Affinity
;
1263 u
.TBI
.Priority
= Thread
->Tcb
.Priority
;
1264 u
.TBI
.BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
1268 u
.TTI
.KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* 100000LL;
1269 u
.TTI
.UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* 100000LL;
1270 u
.TTI
.CreateTime
= Thread
->CreateTime
;
1272 u
.TTI
.ExitTime
= Thread
->ExitTime
;
1275 case ThreadQuerySetWin32StartAddress
:
1276 u
.Address
= Thread
->Win32StartAddress
;
1279 case ThreadPerformanceCount
:
1280 /* Nebbett says this class is always zero */
1281 u
.Count
.QuadPart
= 0;
1284 case ThreadAmILastThread
:
1285 if (Thread
->ThreadsProcess
->ThreadListHead
.Flink
->Flink
==
1286 &Thread
->ThreadsProcess
->ThreadListHead
)
1296 /* Shoult never occure if the data table is correct */
1300 if (PreviousMode
!= KernelMode
)
1304 if (QueryInformationData
[ThreadInformationClass
].Size
)
1306 RtlCopyMemory(ThreadInformation
,
1308 QueryInformationData
[ThreadInformationClass
].Size
);
1310 if (ReturnLength
!= NULL
)
1312 *ReturnLength
= QueryInformationData
[ThreadInformationClass
].Size
;
1317 Status
= _SEH_GetExceptionCode();
1323 if (QueryInformationData
[ThreadInformationClass
].Size
)
1325 RtlCopyMemory(ThreadInformation
,
1327 QueryInformationData
[ThreadInformationClass
].Size
);
1330 if (ReturnLength
!= NULL
)
1332 *ReturnLength
= QueryInformationData
[ThreadInformationClass
].Size
;
1336 ObDereferenceObject(Thread
);