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 DefaultQueryInfoBufferCheck(ProcessInformationClass
,
149 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 Process
->UniqueProcessId
;
194 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
195 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
:
431 * We DO NOT return the file name stored in the EPROCESS structure.
432 * Propably if we can't find a PEB or ProcessParameters structure for the
435 if(Process
->Peb
!= NULL
)
437 PRTL_USER_PROCESS_PARAMETERS ProcParams
= NULL
;
438 UNICODE_STRING LocalDest
;
440 ULONG ImagePathLen
= 0;
441 PUNICODE_STRING DstPath
= (PUNICODE_STRING
)ProcessInformation
;
443 /* we need to attach to the process to make sure we're in the right context! */
444 Attached
= Process
!= PsGetCurrentProcess();
447 KeAttachProcess(&Process
->Pcb
);
451 ProcParams
= Process
->Peb
->ProcessParameters
;
452 ImagePathLen
= ProcParams
->ImagePathName
.Length
;
456 Status
= _SEH_GetExceptionCode();
460 if(NT_SUCCESS(Status
))
462 if(ProcessInformationLength
< sizeof(UNICODE_STRING
) + ImagePathLen
+ sizeof(WCHAR
))
464 Status
= STATUS_INFO_LENGTH_MISMATCH
;
468 PWSTR StrSource
= NULL
;
470 RtlZeroMemory(&LocalDest
, sizeof(LocalDest
));
472 /* create a DstPath structure on the stack */
475 LocalDest
.Length
= ImagePathLen
;
476 LocalDest
.MaximumLength
= ImagePathLen
+ sizeof(WCHAR
);
477 LocalDest
.Buffer
= (PWSTR
)(DstPath
+ 1);
479 /* save a copy of the pointer to the source buffer */
480 StrSource
= ProcParams
->ImagePathName
.Buffer
;
484 Status
= _SEH_GetExceptionCode();
488 if(NT_SUCCESS(Status
))
490 /* now, let's allocate some anonymous memory to copy the string to.
491 we can't just copy it to the buffer the caller pointed as it might
492 be user memory in another context */
493 PWSTR PathCopy
= ExAllocatePool(PagedPool
, LocalDest
.Length
+ sizeof(WCHAR
));
496 /* make a copy of the buffer to the temporary buffer */
499 RtlCopyMemory(PathCopy
, StrSource
, LocalDest
.Length
);
500 PathCopy
[LocalDest
.Length
/ sizeof(WCHAR
)] = L
'\0';
504 Status
= _SEH_GetExceptionCode();
508 /* detach from the process */
512 /* only copy the string back to the caller if we were able to
513 copy it into the temporary buffer! */
514 if(NT_SUCCESS(Status
))
516 /* now let's copy the buffer back to the caller */
519 *DstPath
= LocalDest
;
520 RtlCopyMemory(LocalDest
.Buffer
, PathCopy
, LocalDest
.Length
+ sizeof(WCHAR
));
523 *ReturnLength
= sizeof(UNICODE_STRING
) + LocalDest
.Length
+ sizeof(WCHAR
);
528 Status
= _SEH_GetExceptionCode();
533 /* we're done with the copy operation, free the temporary kernel buffer */
534 ExFreePool(PathCopy
);
536 /* we need to bail because we're already detached from the process */
541 Status
= STATUS_INSUFFICIENT_RESOURCES
;
547 /* don't forget to detach from the process!!! */
553 /* FIXME - what to do here? */
554 Status
= STATUS_UNSUCCESSFUL
;
563 /* receive the process cookie, this is only allowed for the current
566 Process
= PsGetCurrentProcess();
568 Cookie
= Process
->Cookie
;
571 LARGE_INTEGER SystemTime
;
575 /* generate a new cookie */
577 KeQuerySystemTime(&SystemTime
);
579 Prcb
= KeGetCurrentPrcb();
581 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
582 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
584 /* try to set the new cookie, return the current one if another thread
585 set it in the meanwhile */
586 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
591 /* successfully set the cookie */
598 *(PULONG
)ProcessInformation
= Cookie
;
601 *ReturnLength
= sizeof(ULONG
);
606 Status
= _SEH_GetExceptionCode();
614 * Note: The following 10 information classes are verified to not be
615 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
617 case ProcessBasePriority
:
618 case ProcessRaisePriority
:
619 case ProcessExceptionPort
:
620 case ProcessAccessToken
:
622 case ProcessIoPortHandlers
:
623 case ProcessUserModeIOPL
:
624 case ProcessEnableAlignmentFaultFixup
:
625 case ProcessAffinityMask
:
626 case ProcessForegroundInformation
:
628 Status
= STATUS_INVALID_INFO_CLASS
;
631 if(ProcessInformationClass
!= ProcessCookie
)
633 ObDereferenceObject(Process
);
643 NtSetInformationProcess(IN HANDLE ProcessHandle
,
644 IN PROCESSINFOCLASS ProcessInformationClass
,
645 IN PVOID ProcessInformation
,
646 IN ULONG ProcessInformationLength
)
649 KPROCESSOR_MODE PreviousMode
;
651 NTSTATUS Status
= STATUS_SUCCESS
;
655 PreviousMode
= ExGetPreviousMode();
657 DefaultSetInfoBufferCheck(ProcessInformationClass
,
660 ProcessInformationLength
,
663 if(!NT_SUCCESS(Status
))
665 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass
, ProcessInformation
, ProcessInformationLength
);
666 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status
);
670 switch(ProcessInformationClass
)
672 case ProcessSessionInformation
:
673 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_SESSIONID
;
675 case ProcessExceptionPort
:
676 Access
= PROCESS_SET_INFORMATION
| PROCESS_SUSPEND_RESUME
;
680 Access
= PROCESS_SET_INFORMATION
;
684 Status
= ObReferenceObjectByHandle(ProcessHandle
,
690 if (!NT_SUCCESS(Status
))
695 switch (ProcessInformationClass
)
697 case ProcessQuotaLimits
:
698 case ProcessBasePriority
:
699 case ProcessRaisePriority
:
700 Status
= STATUS_NOT_IMPLEMENTED
;
703 case ProcessExceptionPort
:
705 HANDLE PortHandle
= NULL
;
707 /* make a safe copy of the buffer on the stack */
710 PortHandle
= *(PHANDLE
)ProcessInformation
;
711 Status
= STATUS_SUCCESS
;
715 Status
= _SEH_GetExceptionCode();
719 if(NT_SUCCESS(Status
))
721 PEPORT ExceptionPort
;
723 /* in case we had success reading from the buffer, verify the provided
726 Status
= ObReferenceObjectByHandle(PortHandle
,
730 (PVOID
)&ExceptionPort
,
732 if(NT_SUCCESS(Status
))
734 /* lock the process to be thread-safe! */
736 Status
= PsLockProcess(Process
, FALSE
);
737 if(NT_SUCCESS(Status
))
740 * according to "NT Native API" documentation, setting the exception
741 * port is only permitted once!
743 if(Process
->ExceptionPort
== NULL
)
745 /* keep the reference to the handle! */
746 Process
->ExceptionPort
= ExceptionPort
;
747 Status
= STATUS_SUCCESS
;
751 ObDereferenceObject(ExceptionPort
);
752 Status
= STATUS_PORT_ALREADY_SET
;
754 PsUnlockProcess(Process
);
758 ObDereferenceObject(ExceptionPort
);
765 case ProcessAccessToken
:
767 HANDLE TokenHandle
= NULL
;
769 /* make a safe copy of the buffer on the stack */
772 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->Token
;
773 Status
= STATUS_SUCCESS
;
777 Status
= _SEH_GetExceptionCode();
781 if(NT_SUCCESS(Status
))
783 /* in case we had success reading from the buffer, perform the actual task */
784 Status
= PspAssignPrimaryToken(Process
, TokenHandle
);
789 case ProcessDefaultHardErrorMode
:
793 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
794 *(PLONG
)ProcessInformation
);
795 Status
= STATUS_SUCCESS
;
799 Status
= _SEH_GetExceptionCode();
805 case ProcessSessionInformation
:
807 PROCESS_SESSION_INFORMATION SessionInfo
;
808 Status
= STATUS_SUCCESS
;
810 RtlZeroMemory(&SessionInfo
, sizeof(SessionInfo
));
814 /* copy the structure to the stack */
815 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
819 Status
= _SEH_GetExceptionCode();
823 if(NT_SUCCESS(Status
))
825 /* we successfully copied the structure to the stack, continue processing */
828 * setting the session id requires the SeTcbPrivilege!
830 if(!SeSinglePrivilegeCheck(SeTcbPrivilege
,
833 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
834 /* can't set the session id, bail! */
835 Status
= STATUS_PRIVILEGE_NOT_HELD
;
839 /* FIXME - update the session id for the process token */
841 Status
= PsLockProcess(Process
, FALSE
);
842 if(NT_SUCCESS(Status
))
844 Process
->Session
= SessionInfo
.SessionId
;
846 /* Update the session id in the PEB structure */
847 if(Process
->Peb
!= NULL
)
849 /* we need to attach to the process to make sure we're in the right
850 context to access the PEB structure */
851 KeAttachProcess(&Process
->Pcb
);
855 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
857 Status
= STATUS_SUCCESS
;
861 Status
= _SEH_GetExceptionCode();
868 PsUnlockProcess(Process
);
874 case ProcessPriorityClass
:
876 PROCESS_PRIORITY_CLASS ppc
;
880 ppc
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
884 Status
= _SEH_GetExceptionCode();
888 if(NT_SUCCESS(Status
))
895 case ProcessLdtInformation
:
897 case ProcessIoPortHandlers
:
898 case ProcessWorkingSetWatch
:
899 case ProcessUserModeIOPL
:
900 case ProcessEnableAlignmentFaultFixup
:
901 case ProcessAffinityMask
:
902 Status
= STATUS_NOT_IMPLEMENTED
;
905 case ProcessBasicInformation
:
906 case ProcessIoCounters
:
908 case ProcessPooledUsageAndLimits
:
909 case ProcessWx86Information
:
910 case ProcessHandleCount
:
911 case ProcessWow64Information
:
912 case ProcessDebugPort
:
914 Status
= STATUS_INVALID_INFO_CLASS
;
916 ObDereferenceObject(Process
);
921 /**********************************************************************
923 * PiQuerySystemProcessInformation
926 * Compute the size of a process+thread snapshot as
927 * expected by NtQuerySystemInformation.
930 * 0 on error; otherwise the size, in bytes of the buffer
931 * required to write a full snapshot.
934 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
937 PiQuerySystemProcessInformation(PVOID Buffer
,
941 return STATUS_NOT_IMPLEMENTED
;
944 PLIST_ENTRY CurrentEntryP
;
946 PLIST_ENTRY CurrentEntryT
;
949 ULONG RequiredSize
= 0L;
950 BOOLEAN SizeOnly
= FALSE
;
954 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
955 PSYSTEM_PROCESS_INFORMATION pInfoPLast
= NULL
;
956 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
959 /* Lock the process list. */
960 ExAcquireFastMutex(&PspActiveProcessMutex
);
963 * Scan the process list. Since the
964 * list is circular, the guard is false
965 * after the last process.
967 for ( CurrentEntryP
= PsActiveProcessHead
.Flink
;
968 (CurrentEntryP
!= & PsActiveProcessHead
);
969 CurrentEntryP
= CurrentEntryP
->Flink
973 * Compute how much space is
974 * occupied in the snapshot
975 * by adding this process info.
976 * (at least one thread).
978 SpiSizeCurrent
= sizeof (SYSTEM_PROCESS_INFORMATION
);
979 RequiredSize
+= SpiSizeCurrent
;
981 * Do not write process data in the
982 * buffer if it is too small.
984 if (TRUE
== SizeOnly
) continue;
986 * Check if the buffer can contain
989 if (Size
< RequiredSize
)
995 * Get a reference to the
996 * process descriptor we are
999 CurrentP
= CONTAINING_RECORD(
1005 * Write process data in the buffer.
1007 RtlZeroMemory (pInfoP
, sizeof (SYSTEM_PROCESS_INFORMATION
));
1009 pInfoP
->ThreadCount
= 0L;
1010 pInfoP
->ProcessId
= CurrentP
->UniqueProcessId
;
1011 RtlInitUnicodeString (
1013 CurrentP
->ImageFileName
1016 for ( pInfoT
= & CurrentP
->ThreadSysInfo
[0],
1017 CurrentEntryT
= CurrentP
->ThreadListHead
.Flink
;
1019 (CurrentEntryT
!= & CurrentP
->ThreadListHead
);
1021 pInfoT
= & CurrentP
->ThreadSysInfo
[pInfoP
->ThreadCount
],
1022 CurrentEntryT
= CurrentEntryT
->Flink
1026 * Recalculate the size of the
1027 * information block.
1029 if (0 < pInfoP
->ThreadCount
)
1031 RequiredSize
+= sizeof (SYSTEM_THREAD_INFORMATION
);
1034 * Do not write thread data in the
1035 * buffer if it is too small.
1037 if (TRUE
== SizeOnly
) continue;
1039 * Check if the buffer can contain
1040 * the full snapshot.
1042 if (Size
< RequiredSize
)
1048 * Get a reference to the
1049 * thread descriptor we are
1052 CurrentT
= CONTAINING_RECORD(
1058 * Write thread data.
1062 sizeof (SYSTEM_THREAD_INFORMATION
)
1064 pInfoT
->KernelTime
= CurrentT
-> ; /* TIME */
1065 pInfoT
->UserTime
= CurrentT
-> ; /* TIME */
1066 pInfoT
->CreateTime
= CurrentT
-> ; /* TIME */
1067 pInfoT
->TickCount
= CurrentT
-> ; /* ULONG */
1068 pInfoT
->StartEIP
= CurrentT
-> ; /* ULONG */
1069 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
1070 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
1071 pInfoT
->DynamicPriority
= CurrentT
-> ; /* ULONG */
1072 pInfoT
->BasePriority
= CurrentT
-> ; /* ULONG */
1073 pInfoT
->nSwitches
= CurrentT
-> ; /* ULONG */
1074 pInfoT
->State
= CurrentT
-> ; /* DWORD */
1075 pInfoT
->WaitReason
= CurrentT
-> ; /* KWAIT_REASON */
1077 * Count the number of threads
1080 ++ pInfoP
->ThreadCount
;
1083 * Save the size of information
1084 * stored in the buffer for the
1087 pInfoP
->RelativeOffset
= SpiSize
;
1089 * Save a reference to the last
1090 * valid information block.
1092 pInfoPLast
= pInfoP
;
1094 * Compute the offset of the
1095 * SYSTEM_PROCESS_INFORMATION
1096 * descriptor in the snapshot
1097 * buffer for the next process.
1099 (ULONG
) pInfoP
+= SpiSize
;
1102 * Unlock the process list.
1104 ExReleaseFastMutex (
1105 & PspActiveProcessMutex
1108 * Return the proper error status code,
1109 * if the buffer was too small.
1111 if (TRUE
== SizeOnly
)
1113 if (NULL
!= RequiredSize
)
1115 *pRequiredSize
= RequiredSize
;
1117 return STATUS_INFO_LENGTH_MISMATCH
;
1120 * Mark the end of the snapshot.
1122 pInfoP
->RelativeOffset
= 0L;
1124 return STATUS_SUCCESS
;
1132 NtSetInformationThread (IN HANDLE ThreadHandle
,
1133 IN THREADINFOCLASS ThreadInformationClass
,
1134 IN PVOID ThreadInformation
,
1135 IN ULONG ThreadInformationLength
)
1150 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1151 !SetInformationData
[ThreadInformationClass
].Implemented
)
1153 return STATUS_NOT_IMPLEMENTED
;
1155 if (ThreadInformationClass
> MaxThreadInfoClass
||
1156 SetInformationData
[ThreadInformationClass
].Size
== 0)
1158 return STATUS_INVALID_INFO_CLASS
;
1160 if (ThreadInformationLength
!= SetInformationData
[ThreadInformationClass
].Size
)
1162 return STATUS_INFO_LENGTH_MISMATCH
;
1165 Status
= ObReferenceObjectByHandle (ThreadHandle
,
1166 THREAD_SET_INFORMATION
,
1168 ExGetPreviousMode (),
1171 if (!NT_SUCCESS(Status
))
1176 Status
= MmCopyFromCaller(&u
.Priority
,
1178 SetInformationData
[ThreadInformationClass
].Size
);
1179 if (NT_SUCCESS(Status
))
1181 switch (ThreadInformationClass
)
1183 case ThreadPriority
:
1184 if (u
.Priority
< LOW_PRIORITY
|| u
.Priority
>= MAXIMUM_PRIORITY
)
1186 Status
= STATUS_INVALID_PARAMETER
;
1189 KeSetPriorityThread(&Thread
->Tcb
, u
.Priority
);
1192 case ThreadBasePriority
:
1193 KeSetBasePriorityThread (&Thread
->Tcb
, u
.Increment
);
1196 case ThreadAffinityMask
:
1197 Status
= KeSetAffinityThread(&Thread
->Tcb
, u
.Affinity
);
1200 case ThreadImpersonationToken
:
1201 Status
= PsAssignImpersonationToken (Thread
, u
.Handle
);
1204 case ThreadQuerySetWin32StartAddress
:
1205 Thread
->Win32StartAddress
= u
.Address
;
1209 /* Shoult never occure if the data table is correct */
1213 ObDereferenceObject (Thread
);
1222 NtQueryInformationThread (IN HANDLE ThreadHandle
,
1223 IN THREADINFOCLASS ThreadInformationClass
,
1224 OUT PVOID ThreadInformation
,
1225 IN ULONG ThreadInformationLength
,
1226 OUT PULONG ReturnLength OPTIONAL
)
1232 THREAD_BASIC_INFORMATION TBI
;
1233 KERNEL_USER_TIMES TTI
;
1235 LARGE_INTEGER Count
;
1241 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1242 !QueryInformationData
[ThreadInformationClass
].Implemented
)
1244 return STATUS_NOT_IMPLEMENTED
;
1246 if (ThreadInformationClass
> MaxThreadInfoClass
||
1247 QueryInformationData
[ThreadInformationClass
].Size
== 0)
1249 return STATUS_INVALID_INFO_CLASS
;
1251 if (ThreadInformationLength
!= QueryInformationData
[ThreadInformationClass
].Size
)
1253 return STATUS_INFO_LENGTH_MISMATCH
;
1256 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1257 THREAD_QUERY_INFORMATION
,
1259 ExGetPreviousMode(),
1262 if (!NT_SUCCESS(Status
))
1267 switch (ThreadInformationClass
)
1269 case ThreadBasicInformation
:
1270 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1271 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1272 * 0. So do the conversion here:
1274 u
.TBI
.ExitStatus
= (Thread
->ExitStatus
== 0) ? STATUS_PENDING
: Thread
->ExitStatus
;
1275 u
.TBI
.TebBaseAddress
= Thread
->Tcb
.Teb
;
1276 u
.TBI
.ClientId
= Thread
->Cid
;
1277 u
.TBI
.AffinityMask
= Thread
->Tcb
.Affinity
;
1278 u
.TBI
.Priority
= Thread
->Tcb
.Priority
;
1279 u
.TBI
.BasePriority
= Thread
->Tcb
.BasePriority
;
1283 u
.TTI
.KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* 100000LL;
1284 u
.TTI
.UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* 100000LL;
1285 u
.TTI
.CreateTime
= Thread
->CreateTime
;
1287 u
.TTI
.ExitTime
= Thread
->ExitTime
;
1290 case ThreadQuerySetWin32StartAddress
:
1291 u
.Address
= Thread
->Win32StartAddress
;
1294 case ThreadPerformanceCount
:
1295 /* Nebbett says this class is always zero */
1296 u
.Count
.QuadPart
= 0;
1299 case ThreadAmILastThread
:
1300 if (Thread
->ThreadsProcess
->ThreadListHead
.Flink
->Flink
==
1301 &Thread
->ThreadsProcess
->ThreadListHead
)
1311 /* Shoult never occure if the data table is correct */
1314 if (QueryInformationData
[ThreadInformationClass
].Size
)
1316 Status
= MmCopyToCaller(ThreadInformation
,
1318 QueryInformationData
[ThreadInformationClass
].Size
);
1323 static ULONG Null
= 0;
1324 Status2
= MmCopyToCaller(ReturnLength
,
1325 NT_SUCCESS(Status
) ? &QueryInformationData
[ThreadInformationClass
].Size
: &Null
,
1327 if (NT_SUCCESS(Status
))
1333 ObDereferenceObject(Thread
);