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 ******************************************************************/
20 static const INFORMATION_CLASS_INFO PsProcessInfoClass
[] =
22 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessBasicInformation */
23 ICI_SQ_SAME( sizeof(QUOTA_LIMITS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessQuotaLimits */
24 ICI_SQ_SAME( sizeof(IO_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessIoCounters */
25 ICI_SQ_SAME( sizeof(VM_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessVmCounters */
26 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessTimes */
27 ICI_SQ_SAME( sizeof(KPRIORITY
), sizeof(ULONG
), ICIF_SET
), /* ProcessBasePriority */
28 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_SET
), /* ProcessRaisePriority */
29 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessDebugPort */
30 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_SET
), /* ProcessExceptionPort */
31 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN
), sizeof(ULONG
), ICIF_SET
), /* ProcessAccessToken */
32 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessLdtInformation */
33 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessLdtSize */
34 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessDefaultHardErrorMode */
35 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessIoPortHandlers */
36 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessPooledUsageAndLimits */
37 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessWorkingSetWatch */
38 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG
), ICIF_SET
), /* ProcessUserModeIOPL */
39 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(ULONG
), ICIF_SET
), /* ProcessEnableAlignmentFaultFixup */
40 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS
), sizeof(USHORT
), ICIF_QUERY
| ICIF_SET
), /* ProcessPriorityClass */
41 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWx86Information */
42 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessHandleCount */
43 ICI_SQ_SAME( sizeof(KAFFINITY
), sizeof(ULONG
), ICIF_SET
), /* ProcessAffinityMask */
44 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessPriorityBoost */
46 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Query
), /* ProcessDeviceMap */
47 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Set
),
50 ICIF_QUERY
| ICIF_SET
),
52 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessSessionInformation */
53 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(ULONG
), ICIF_SET
), /* ProcessForegroundInformation */
54 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWow64Information */
55 ICI_SQ_SAME( sizeof(UNICODE_STRING
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SIZE_VARIABLE
), /* ProcessImageFileName */
58 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
59 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
60 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
61 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
62 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
63 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
64 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
65 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
67 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessCookie */
72 * Remove the Implemented value if all functions are implemented.
79 } QueryInformationData
[MaxThreadInfoClass
+ 1] =
81 {TRUE
, sizeof(THREAD_BASIC_INFORMATION
)}, // ThreadBasicInformation
82 {TRUE
, sizeof(KERNEL_USER_TIMES
)}, // ThreadTimes
83 {TRUE
, 0}, // ThreadPriority
84 {TRUE
, 0}, // ThreadBasePriority
85 {TRUE
, 0}, // ThreadAffinityMask
86 {TRUE
, 0}, // ThreadImpersonationToken
87 {FALSE
, 0}, // ThreadDescriptorTableEntry
88 {TRUE
, 0}, // ThreadEnableAlignmentFaultFixup
89 {TRUE
, 0}, // ThreadEventPair
90 {TRUE
, sizeof(PVOID
)}, // ThreadQuerySetWin32StartAddress
91 {TRUE
, 0}, // ThreadZeroTlsCell
92 {TRUE
, sizeof(LARGE_INTEGER
)}, // ThreadPerformanceCount
93 {TRUE
, sizeof(BOOLEAN
)}, // ThreadAmILastThread
94 {TRUE
, 0}, // ThreadIdealProcessor
95 {FALSE
, 0}, // ThreadPriorityBoost
96 {TRUE
, 0}, // ThreadSetTlsArrayAddress
97 {FALSE
, 0}, // ThreadIsIoPending
98 {TRUE
, 0} // ThreadHideFromDebugger
105 } SetInformationData
[MaxThreadInfoClass
+ 1] =
107 {TRUE
, 0}, // ThreadBasicInformation
108 {TRUE
, 0}, // ThreadTimes
109 {TRUE
, sizeof(KPRIORITY
)}, // ThreadPriority
110 {TRUE
, sizeof(LONG
)}, // ThreadBasePriority
111 {TRUE
, sizeof(KAFFINITY
)}, // ThreadAffinityMask
112 {TRUE
, sizeof(HANDLE
)}, // ThreadImpersonationToken
113 {TRUE
, 0}, // ThreadDescriptorTableEntry
114 {FALSE
, 0}, // ThreadEnableAlignmentFaultFixup
115 {FALSE
, 0}, // ThreadEventPair
116 {TRUE
, sizeof(PVOID
)}, // ThreadQuerySetWin32StartAddress
117 {FALSE
, 0}, // ThreadZeroTlsCell
118 {TRUE
, 0}, // ThreadPerformanceCount
119 {TRUE
, 0}, // ThreadAmILastThread
120 {FALSE
, 0}, // ThreadIdealProcessor
121 {FALSE
, 0}, // ThreadPriorityBoost
122 {FALSE
, 0}, // ThreadSetTlsArrayAddress
123 {TRUE
, 0}, // ThreadIsIoPending
124 {FALSE
, 0} // ThreadHideFromDebugger
127 /* FUNCTIONS *****************************************************************/
133 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
134 IN PROCESSINFOCLASS ProcessInformationClass
,
135 OUT PVOID ProcessInformation
,
136 IN ULONG ProcessInformationLength
,
137 OUT PULONG ReturnLength OPTIONAL
)
140 KPROCESSOR_MODE PreviousMode
;
141 NTSTATUS Status
= STATUS_SUCCESS
;
145 PreviousMode
= ExGetPreviousMode();
147 DefaultQueryInfoBufferCheck(ProcessInformationClass
,
150 ProcessInformationLength
,
154 if(!NT_SUCCESS(Status
))
156 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status
);
160 if(ProcessInformationClass
!= ProcessCookie
)
162 Status
= ObReferenceObjectByHandle(ProcessHandle
,
163 PROCESS_QUERY_INFORMATION
,
168 if (!NT_SUCCESS(Status
))
173 else if(ProcessHandle
!= NtCurrentProcess())
175 /* retreiving the process cookie is only allowed for the calling process
176 itself! XP only allowes NtCurrentProcess() as process handles even if a
177 real handle actually represents the current process. */
178 return STATUS_INVALID_PARAMETER
;
181 switch (ProcessInformationClass
)
183 case ProcessBasicInformation
:
185 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
=
186 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
190 ProcessBasicInformationP
->ExitStatus
= Process
->ExitStatus
;
191 ProcessBasicInformationP
->PebBaseAddress
= Process
->Peb
;
192 ProcessBasicInformationP
->AffinityMask
= Process
->Pcb
.Affinity
;
193 ProcessBasicInformationP
->UniqueProcessId
=
194 Process
->UniqueProcessId
;
195 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
196 Process
->InheritedFromUniqueProcessId
;
197 ProcessBasicInformationP
->BasePriority
=
198 Process
->Pcb
.BasePriority
;
202 *ReturnLength
= sizeof(PROCESS_BASIC_INFORMATION
);
207 Status
= _SEH_GetExceptionCode();
213 case ProcessQuotaLimits
:
214 case ProcessIoCounters
:
215 Status
= STATUS_NOT_IMPLEMENTED
;
220 PKERNEL_USER_TIMES ProcessTimeP
= (PKERNEL_USER_TIMES
)ProcessInformation
;
223 ProcessTimeP
->CreateTime
= Process
->CreateTime
;
224 ProcessTimeP
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
* 100000LL;
225 ProcessTimeP
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
* 100000LL;
226 ProcessTimeP
->ExitTime
= Process
->ExitTime
;
230 *ReturnLength
= sizeof(KERNEL_USER_TIMES
);
235 Status
= _SEH_GetExceptionCode();
241 case ProcessDebugPort
:
245 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
!= NULL
? (HANDLE
)-1 : NULL
);
248 *ReturnLength
= sizeof(HANDLE
);
253 Status
= _SEH_GetExceptionCode();
259 case ProcessLdtInformation
:
260 case ProcessWorkingSetWatch
:
261 case ProcessWx86Information
:
262 Status
= STATUS_NOT_IMPLEMENTED
;
265 case ProcessHandleCount
:
267 ULONG HandleCount
= ObpGetHandleCountByHandleTable(Process
->ObjectTable
);
271 *(PULONG
)ProcessInformation
= HandleCount
;
274 *ReturnLength
= sizeof(ULONG
);
279 Status
= _SEH_GetExceptionCode();
285 case ProcessSessionInformation
:
287 PPROCESS_SESSION_INFORMATION SessionInfo
= (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
291 SessionInfo
->SessionId
= Process
->SessionId
;
294 *ReturnLength
= sizeof(PROCESS_SESSION_INFORMATION
);
299 Status
= _SEH_GetExceptionCode();
305 case ProcessWow64Information
:
306 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
307 Status
= STATUS_NOT_IMPLEMENTED
;
310 case ProcessVmCounters
:
312 PVM_COUNTERS pOut
= (PVM_COUNTERS
)ProcessInformation
;
316 pOut
->PeakVirtualSize
= Process
->PeakVirtualSize
;
318 * Here we should probably use VirtualSize.LowPart, but due to
319 * incompatibilities in current headers (no unnamed union),
322 pOut
->VirtualSize
= (ULONG
)Process
->VirtualSize
.QuadPart
;
323 pOut
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
324 pOut
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
325 pOut
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
326 pOut
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeakPoolUsage
[0]; // TODO: Verify!
327 pOut
->QuotaPagedPoolUsage
= Process
->QuotaPoolUsage
[0]; // TODO: Verify!
328 pOut
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeakPoolUsage
[1]; // TODO: Verify!
329 pOut
->QuotaNonPagedPoolUsage
= Process
->QuotaPoolUsage
[1]; // TODO: Verify!
330 pOut
->PagefileUsage
= Process
->PagefileUsage
;
331 pOut
->PeakPagefileUsage
= Process
->PeakPagefileUsage
;
335 *ReturnLength
= sizeof(VM_COUNTERS
);
340 Status
= _SEH_GetExceptionCode();
346 case ProcessDefaultHardErrorMode
:
348 PULONG HardErrMode
= (PULONG
)ProcessInformation
;
351 *HardErrMode
= Process
->DefaultHardErrorProcessing
;
354 *ReturnLength
= sizeof(ULONG
);
359 Status
= _SEH_GetExceptionCode();
365 case ProcessPriorityBoost
:
367 PULONG BoostEnabled
= (PULONG
)ProcessInformation
;
371 *BoostEnabled
= Process
->Pcb
.DisableBoost
? FALSE
: TRUE
;
375 *ReturnLength
= sizeof(ULONG
);
380 Status
= _SEH_GetExceptionCode();
386 case ProcessDeviceMap
:
388 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
390 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
394 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
397 *ReturnLength
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
402 Status
= _SEH_GetExceptionCode();
408 case ProcessPriorityClass
:
410 PUSHORT Priority
= (PUSHORT
)ProcessInformation
;
414 *Priority
= Process
->PriorityClass
;
418 *ReturnLength
= sizeof(USHORT
);
423 Status
= _SEH_GetExceptionCode();
429 case ProcessImageFileName
:
432 * We DO NOT return the file name stored in the EPROCESS structure.
433 * Propably if we can't find a PEB or ProcessParameters structure for the
436 if(Process
->Peb
!= NULL
)
438 PRTL_USER_PROCESS_PARAMETERS ProcParams
= NULL
;
439 UNICODE_STRING LocalDest
;
441 ULONG ImagePathLen
= 0;
442 PUNICODE_STRING DstPath
= (PUNICODE_STRING
)ProcessInformation
;
444 /* we need to attach to the process to make sure we're in the right context! */
445 Attached
= Process
!= PsGetCurrentProcess();
448 KeAttachProcess(&Process
->Pcb
);
452 ProcParams
= Process
->Peb
->ProcessParameters
;
453 ImagePathLen
= ProcParams
->ImagePathName
.Length
;
457 Status
= _SEH_GetExceptionCode();
461 if(NT_SUCCESS(Status
))
463 if(ProcessInformationLength
< sizeof(UNICODE_STRING
) + ImagePathLen
+ sizeof(WCHAR
))
465 Status
= STATUS_INFO_LENGTH_MISMATCH
;
469 PWSTR StrSource
= NULL
;
471 /* create a DstPath structure on the stack */
474 LocalDest
.Length
= ImagePathLen
;
475 LocalDest
.MaximumLength
= ImagePathLen
+ sizeof(WCHAR
);
476 LocalDest
.Buffer
= (PWSTR
)(DstPath
+ 1);
478 /* save a copy of the pointer to the source buffer */
479 StrSource
= ProcParams
->ImagePathName
.Buffer
;
483 Status
= _SEH_GetExceptionCode();
487 if(NT_SUCCESS(Status
))
489 /* now, let's allocate some anonymous memory to copy the string to.
490 we can't just copy it to the buffer the caller pointed as it might
491 be user memory in another context */
492 PWSTR PathCopy
= ExAllocatePool(PagedPool
, LocalDest
.Length
+ sizeof(WCHAR
));
495 /* make a copy of the buffer to the temporary buffer */
498 RtlCopyMemory(PathCopy
, StrSource
, LocalDest
.Length
);
499 PathCopy
[LocalDest
.Length
/ sizeof(WCHAR
)] = L
'\0';
503 Status
= _SEH_GetExceptionCode();
507 /* detach from the process */
511 /* only copy the string back to the caller if we were able to
512 copy it into the temporary buffer! */
513 if(NT_SUCCESS(Status
))
515 /* now let's copy the buffer back to the caller */
518 *DstPath
= LocalDest
;
519 RtlCopyMemory(LocalDest
.Buffer
, PathCopy
, LocalDest
.Length
+ sizeof(WCHAR
));
522 *ReturnLength
= sizeof(UNICODE_STRING
) + LocalDest
.Length
+ sizeof(WCHAR
);
527 Status
= _SEH_GetExceptionCode();
532 /* we're done with the copy operation, free the temporary kernel buffer */
533 ExFreePool(PathCopy
);
535 /* we need to bail because we're already detached from the process */
540 Status
= STATUS_INSUFFICIENT_RESOURCES
;
546 /* don't forget to detach from the process!!! */
552 /* FIXME - what to do here? */
553 Status
= STATUS_UNSUCCESSFUL
;
562 /* receive the process cookie, this is only allowed for the current
565 Process
= PsGetCurrentProcess();
567 Cookie
= Process
->Cookie
;
570 LARGE_INTEGER SystemTime
;
574 /* generate a new cookie */
576 KeQuerySystemTime(&SystemTime
);
578 Prcb
= KeGetCurrentPrcb();
580 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
581 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
583 /* try to set the new cookie, return the current one if another thread
584 set it in the meanwhile */
585 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
590 /* successfully set the cookie */
597 *(PULONG
)ProcessInformation
= Cookie
;
600 *ReturnLength
= sizeof(ULONG
);
605 Status
= _SEH_GetExceptionCode();
613 * Note: The following 10 information classes are verified to not be
614 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
616 case ProcessBasePriority
:
617 case ProcessRaisePriority
:
618 case ProcessExceptionPort
:
619 case ProcessAccessToken
:
621 case ProcessIoPortHandlers
:
622 case ProcessUserModeIOPL
:
623 case ProcessEnableAlignmentFaultFixup
:
624 case ProcessAffinityMask
:
625 case ProcessForegroundInformation
:
627 Status
= STATUS_INVALID_INFO_CLASS
;
630 if(ProcessInformationClass
!= ProcessCookie
)
632 ObDereferenceObject(Process
);
642 NtSetInformationProcess(IN HANDLE ProcessHandle
,
643 IN PROCESSINFOCLASS ProcessInformationClass
,
644 IN PVOID ProcessInformation
,
645 IN ULONG ProcessInformationLength
)
648 KPROCESSOR_MODE PreviousMode
;
650 NTSTATUS Status
= STATUS_SUCCESS
;
654 PreviousMode
= ExGetPreviousMode();
656 DefaultSetInfoBufferCheck(ProcessInformationClass
,
659 ProcessInformationLength
,
662 if(!NT_SUCCESS(Status
))
664 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass
, ProcessInformation
, ProcessInformationLength
);
665 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status
);
669 switch(ProcessInformationClass
)
671 case ProcessSessionInformation
:
672 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_SESSIONID
;
674 case ProcessExceptionPort
:
675 case ProcessDebugPort
:
676 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_PORT
;
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 ProcessDebugPort
:
705 HANDLE PortHandle
= NULL
;
707 /* make a safe copy of the buffer on the stack */
710 PortHandle
= *(PHANDLE
)ProcessInformation
;
711 Status
= (PortHandle
!= NULL
? STATUS_SUCCESS
: STATUS_INVALID_PARAMETER
);
715 Status
= _SEH_GetExceptionCode();
719 if(NT_SUCCESS(Status
))
723 /* in case we had success reading from the buffer, verify the provided
726 Status
= ObReferenceObjectByHandle(PortHandle
,
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 debug
741 * port is only permitted once!
743 if(Process
->DebugPort
== NULL
)
745 /* keep the reference to the handle! */
746 Process
->DebugPort
= DebugPort
;
750 /* we're now debugging the process, so set the flag in the PEB
751 structure. However, to access it we need to attach to the
752 process so we're sure we're in the right context! */
754 KeAttachProcess(&Process
->Pcb
);
757 Process
->Peb
->BeingDebugged
= TRUE
;
761 DPRINT1("Trying to set the Peb->BeingDebugged field of process 0x%x failed, exception: 0x%x\n", Process
, _SEH_GetExceptionCode());
766 Status
= STATUS_SUCCESS
;
770 ObDereferenceObject(DebugPort
);
771 Status
= STATUS_PORT_ALREADY_SET
;
773 PsUnlockProcess(Process
);
777 ObDereferenceObject(DebugPort
);
784 case ProcessExceptionPort
:
786 HANDLE PortHandle
= NULL
;
788 /* make a safe copy of the buffer on the stack */
791 PortHandle
= *(PHANDLE
)ProcessInformation
;
792 Status
= STATUS_SUCCESS
;
796 Status
= _SEH_GetExceptionCode();
800 if(NT_SUCCESS(Status
))
802 PEPORT ExceptionPort
;
804 /* in case we had success reading from the buffer, verify the provided
807 Status
= ObReferenceObjectByHandle(PortHandle
,
811 (PVOID
)&ExceptionPort
,
813 if(NT_SUCCESS(Status
))
815 /* lock the process to be thread-safe! */
817 Status
= PsLockProcess(Process
, FALSE
);
818 if(NT_SUCCESS(Status
))
821 * according to "NT Native API" documentation, setting the exception
822 * port is only permitted once!
824 if(Process
->ExceptionPort
== NULL
)
826 /* keep the reference to the handle! */
827 Process
->ExceptionPort
= ExceptionPort
;
828 Status
= STATUS_SUCCESS
;
832 ObDereferenceObject(ExceptionPort
);
833 Status
= STATUS_PORT_ALREADY_SET
;
835 PsUnlockProcess(Process
);
839 ObDereferenceObject(ExceptionPort
);
846 case ProcessAccessToken
:
848 HANDLE TokenHandle
= NULL
;
850 /* make a safe copy of the buffer on the stack */
853 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->Token
;
854 Status
= STATUS_SUCCESS
;
858 Status
= _SEH_GetExceptionCode();
862 if(NT_SUCCESS(Status
))
864 /* in case we had success reading from the buffer, perform the actual task */
865 Status
= PspAssignPrimaryToken(Process
, TokenHandle
);
870 case ProcessDefaultHardErrorMode
:
874 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
875 *(PLONG
)ProcessInformation
);
876 Status
= STATUS_SUCCESS
;
880 Status
= _SEH_GetExceptionCode();
886 case ProcessSessionInformation
:
888 PROCESS_SESSION_INFORMATION SessionInfo
;
889 Status
= STATUS_SUCCESS
;
893 /* copy the structure to the stack */
894 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
898 Status
= _SEH_GetExceptionCode();
902 if(NT_SUCCESS(Status
))
904 /* we successfully copied the structure to the stack, continue processing */
907 * setting the session id requires the SeTcbPrivilege!
909 if(!SeSinglePrivilegeCheck(SeTcbPrivilege
,
912 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
913 /* can't set the session id, bail! */
914 Status
= STATUS_PRIVILEGE_NOT_HELD
;
918 /* FIXME - update the session id for the process token */
920 Status
= PsLockProcess(Process
, FALSE
);
921 if(NT_SUCCESS(Status
))
923 Process
->SessionId
= SessionInfo
.SessionId
;
925 /* Update the session id in the PEB structure */
926 if(Process
->Peb
!= NULL
)
928 /* we need to attach to the process to make sure we're in the right
929 context to access the PEB structure */
930 KeAttachProcess(&Process
->Pcb
);
934 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
936 Status
= STATUS_SUCCESS
;
940 Status
= _SEH_GetExceptionCode();
947 PsUnlockProcess(Process
);
953 case ProcessPriorityClass
:
955 PROCESS_PRIORITY_CLASS ppc
;
959 ppc
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
963 Status
= _SEH_GetExceptionCode();
967 if(NT_SUCCESS(Status
))
974 case ProcessLdtInformation
:
976 case ProcessIoPortHandlers
:
977 case ProcessWorkingSetWatch
:
978 case ProcessUserModeIOPL
:
979 case ProcessEnableAlignmentFaultFixup
:
980 case ProcessAffinityMask
:
981 Status
= STATUS_NOT_IMPLEMENTED
;
984 case ProcessBasicInformation
:
985 case ProcessIoCounters
:
987 case ProcessPooledUsageAndLimits
:
988 case ProcessWx86Information
:
989 case ProcessHandleCount
:
990 case ProcessWow64Information
:
992 Status
= STATUS_INVALID_INFO_CLASS
;
994 ObDereferenceObject(Process
);
999 /**********************************************************************
1001 * PiQuerySystemProcessInformation
1004 * Compute the size of a process+thread snapshot as
1005 * expected by NtQuerySystemInformation.
1008 * 0 on error; otherwise the size, in bytes of the buffer
1009 * required to write a full snapshot.
1012 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
1015 PiQuerySystemProcessInformation(PVOID Buffer
,
1019 return STATUS_NOT_IMPLEMENTED
;
1022 PLIST_ENTRY CurrentEntryP
;
1024 PLIST_ENTRY CurrentEntryT
;
1027 ULONG RequiredSize
= 0L;
1028 BOOLEAN SizeOnly
= FALSE
;
1032 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
1033 PSYSTEM_PROCESS_INFORMATION pInfoPLast
= NULL
;
1034 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
1037 /* Lock the process list. */
1038 ExAcquireFastMutex(&PspActiveProcessMutex
);
1041 * Scan the process list. Since the
1042 * list is circular, the guard is false
1043 * after the last process.
1045 for ( CurrentEntryP
= PsActiveProcessHead
.Flink
;
1046 (CurrentEntryP
!= & PsActiveProcessHead
);
1047 CurrentEntryP
= CurrentEntryP
->Flink
1051 * Compute how much space is
1052 * occupied in the snapshot
1053 * by adding this process info.
1054 * (at least one thread).
1056 SpiSizeCurrent
= sizeof (SYSTEM_PROCESS_INFORMATION
);
1057 RequiredSize
+= SpiSizeCurrent
;
1059 * Do not write process data in the
1060 * buffer if it is too small.
1062 if (TRUE
== SizeOnly
) continue;
1064 * Check if the buffer can contain
1065 * the full snapshot.
1067 if (Size
< RequiredSize
)
1073 * Get a reference to the
1074 * process descriptor we are
1077 CurrentP
= CONTAINING_RECORD(
1083 * Write process data in the buffer.
1085 RtlZeroMemory (pInfoP
, sizeof (SYSTEM_PROCESS_INFORMATION
));
1087 pInfoP
->ThreadCount
= 0L;
1088 pInfoP
->ProcessId
= CurrentP
->UniqueProcessId
;
1089 RtlInitUnicodeString (
1091 CurrentP
->ImageFileName
1094 for ( pInfoT
= & CurrentP
->ThreadSysInfo
[0],
1095 CurrentEntryT
= CurrentP
->ThreadListHead
.Flink
;
1097 (CurrentEntryT
!= & CurrentP
->ThreadListHead
);
1099 pInfoT
= & CurrentP
->ThreadSysInfo
[pInfoP
->ThreadCount
],
1100 CurrentEntryT
= CurrentEntryT
->Flink
1104 * Recalculate the size of the
1105 * information block.
1107 if (0 < pInfoP
->ThreadCount
)
1109 RequiredSize
+= sizeof (SYSTEM_THREAD_INFORMATION
);
1112 * Do not write thread data in the
1113 * buffer if it is too small.
1115 if (TRUE
== SizeOnly
) continue;
1117 * Check if the buffer can contain
1118 * the full snapshot.
1120 if (Size
< RequiredSize
)
1126 * Get a reference to the
1127 * thread descriptor we are
1130 CurrentT
= CONTAINING_RECORD(
1136 * Write thread data.
1140 sizeof (SYSTEM_THREAD_INFORMATION
)
1142 pInfoT
->KernelTime
= CurrentT
-> ; /* TIME */
1143 pInfoT
->UserTime
= CurrentT
-> ; /* TIME */
1144 pInfoT
->CreateTime
= CurrentT
-> ; /* TIME */
1145 pInfoT
->TickCount
= CurrentT
-> ; /* ULONG */
1146 pInfoT
->StartEIP
= CurrentT
-> ; /* ULONG */
1147 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
1148 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
1149 pInfoT
->DynamicPriority
= CurrentT
-> ; /* ULONG */
1150 pInfoT
->BasePriority
= CurrentT
-> ; /* ULONG */
1151 pInfoT
->nSwitches
= CurrentT
-> ; /* ULONG */
1152 pInfoT
->State
= CurrentT
-> ; /* DWORD */
1153 pInfoT
->WaitReason
= CurrentT
-> ; /* KWAIT_REASON */
1155 * Count the number of threads
1158 ++ pInfoP
->ThreadCount
;
1161 * Save the size of information
1162 * stored in the buffer for the
1165 pInfoP
->RelativeOffset
= SpiSize
;
1167 * Save a reference to the last
1168 * valid information block.
1170 pInfoPLast
= pInfoP
;
1172 * Compute the offset of the
1173 * SYSTEM_PROCESS_INFORMATION
1174 * descriptor in the snapshot
1175 * buffer for the next process.
1177 (ULONG
) pInfoP
+= SpiSize
;
1180 * Unlock the process list.
1182 ExReleaseFastMutex (
1183 & PspActiveProcessMutex
1186 * Return the proper error status code,
1187 * if the buffer was too small.
1189 if (TRUE
== SizeOnly
)
1191 if (NULL
!= RequiredSize
)
1193 *pRequiredSize
= RequiredSize
;
1195 return STATUS_INFO_LENGTH_MISMATCH
;
1198 * Mark the end of the snapshot.
1200 pInfoP
->RelativeOffset
= 0L;
1202 return STATUS_SUCCESS
;
1210 NtSetInformationThread (IN HANDLE ThreadHandle
,
1211 IN THREADINFOCLASS ThreadInformationClass
,
1212 IN PVOID ThreadInformation
,
1213 IN ULONG ThreadInformationLength
)
1228 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1229 !SetInformationData
[ThreadInformationClass
].Implemented
)
1231 return STATUS_NOT_IMPLEMENTED
;
1233 if (ThreadInformationClass
> MaxThreadInfoClass
||
1234 SetInformationData
[ThreadInformationClass
].Size
== 0)
1236 return STATUS_INVALID_INFO_CLASS
;
1238 if (ThreadInformationLength
!= SetInformationData
[ThreadInformationClass
].Size
)
1240 return STATUS_INFO_LENGTH_MISMATCH
;
1243 Status
= ObReferenceObjectByHandle (ThreadHandle
,
1244 THREAD_SET_INFORMATION
,
1246 ExGetPreviousMode (),
1249 if (!NT_SUCCESS(Status
))
1254 Status
= MmCopyFromCaller(&u
.Priority
,
1256 SetInformationData
[ThreadInformationClass
].Size
);
1257 if (NT_SUCCESS(Status
))
1259 switch (ThreadInformationClass
)
1261 case ThreadPriority
:
1262 if (u
.Priority
< LOW_PRIORITY
|| u
.Priority
>= MAXIMUM_PRIORITY
)
1264 Status
= STATUS_INVALID_PARAMETER
;
1267 KeSetPriorityThread(&Thread
->Tcb
, u
.Priority
);
1270 case ThreadBasePriority
:
1271 KeSetBasePriorityThread (&Thread
->Tcb
, u
.Increment
);
1274 case ThreadAffinityMask
:
1275 Status
= KeSetAffinityThread(&Thread
->Tcb
, u
.Affinity
);
1278 case ThreadImpersonationToken
:
1279 Status
= PsAssignImpersonationToken (Thread
, u
.Handle
);
1282 case ThreadQuerySetWin32StartAddress
:
1283 Thread
->Win32StartAddress
= u
.Address
;
1287 /* Shoult never occure if the data table is correct */
1291 ObDereferenceObject (Thread
);
1300 NtQueryInformationThread (IN HANDLE ThreadHandle
,
1301 IN THREADINFOCLASS ThreadInformationClass
,
1302 OUT PVOID ThreadInformation
,
1303 IN ULONG ThreadInformationLength
,
1304 OUT PULONG ReturnLength OPTIONAL
)
1310 THREAD_BASIC_INFORMATION TBI
;
1311 KERNEL_USER_TIMES TTI
;
1313 LARGE_INTEGER Count
;
1319 if (ThreadInformationClass
<= MaxThreadInfoClass
&&
1320 !QueryInformationData
[ThreadInformationClass
].Implemented
)
1322 return STATUS_NOT_IMPLEMENTED
;
1324 if (ThreadInformationClass
> MaxThreadInfoClass
||
1325 QueryInformationData
[ThreadInformationClass
].Size
== 0)
1327 return STATUS_INVALID_INFO_CLASS
;
1329 if (ThreadInformationLength
!= QueryInformationData
[ThreadInformationClass
].Size
)
1331 return STATUS_INFO_LENGTH_MISMATCH
;
1334 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1335 THREAD_QUERY_INFORMATION
,
1337 ExGetPreviousMode(),
1340 if (!NT_SUCCESS(Status
))
1345 switch (ThreadInformationClass
)
1347 case ThreadBasicInformation
:
1348 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1349 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1350 * 0. So do the conversion here:
1352 u
.TBI
.ExitStatus
= (Thread
->ExitStatus
== 0) ? STATUS_PENDING
: Thread
->ExitStatus
;
1353 u
.TBI
.TebBaseAddress
= Thread
->Tcb
.Teb
;
1354 u
.TBI
.ClientId
= Thread
->Cid
;
1355 u
.TBI
.AffinityMask
= Thread
->Tcb
.Affinity
;
1356 u
.TBI
.Priority
= Thread
->Tcb
.Priority
;
1357 u
.TBI
.BasePriority
= Thread
->Tcb
.BasePriority
;
1361 u
.TTI
.KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* 100000LL;
1362 u
.TTI
.UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* 100000LL;
1363 u
.TTI
.CreateTime
= Thread
->CreateTime
;
1365 u
.TTI
.ExitTime
= Thread
->ExitTime
;
1368 case ThreadQuerySetWin32StartAddress
:
1369 u
.Address
= Thread
->Win32StartAddress
;
1372 case ThreadPerformanceCount
:
1373 /* Nebbett says this class is always zero */
1374 u
.Count
.QuadPart
= 0;
1377 case ThreadAmILastThread
:
1378 if (Thread
->ThreadsProcess
->ThreadListHead
.Flink
->Flink
==
1379 &Thread
->ThreadsProcess
->ThreadListHead
)
1389 /* Shoult never occure if the data table is correct */
1392 if (QueryInformationData
[ThreadInformationClass
].Size
)
1394 Status
= MmCopyToCaller(ThreadInformation
,
1396 QueryInformationData
[ThreadInformationClass
].Size
);
1401 static ULONG Null
= 0;
1402 Status2
= MmCopyToCaller(ReturnLength
,
1403 NT_SUCCESS(Status
) ? &QueryInformationData
[ThreadInformationClass
].Size
: &Null
,
1405 if (NT_SUCCESS(Status
))
1411 ObDereferenceObject(Thread
);