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 ******************************************************************/
14 #include <internal/debug.h>
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
19 /* PRIVATE FUNCTIONS *********************************************************/
22 * This entire API is messed up because:
23 * 1) Directly pokes SECTION_OBJECT/FILE_OBJECT without special reffing.
24 * 2) Ignores SeAuditProcessImageFileName stuff added in XP (and ROS).
25 * 3) Doesn't use ObQueryNameString.
29 PspGetImagePath(IN PEPROCESS Process
,
30 OUT PUNICODE_STRING DstPath
,
31 IN ULONG ProcessInformationLength
)
34 ULONG ImagePathLen
= 0;
35 PROS_SECTION_OBJECT Section
;
36 PWSTR SrcBuffer
= NULL
, DstBuffer
= (PWSTR
)(DstPath
+ 1);
38 Section
= (PROS_SECTION_OBJECT
)Process
->SectionObject
;
39 if ((Section
)&& (Section
->FileObject
))
41 /* FIXME - check for SEC_IMAGE and/or SEC_FILE instead
42 of relying on FileObject being != NULL? */
43 SrcBuffer
= Section
->FileObject
->FileName
.Buffer
;
44 if (SrcBuffer
) ImagePathLen
= Section
->FileObject
->FileName
.Length
;
47 if (ProcessInformationLength
< (sizeof(UNICODE_STRING
) +
51 return STATUS_INFO_LENGTH_MISMATCH
;
54 Status
= STATUS_SUCCESS
;
57 /* copy the string manually, don't use RtlCopyUnicodeString with DstPath! */
58 DstPath
->Length
= ImagePathLen
;
59 DstPath
->MaximumLength
= ImagePathLen
+ sizeof(WCHAR
);
60 DstPath
->Buffer
= DstBuffer
;
61 if (ImagePathLen
) RtlCopyMemory(DstBuffer
, SrcBuffer
, ImagePathLen
);
62 DstBuffer
[ImagePathLen
/ sizeof(WCHAR
)] = L
'\0';
66 Status
= _SEH_GetExceptionCode();
74 /* PUBLIC FUNCTIONS **********************************************************/
81 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
82 IN PROCESSINFOCLASS ProcessInformationClass
,
83 OUT PVOID ProcessInformation
,
84 IN ULONG ProcessInformationLength
,
85 OUT PULONG ReturnLength OPTIONAL
)
88 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
89 NTSTATUS Status
= STATUS_SUCCESS
;
91 PPROCESS_BASIC_INFORMATION ProcessBasicInfo
=
92 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
93 PKERNEL_USER_TIMES ProcessTime
= (PKERNEL_USER_TIMES
)ProcessInformation
;
95 PPROCESS_SESSION_INFORMATION SessionInfo
=
96 (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
97 PVM_COUNTERS VmCounters
= (PVM_COUNTERS
)ProcessInformation
;
98 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
102 /* Check validity of Information Class */
103 Status
= DefaultQueryInfoBufferCheck(ProcessInformationClass
,
105 RTL_NUMBER_OF(PsProcessInfoClass
),
107 ProcessInformationLength
,
110 if (!NT_SUCCESS(Status
)) return Status
;
112 /* Check if this isn't the cookie class */
113 if(ProcessInformationClass
!= ProcessCookie
)
115 /* Reference the process */
116 Status
= ObReferenceObjectByHandle(ProcessHandle
,
117 PROCESS_QUERY_INFORMATION
,
122 if (!NT_SUCCESS(Status
)) return Status
;
124 else if(ProcessHandle
!= NtCurrentProcess())
127 * Retreiving the process cookie is only allowed for the calling process
128 * itself! XP only allowes NtCurrentProcess() as process handles even if
129 * a real handle actually represents the current process.
131 return STATUS_INVALID_PARAMETER
;
134 /* Check the information class */
135 switch (ProcessInformationClass
)
137 /* Basic process information */
138 case ProcessBasicInformation
:
140 /* Protect writes with SEH */
143 /* Write all the information from the EPROCESS/KPROCESS */
144 ProcessBasicInfo
->ExitStatus
= Process
->ExitStatus
;
145 ProcessBasicInfo
->PebBaseAddress
= Process
->Peb
;
146 ProcessBasicInfo
->AffinityMask
= Process
->Pcb
.Affinity
;
147 ProcessBasicInfo
->UniqueProcessId
= (ULONG
)Process
->
149 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
150 (ULONG
)Process
->InheritedFromUniqueProcessId
;
151 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
153 /* Set return length */
154 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
158 /* Get exception code */
159 Status
= _SEH_GetExceptionCode();
164 /* Quote limits and I/O Counters: not implemented */
165 case ProcessQuotaLimits
:
166 case ProcessIoCounters
:
167 Status
= STATUS_NOT_IMPLEMENTED
;
173 /* Protect writes with SEH */
176 /* Copy time information from EPROCESS/KPROCESS */
177 ProcessTime
->CreateTime
= Process
->CreateTime
;
178 ProcessTime
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
*
180 ProcessTime
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
*
182 ProcessTime
->ExitTime
= Process
->ExitTime
;
184 /* Set the return length */
185 Length
= sizeof(KERNEL_USER_TIMES
);
189 /* Get exception code */
190 Status
= _SEH_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
);
210 /* Get exception code */
211 Status
= _SEH_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 /* Count the number of handles this process has */
226 HandleCount
= ObpGetHandleCountByHandleTable(Process
->ObjectTable
);
228 /* Protect write in SEH */
231 /* Return the count of handles */
232 *(PULONG
)ProcessInformation
= HandleCount
;
234 /* Set the return length*/
235 Length
= sizeof(ULONG
);
239 /* Get the exception code */
240 Status
= _SEH_GetExceptionCode();
245 /* Session ID for the process */
246 case ProcessSessionInformation
:
248 /* Enter SEH for write safety */
251 /* Write back the Session ID */
252 SessionInfo
->SessionId
= Process
->Session
;
254 /* Set the return length */
255 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
259 /* Get the exception code */
260 Status
= _SEH_GetExceptionCode();
265 /* WOW64: Not implemented */
266 case ProcessWow64Information
:
267 Status
= STATUS_NOT_IMPLEMENTED
;
270 /* Virtual Memory Statistics */
271 case ProcessVmCounters
:
273 /* Enter SEH for write safety */
276 /* Return data from EPROCESS */
277 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
278 VmCounters
->VirtualSize
= Process
->VirtualSize
;
279 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
280 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
281 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
282 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
283 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
284 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
285 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
286 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2];
287 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2];
289 /* Set the return length */
290 *ReturnLength
= sizeof(VM_COUNTERS
);
294 /* Get the exception code */
295 Status
= _SEH_GetExceptionCode();
300 /* Hard Error Processing Mode */
301 case ProcessDefaultHardErrorMode
:
303 /* Enter SEH for writing back data */
306 /* Write the current processing mode */
307 *(PULONG
)ProcessInformation
= Process
->
308 DefaultHardErrorProcessing
;
310 /* Set the return length */
311 Length
= sizeof(ULONG
);
315 /* Get the exception code */
316 Status
= _SEH_GetExceptionCode();
321 /* Priority Boosting status */
322 case ProcessPriorityBoost
:
324 /* Enter SEH for writing back data */
327 /* Return boost status */
328 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
331 /* Set the return length */
332 Length
= sizeof(ULONG
);
336 /* Get the exception code */
337 Status
= _SEH_GetExceptionCode();
343 case ProcessDeviceMap
:
345 /* Query the device map information */
346 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
348 /* Enter SEH for writing back data */
351 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
353 /* Set the return length */
354 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
358 /* Get the exception code */
359 Status
= _SEH_GetExceptionCode();
365 case ProcessPriorityClass
:
367 /* Enter SEH for writing back data */
370 /* Return current priority class */
371 *(PUSHORT
)ProcessInformation
= Process
->PriorityClass
;
373 /* Set the return length */
374 Length
= sizeof(USHORT
);
378 /* Get the exception code */
379 Status
= _SEH_GetExceptionCode();
384 case ProcessImageFileName
:
386 /* Get the image path */
387 Status
= PspGetImagePath(Process
,
388 (PUNICODE_STRING
)ProcessInformation
,
389 ProcessInformationLength
);
392 /* Per-process security cookie */
395 /* Get the current process and cookie */
396 Process
= PsGetCurrentProcess();
397 Cookie
= Process
->Cookie
;
400 LARGE_INTEGER SystemTime
;
404 /* Generate a new cookie */
405 KeQuerySystemTime(&SystemTime
);
406 Prcb
= KeGetCurrentPrcb();
407 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
408 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
410 /* Set the new cookie or return the current one */
411 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
414 if(!Cookie
) Cookie
= NewCookie
;
416 /* Set return length */
417 Length
= sizeof(ULONG
);
420 /* Enter SEH to protect write */
423 /* Write back the cookie */
424 *(PULONG
)ProcessInformation
= Cookie
;
428 /* Get the exception code */
429 Status
= _SEH_GetExceptionCode();
434 /* Not yet implemented, or unknown */
435 case ProcessBasePriority
:
436 case ProcessRaisePriority
:
437 case ProcessExceptionPort
:
438 case ProcessAccessToken
:
440 case ProcessIoPortHandlers
:
441 case ProcessUserModeIOPL
:
442 case ProcessEnableAlignmentFaultFixup
:
443 case ProcessAffinityMask
:
444 case ProcessForegroundInformation
:
446 Status
= STATUS_INVALID_INFO_CLASS
;
449 /* Protect write with SEH */
452 /* Check if caller wanted return length */
453 if (ReturnLength
) *ReturnLength
= Length
;
457 /* Get exception code */
458 Status
= _SEH_GetExceptionCode();
462 /* If we referenced the process, dereference it */
463 if(ProcessInformationClass
!= ProcessCookie
) ObDereferenceObject(Process
);
472 NtSetInformationProcess(IN HANDLE ProcessHandle
,
473 IN PROCESSINFOCLASS ProcessInformationClass
,
474 IN PVOID ProcessInformation
,
475 IN ULONG ProcessInformationLength
)
478 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
480 NTSTATUS Status
= STATUS_SUCCESS
;
483 /* Verify Information Class validity */
484 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
486 RTL_NUMBER_OF(PsProcessInfoClass
),
488 ProcessInformationLength
,
490 if(!NT_SUCCESS(Status
))
492 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status
);
496 switch(ProcessInformationClass
)
498 case ProcessSessionInformation
:
499 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_SESSIONID
;
501 case ProcessExceptionPort
:
502 Access
= PROCESS_SET_INFORMATION
| PROCESS_SUSPEND_RESUME
;
506 Access
= PROCESS_SET_INFORMATION
;
510 Status
= ObReferenceObjectByHandle(ProcessHandle
,
516 if (!NT_SUCCESS(Status
)) return(Status
);
518 switch (ProcessInformationClass
)
520 case ProcessQuotaLimits
:
521 case ProcessBasePriority
:
522 case ProcessRaisePriority
:
523 Status
= STATUS_NOT_IMPLEMENTED
;
526 case ProcessExceptionPort
:
528 HANDLE PortHandle
= NULL
;
530 /* make a safe copy of the buffer on the stack */
533 PortHandle
= *(PHANDLE
)ProcessInformation
;
534 Status
= STATUS_SUCCESS
;
538 Status
= _SEH_GetExceptionCode();
542 if(NT_SUCCESS(Status
))
544 PEPORT ExceptionPort
;
546 /* in case we had success reading from the buffer, verify the provided
549 Status
= ObReferenceObjectByHandle(PortHandle
,
553 (PVOID
)&ExceptionPort
,
555 if(NT_SUCCESS(Status
))
557 /* lock the process to be thread-safe! */
559 Status
= PsLockProcess(Process
, FALSE
);
560 if(NT_SUCCESS(Status
))
563 * according to "NT Native API" documentation, setting the exception
564 * port is only permitted once!
566 if(Process
->ExceptionPort
== NULL
)
568 /* keep the reference to the handle! */
569 Process
->ExceptionPort
= ExceptionPort
;
570 Status
= STATUS_SUCCESS
;
574 ObDereferenceObject(ExceptionPort
);
575 Status
= STATUS_PORT_ALREADY_SET
;
577 PsUnlockProcess(Process
);
581 ObDereferenceObject(ExceptionPort
);
588 case ProcessAccessToken
:
590 HANDLE TokenHandle
= NULL
;
592 /* make a safe copy of the buffer on the stack */
595 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->Token
;
596 Status
= STATUS_SUCCESS
;
600 Status
= _SEH_GetExceptionCode();
604 if(NT_SUCCESS(Status
))
606 /* in case we had success reading from the buffer, perform the actual task */
607 Status
= PspAssignPrimaryToken(Process
, TokenHandle
);
612 case ProcessDefaultHardErrorMode
:
616 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
617 *(PLONG
)ProcessInformation
);
618 Status
= STATUS_SUCCESS
;
622 Status
= _SEH_GetExceptionCode();
628 case ProcessSessionInformation
:
630 PROCESS_SESSION_INFORMATION SessionInfo
;
631 Status
= STATUS_SUCCESS
;
633 RtlZeroMemory(&SessionInfo
, sizeof(SessionInfo
));
637 /* copy the structure to the stack */
638 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
642 Status
= _SEH_GetExceptionCode();
646 if(NT_SUCCESS(Status
))
648 /* we successfully copied the structure to the stack, continue processing */
651 * setting the session id requires the SeTcbPrivilege!
653 if(!SeSinglePrivilegeCheck(SeTcbPrivilege
,
656 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
657 /* can't set the session id, bail! */
658 Status
= STATUS_PRIVILEGE_NOT_HELD
;
662 /* FIXME - update the session id for the process token */
664 Status
= PsLockProcess(Process
, FALSE
);
665 if(NT_SUCCESS(Status
))
667 Process
->Session
= SessionInfo
.SessionId
;
669 /* Update the session id in the PEB structure */
670 if(Process
->Peb
!= NULL
)
672 /* we need to attach to the process to make sure we're in the right
673 context to access the PEB structure */
674 KeAttachProcess(&Process
->Pcb
);
678 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
680 Status
= STATUS_SUCCESS
;
684 Status
= _SEH_GetExceptionCode();
691 PsUnlockProcess(Process
);
697 case ProcessPriorityClass
:
699 PROCESS_PRIORITY_CLASS ppc
;
703 ppc
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
707 Status
= _SEH_GetExceptionCode();
711 if(NT_SUCCESS(Status
))
718 case ProcessLdtInformation
:
720 case ProcessIoPortHandlers
:
721 case ProcessWorkingSetWatch
:
722 case ProcessUserModeIOPL
:
723 case ProcessEnableAlignmentFaultFixup
:
724 case ProcessAffinityMask
:
725 Status
= STATUS_NOT_IMPLEMENTED
;
728 case ProcessBasicInformation
:
729 case ProcessIoCounters
:
731 case ProcessPooledUsageAndLimits
:
732 case ProcessWx86Information
:
733 case ProcessHandleCount
:
734 case ProcessWow64Information
:
735 case ProcessDebugPort
:
737 Status
= STATUS_INVALID_INFO_CLASS
;
739 ObDereferenceObject(Process
);
748 NtSetInformationThread(IN HANDLE ThreadHandle
,
749 IN THREADINFOCLASS ThreadInformationClass
,
750 IN PVOID ThreadInformation
,
751 IN ULONG ThreadInformationLength
)
754 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
755 NTSTATUS Status
= STATUS_SUCCESS
;
758 DPRINT1("%s called for: %d\n", __FUNCTION__
, ThreadInformationClass
);
759 /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
760 /* FIXME: We should also check for certain things before doing the reference */
761 Status
= ObReferenceObjectByHandle(ThreadHandle
,
762 THREAD_SET_INFORMATION
,
767 if (NT_SUCCESS(Status
))
770 switch (ThreadInformationClass
)
774 if (u
.Priority
< LOW_PRIORITY
|| u
.Priority
>= MAXIMUM_PRIORITY
)
776 Status
= STATUS_INVALID_PARAMETER
;
779 KeSetPriorityThread(&Thread
->Tcb
, u
.Priority
);
782 case ThreadBasePriority
:
783 KeSetBasePriorityThread (&Thread
->Tcb
, u
.Increment
);
786 case ThreadAffinityMask
:
788 /* Check if this is valid */
789 DPRINT1("%lx, %lx\n", Thread
->ThreadsProcess
->Pcb
.Affinity
, u
.Affinity
);
790 if ((Thread
->ThreadsProcess
->Pcb
.Affinity
& u
.Affinity
) !=
793 DPRINT1("Wrong affinity given\n");
794 Status
= STATUS_INVALID_PARAMETER
;
798 Status
= KeSetAffinityThread(&Thread
->Tcb
, u
.Affinity
);
802 case ThreadImpersonationToken
:
803 Status
= PsAssignImpersonationToken (Thread
, u
.Handle
);
806 case ThreadQuerySetWin32StartAddress
:
807 Thread
->Win32StartAddress
= u
.Address
;
811 /* Shoult never occure if the data table is correct */
815 ObDereferenceObject (Thread
);
826 NtQueryInformationThread(IN HANDLE ThreadHandle
,
827 IN THREADINFOCLASS ThreadInformationClass
,
828 OUT PVOID ThreadInformation
,
829 IN ULONG ThreadInformationLength
,
830 OUT PULONG ReturnLength OPTIONAL
)
833 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
834 NTSTATUS Status
= STATUS_SUCCESS
;
837 DPRINT1("%s called for: %d\n", __FUNCTION__
, ThreadInformationClass
);
838 Status
= ObReferenceObjectByHandle(ThreadHandle
,
839 THREAD_QUERY_INFORMATION
,
844 if (!NT_SUCCESS(Status
)) return Status
;
847 switch (ThreadInformationClass
)
849 case ThreadBasicInformation
:
850 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
851 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
852 * 0. So do the conversion here:
854 u
.TBI
.ExitStatus
= (Thread
->ExitStatus
== 0) ? STATUS_PENDING
: Thread
->ExitStatus
;
855 u
.TBI
.TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
856 u
.TBI
.ClientId
= Thread
->Cid
;
857 u
.TBI
.AffinityMask
= Thread
->Tcb
.Affinity
;
858 u
.TBI
.Priority
= Thread
->Tcb
.Priority
;
859 u
.TBI
.BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
863 u
.TTI
.KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* 100000LL;
864 u
.TTI
.UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* 100000LL;
865 u
.TTI
.CreateTime
= Thread
->CreateTime
;
867 u
.TTI
.ExitTime
= Thread
->ExitTime
;
870 case ThreadQuerySetWin32StartAddress
:
871 u
.Address
= Thread
->Win32StartAddress
;
874 case ThreadPerformanceCount
:
875 /* Nebbett says this class is always zero */
876 u
.Count
.QuadPart
= 0;
879 case ThreadAmILastThread
:
880 if (Thread
->ThreadsProcess
->ThreadListHead
.Flink
->Flink
==
881 &Thread
->ThreadsProcess
->ThreadListHead
)
891 case ThreadIsIoPending
:
895 /* Raise the IRQL to protect the IRP list */
896 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
897 u
.IsIoPending
= !IsListEmpty(&Thread
->IrpList
);
898 KeLowerIrql(OldIrql
);
903 /* Shoult never occure if the data table is correct */
907 ObDereferenceObject(Thread
);