2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/process.c
5 * PURPOSE: Process Manager: Process Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 extern ULONG PsMinimumWorkingSet
, PsMaximumWorkingSet
;
20 POBJECT_TYPE PsProcessType
= NULL
;
22 LIST_ENTRY PsActiveProcessHead
;
23 KGUARDED_MUTEX PspActiveProcessMutex
;
25 LARGE_INTEGER ShortPsLockDelay
;
27 ULONG PsRawPrioritySeparation
= 0;
28 ULONG PsPrioritySeparation
;
29 CHAR PspForegroundQuantum
[3];
31 /* Fixed quantum table */
32 CHAR PspFixedQuantums
[6] =
45 /* Variable quantum table */
46 CHAR PspVariableQuantums
[6] =
60 KPRIORITY PspPriorityTable
[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
+ 1] =
71 /* PRIVATE FUNCTIONS *********************************************************/
75 PsGetNextProcessThread(IN PEPROCESS Process
,
76 IN PETHREAD Thread OPTIONAL
)
78 PETHREAD FoundThread
= NULL
;
79 PLIST_ENTRY ListHead
, Entry
;
81 PSTRACE(PS_PROCESS_DEBUG
,
82 "Process: %p Thread: %p\n", Process
, Thread
);
84 /* Lock the process */
85 KeEnterCriticalRegion();
86 ExAcquirePushLockShared(&Process
->ProcessLock
);
88 /* Check if we're already starting somewhere */
91 /* Start where we left off */
92 Entry
= Thread
->ThreadListEntry
.Flink
;
96 /* Start at the beginning */
97 Entry
= Process
->ThreadListHead
.Flink
;
100 /* Set the list head and start looping */
101 ListHead
= &Process
->ThreadListHead
;
102 while (ListHead
!= Entry
)
105 FoundThread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
107 /* Safe reference the thread */
108 if (ObReferenceObjectSafe(FoundThread
)) break;
110 /* Nothing found, keep looping */
112 Entry
= Entry
->Flink
;
115 /* Unlock the process */
116 ExReleasePushLockShared(&Process
->ProcessLock
);
117 KeLeaveCriticalRegion();
119 /* Check if we had a starting thread, and dereference it */
120 if (Thread
) ObDereferenceObject(Thread
);
122 /* Return what we found */
128 PsGetNextProcess(IN PEPROCESS OldProcess
)
131 PEPROCESS FoundProcess
= NULL
;
133 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p\n", OldProcess
);
135 /* Acquire the Active Process Lock */
136 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
138 /* Check if we're already starting somewhere */
141 /* Start where we left off */
142 Entry
= OldProcess
->ActiveProcessLinks
.Flink
;
146 /* Start at the beginning */
147 Entry
= PsActiveProcessHead
.Flink
;
150 /* Loop the process list */
151 while (Entry
!= &PsActiveProcessHead
)
153 /* Get the process */
154 FoundProcess
= CONTAINING_RECORD(Entry
, EPROCESS
, ActiveProcessLinks
);
156 /* Reference the process */
157 if (ObReferenceObjectSafe(FoundProcess
)) break;
159 /* Nothing found, keep trying */
161 Entry
= Entry
->Flink
;
164 /* Release the lock */
165 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
167 /* Dereference the Process we had referenced earlier */
168 if (OldProcess
) ObDereferenceObject(OldProcess
);
174 PspComputeQuantumAndPriority(IN PEPROCESS Process
,
175 IN PSPROCESSPRIORITYMODE Mode
,
179 UCHAR LocalQuantum
, MemoryPriority
;
181 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Mode: %lx\n", Process
, Mode
);
183 /* Check if this is a foreground process */
184 if (Mode
== PsProcessPriorityForeground
)
186 /* Set the memory priority and use priority separation */
187 MemoryPriority
= MEMORY_PRIORITY_FOREGROUND
;
188 i
= PsPrioritySeparation
;
192 /* Set the background memory priority and no separation */
193 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
197 /* Make sure that the process mode isn't spinning */
198 if (Mode
!= PsProcessPrioritySpinning
)
200 /* Set the priority */
201 MmSetMemoryPriorityProcess(Process
, MemoryPriority
);
204 /* Make sure that the process isn't idle */
205 if (Process
->PriorityClass
!= PROCESS_PRIORITY_CLASS_IDLE
)
207 /* Does the process have a job? */
208 if ((Process
->Job
) && (PspUseJobSchedulingClasses
))
210 /* Use job quantum */
211 LocalQuantum
= PspJobSchedulingClasses
[Process
->Job
->
216 /* Use calculated quantum */
217 LocalQuantum
= PspForegroundQuantum
[i
];
222 /* Process is idle, use default quantum */
226 /* Return quantum to caller */
227 *Quantum
= LocalQuantum
;
229 /* Return priority */
230 return PspPriorityTable
[Process
->PriorityClass
];
235 PsChangeQuantumTable(IN BOOLEAN Immediate
,
236 IN ULONG PrioritySeparation
)
238 PEPROCESS Process
= NULL
;
243 PSTRACE(PS_PROCESS_DEBUG
,
244 "%lx PrioritySeparation: %lx\n", Immediate
, PrioritySeparation
);
246 /* Write the current priority separation */
247 PsPrioritySeparation
= PspPrioritySeparationFromMask(PrioritySeparation
);
249 /* Normalize it if it was too high */
250 if (PsPrioritySeparation
== 3) PsPrioritySeparation
= 2;
252 /* Get the quantum table to use */
253 if (PspQuantumTypeFromMask(PrioritySeparation
) == PSP_VARIABLE_QUANTUMS
)
255 /* Use a variable table */
256 QuantumTable
= PspVariableQuantums
;
260 /* Use fixed table */
261 QuantumTable
= PspFixedQuantums
;
264 /* Now check if we should use long or short */
265 if (PspQuantumLengthFromMask(PrioritySeparation
) == PSP_LONG_QUANTUMS
)
267 /* Use long quantums */
271 /* Check if we're using long fixed quantums */
272 if (QuantumTable
== &PspFixedQuantums
[3])
274 /* Use Job scheduling classes */
275 PspUseJobSchedulingClasses
= TRUE
;
279 /* Otherwise, we don't */
280 PspUseJobSchedulingClasses
= FALSE
;
283 /* Copy the selected table into the Foreground Quantum table */
284 RtlCopyMemory(PspForegroundQuantum
,
286 sizeof(PspForegroundQuantum
));
288 /* Check if we should apply these changes real-time */
291 /* We are...loop every process */
292 Process
= PsGetNextProcess(Process
);
296 * Use the priority separation, unless the process has
297 * low memory priority
299 i
= (Process
->Vm
.Flags
.MemoryPriority
== 1) ?
300 0: PsPrioritySeparation
;
302 /* Make sure that the process isn't idle */
303 if (Process
->PriorityClass
!= PROCESS_PRIORITY_CLASS_IDLE
)
305 /* Does the process have a job? */
306 if ((Process
->Job
) && (PspUseJobSchedulingClasses
))
308 /* Use job quantum */
309 Quantum
= PspJobSchedulingClasses
[Process
->Job
->
314 /* Use calculated quantum */
315 Quantum
= PspForegroundQuantum
[i
];
320 /* Process is idle, use default quantum */
324 /* Now set the quantum */
325 KeSetQuantumProcess(&Process
->Pcb
, Quantum
);
327 /* Get the next process */
328 Process
= PsGetNextProcess(Process
);
335 PspCreateProcess(OUT PHANDLE ProcessHandle
,
336 IN ACCESS_MASK DesiredAccess
,
337 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
338 IN HANDLE ParentProcess OPTIONAL
,
340 IN HANDLE SectionHandle OPTIONAL
,
341 IN HANDLE DebugPort OPTIONAL
,
342 IN HANDLE ExceptionPort OPTIONAL
,
346 PEPROCESS Process
, Parent
;
347 PVOID ExceptionPortObject
;
348 PDEBUG_OBJECT DebugObject
;
349 PSECTION_OBJECT SectionObject
;
350 NTSTATUS Status
, AccessStatus
;
351 ULONG_PTR DirectoryTableBase
[2] = {0,0};
353 HANDLE_TABLE_ENTRY CidEntry
;
354 PETHREAD CurrentThread
= PsGetCurrentThread();
355 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
356 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
358 ACCESS_STATE LocalAccessState
;
359 PACCESS_STATE AccessState
= &LocalAccessState
;
360 AUX_ACCESS_DATA AuxData
;
362 BOOLEAN Result
, SdAllocated
;
363 PSECURITY_DESCRIPTOR SecurityDescriptor
;
364 SECURITY_SUBJECT_CONTEXT SubjectContext
;
365 BOOLEAN NeedsPeb
= FALSE
;
366 INITIAL_PEB InitialPeb
;
368 PSTRACE(PS_PROCESS_DEBUG
,
369 "ProcessHandle: %p Parent: %p\n", ProcessHandle
, ParentProcess
);
372 if (Flags
& ~PROCESS_CREATE_FLAGS_LEGAL_MASK
) return STATUS_INVALID_PARAMETER
;
374 /* Check for parent */
378 Status
= ObReferenceObjectByHandle(ParentProcess
,
379 PROCESS_CREATE_PROCESS
,
384 if (!NT_SUCCESS(Status
)) return Status
;
386 /* If this process should be in a job but the parent isn't */
387 if ((InJob
) && (!Parent
->Job
))
389 /* This is illegal. Dereference the parent and fail */
390 ObDereferenceObject(Parent
);
391 return STATUS_INVALID_PARAMETER
;
394 /* Inherit Parent process's Affinity. */
395 Affinity
= Parent
->Pcb
.Affinity
;
399 /* We have no parent */
401 Affinity
= KeActiveProcessors
;
404 /* Save working set data */
405 MinWs
= PsMinimumWorkingSet
;
406 MaxWs
= PsMaximumWorkingSet
;
408 /* Create the Object */
409 Status
= ObCreateObject(PreviousMode
,
418 if (!NT_SUCCESS(Status
)) goto Cleanup
;
420 /* Clean up the Object */
421 RtlZeroMemory(Process
, sizeof(EPROCESS
));
423 /* Initialize pushlock and rundown protection */
424 ExInitializeRundownProtection(&Process
->RundownProtect
);
425 Process
->ProcessLock
.Value
= 0;
427 /* Setup the Thread List Head */
428 InitializeListHead(&Process
->ThreadListHead
);
430 /* Set up the Quota Block from the Parent */
431 PspInheritQuota(Process
, Parent
);
433 /* Set up Dos Device Map from the Parent */
434 ObInheritDeviceMap(Parent
, Process
);
436 /* Check if we have a parent */
439 /* Inherit PID and Hard Error Processing */
440 Process
->InheritedFromUniqueProcessId
= Parent
->UniqueProcessId
;
441 Process
->DefaultHardErrorProcessing
= Parent
->
442 DefaultHardErrorProcessing
;
446 /* Use default hard error processing */
447 Process
->DefaultHardErrorProcessing
= TRUE
;
450 /* Check for a section handle */
453 /* Get a pointer to it */
454 Status
= ObReferenceObjectByHandle(SectionHandle
,
458 (PVOID
*)&SectionObject
,
460 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
464 /* Assume no section object */
465 SectionObject
= NULL
;
467 /* Is the parent the initial process?
468 * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */
469 if (Parent
!= PsInitialSystemProcess
&& (Parent
!= NULL
))
471 /* It's not, so acquire the process rundown */
472 if (ExAcquireRundownProtection(&Parent
->RundownProtect
))
474 /* If the parent has a section, use it */
475 SectionObject
= Parent
->SectionObject
;
476 if (SectionObject
) ObReferenceObject(SectionObject
);
478 /* Release process rundown */
479 ExReleaseRundownProtection(&Parent
->RundownProtect
);
482 /* If we don't have a section object */
485 /* Then the process is in termination, so fail */
486 Status
= STATUS_PROCESS_IS_TERMINATING
;
492 /* Save the pointer to the section object */
493 Process
->SectionObject
= SectionObject
;
495 /* Check for the debug port */
499 Status
= ObReferenceObjectByHandle(DebugPort
,
500 DEBUG_OBJECT_ADD_REMOVE_PROCESS
,
503 (PVOID
*)&DebugObject
,
505 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
507 /* Save the debug object */
508 Process
->DebugPort
= DebugObject
;
510 /* Check if the caller doesn't want the debug stuff inherited */
511 if (Flags
& PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
)
513 /* Set the process flag */
514 InterlockedOr((PLONG
)&Process
->Flags
, PSF_NO_DEBUG_INHERIT_BIT
);
519 /* Do we have a parent? Copy his debug port */
520 if (Parent
) DbgkCopyProcessDebugPort(Process
, Parent
);
523 /* Now check for an exception port */
527 Status
= ObReferenceObjectByHandle(ExceptionPort
,
531 (PVOID
*)&ExceptionPortObject
,
533 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
535 /* Save the exception port */
536 Process
->ExceptionPort
= ExceptionPortObject
;
539 /* Save the pointer to the section object */
540 Process
->SectionObject
= SectionObject
;
542 /* Set default exit code */
543 Process
->ExitStatus
= STATUS_PENDING
;
545 /* Check if this is the initial process being built */
548 /* Create the address space for the child */
549 if (!MmCreateProcessAddressSpace(MinWs
,
554 Status
= STATUS_INSUFFICIENT_RESOURCES
;
560 /* Otherwise, we are the boot process, we're already semi-initialized */
561 Process
->ObjectTable
= CurrentProcess
->ObjectTable
;
562 Status
= MmInitializeHandBuiltProcess(Process
, DirectoryTableBase
);
563 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
566 /* We now have an address space */
567 InterlockedOr((PLONG
)&Process
->Flags
, PSF_HAS_ADDRESS_SPACE_BIT
);
569 /* Set the maximum WS */
570 Process
->Vm
.MaximumWorkingSetSize
= MaxWs
;
572 /* Now initialize the Kernel Process */
573 KeInitializeProcess(&Process
->Pcb
,
574 PROCESS_PRIORITY_NORMAL
,
577 (BOOLEAN
)(Process
->DefaultHardErrorProcessing
& 4));
579 /* Duplicate Parent Token */
580 Status
= PspInitializeProcessSecurity(Process
, Parent
);
581 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
583 /* Set default priority class */
584 Process
->PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
586 /* Check if we have a parent */
589 /* Check our priority class */
590 if (Parent
->PriorityClass
== PROCESS_PRIORITY_CLASS_IDLE
||
591 Parent
->PriorityClass
== PROCESS_PRIORITY_CLASS_BELOW_NORMAL
)
594 Process
->PriorityClass
= Parent
->PriorityClass
;
597 /* Initialize object manager for the process */
598 Status
= ObInitProcess(Flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
?
601 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
605 /* Do the second part of the boot process memory setup */
606 Status
= MmInitializeHandBuiltProcess2(Process
);
607 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
610 /* Set success for now */
611 Status
= STATUS_SUCCESS
;
613 /* Check if this is a real user-mode process */
616 /* Initialize the address space */
617 Status
= MmInitializeProcessAddressSpace(Process
,
622 SeAuditProcessCreationInfo
.
624 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
633 /* Check if this is a child of the system process */
634 if (Parent
!= PsInitialSystemProcess
)
641 /* This is a clone! */
642 ASSERTMSG("No support for cloning yet\n", FALSE
);
646 /* This is the initial system process */
647 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
648 Status
= MmInitializeProcessAddressSpace(Process
,
653 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
655 /* Create a dummy image file name */
656 Process
->SeAuditProcessCreationInfo
.ImageFileName
=
657 ExAllocatePoolWithTag(PagedPool
,
658 sizeof(OBJECT_NAME_INFORMATION
),
660 if (!Process
->SeAuditProcessCreationInfo
.ImageFileName
)
663 Status
= STATUS_INSUFFICIENT_RESOURCES
;
668 RtlZeroMemory(Process
->SeAuditProcessCreationInfo
.ImageFileName
,
669 sizeof(OBJECT_NAME_INFORMATION
));
674 /* Copy the process name now that we have it */
675 memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
676 if (Process
->Pcb
.DirectoryTableBase
[1]) memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
677 if (Process
->WorkingSetPage
) memcpy(MiGetPfnEntry(Process
->WorkingSetPage
)->ProcessName
, Process
->ImageFileName
, 16);
680 /* Check if we have a section object and map the system DLL */
681 if (SectionObject
) PspMapSystemDll(Process
, NULL
, FALSE
);
683 /* Create a handle for the Process */
684 CidEntry
.Object
= Process
;
685 CidEntry
.GrantedAccess
= 0;
686 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
687 if (!Process
->UniqueProcessId
)
690 Status
= STATUS_INSUFFICIENT_RESOURCES
;
694 /* Set the handle table PID */
695 Process
->ObjectTable
->UniqueProcessId
= Process
->UniqueProcessId
;
697 /* Check if we need to audit */
698 if (SeDetailedAuditingWithToken(NULL
)) SeAuditProcessCreate(Process
);
700 /* Check if the parent had a job */
701 if ((Parent
) && (Parent
->Job
))
703 /* FIXME: We need to insert this process */
704 DPRINT1("Jobs not yet supported\n");
708 /* Create PEB only for User-Mode Processes */
709 if ((Parent
) && (NeedsPeb
))
712 // Set up the initial PEB
714 RtlZeroMemory(&InitialPeb
, sizeof(INITIAL_PEB
));
715 InitialPeb
.Mutant
= (HANDLE
)-1;
716 InitialPeb
.ImageUsesLargePages
= 0; // FIXME: Not yet supported
719 // Create it only if we have an image section
726 Status
= MmCreatePeb(Process
, &InitialPeb
, &Process
->Peb
);
727 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
732 // We have to clone it
734 ASSERTMSG("No support for cloning yet\n", FALSE
);
739 /* The process can now be activated */
740 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
741 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
742 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
744 /* Create an access state */
745 Status
= SeCreateAccessStateEx(CurrentThread
,
747 (Parent
== PsInitialSystemProcess
)) ?
748 Parent
: CurrentProcess
,
752 &PsProcessType
->TypeInfo
.GenericMapping
);
753 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
755 /* Insert the Process into the Object Directory */
756 Status
= ObInsertObject(Process
,
763 /* Free the access state */
764 if (AccessState
) SeDeleteAccessState(AccessState
);
766 /* Cleanup on failure */
767 if (!NT_SUCCESS(Status
)) goto Cleanup
;
769 /* Compute Quantum and Priority */
770 ASSERT(IsListEmpty(&Process
->ThreadListHead
) == TRUE
);
771 Process
->Pcb
.BasePriority
=
772 (SCHAR
)PspComputeQuantumAndPriority(Process
,
773 PsProcessPriorityBackground
,
775 Process
->Pcb
.QuantumReset
= Quantum
;
777 /* Check if we have a parent other then the initial system process */
778 Process
->GrantedAccess
= PROCESS_TERMINATE
;
779 if ((Parent
) && (Parent
!= PsInitialSystemProcess
))
781 /* Get the process's SD */
782 Status
= ObGetObjectSecurity(Process
,
785 if (!NT_SUCCESS(Status
))
787 /* We failed, close the handle and clean up */
788 ObCloseHandle(hProcess
, PreviousMode
);
792 /* Create the subject context */
793 SubjectContext
.ProcessAuditId
= Process
;
794 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
795 SubjectContext
.ClientToken
= NULL
;
797 /* Do the access check */
798 Result
= SeAccessCheck(SecurityDescriptor
,
804 &PsProcessType
->TypeInfo
.GenericMapping
,
806 &Process
->GrantedAccess
,
809 /* Dereference the token and let go the SD */
810 ObFastDereferenceObject(&Process
->Token
,
811 SubjectContext
.PrimaryToken
);
812 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
814 /* Remove access if it failed */
815 if (!Result
) Process
->GrantedAccess
= 0;
817 /* Give the process some basic access */
818 Process
->GrantedAccess
|= (PROCESS_VM_OPERATION
|
821 PROCESS_QUERY_INFORMATION
|
823 PROCESS_CREATE_THREAD
|
825 PROCESS_CREATE_PROCESS
|
826 PROCESS_SET_INFORMATION
|
827 STANDARD_RIGHTS_ALL
|
832 /* Set full granted access */
833 Process
->GrantedAccess
= PROCESS_ALL_ACCESS
;
836 /* Set the Creation Time */
837 KeQuerySystemTime(&Process
->CreateTime
);
839 /* Protect against bad user-mode pointer */
842 /* Hacky way of returning the PEB to the user-mode creator */
843 if ((Process
->Peb
) && (CurrentThread
->Tcb
.Teb
))
845 CurrentThread
->Tcb
.Teb
->NtTib
.ArbitraryUserPointer
= Process
->Peb
;
848 /* Save the process handle */
849 *ProcessHandle
= hProcess
;
851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
853 /* Get the exception code */
854 Status
= _SEH2_GetExceptionCode();
858 /* Run the Notification Routines */
859 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
861 /* If 12 processes have been created, enough of user-mode is ready */
862 if (++ProcessCount
== 12) Ki386PerfEnd();
866 * Dereference the process. For failures, kills the process and does
867 * cleanup present in PspDeleteProcess. For success, kills the extra
868 * reference added by ObInsertObject.
870 ObDereferenceObject(Process
);
873 /* Dereference the parent */
874 if (Parent
) ObDereferenceObject(Parent
);
876 /* Return status to caller */
880 /* PUBLIC FUNCTIONS **********************************************************/
887 PsCreateSystemProcess(OUT PHANDLE ProcessHandle
,
888 IN ACCESS_MASK DesiredAccess
,
889 IN POBJECT_ATTRIBUTES ObjectAttributes
)
891 /* Call the internal API */
892 return PspCreateProcess(ProcessHandle
,
908 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
909 OUT PEPROCESS
*Process
)
911 PHANDLE_TABLE_ENTRY CidEntry
;
912 PEPROCESS FoundProcess
;
913 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
915 PSTRACE(PS_PROCESS_DEBUG
, "ProcessId: %p\n", ProcessId
);
916 KeEnterCriticalRegion();
918 /* Get the CID Handle Entry */
919 CidEntry
= ExMapHandleToPointer(PspCidTable
, ProcessId
);
922 /* Get the Process */
923 FoundProcess
= CidEntry
->Object
;
925 /* Make sure it's really a process */
926 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
928 /* Safe Reference and return it */
929 if (ObReferenceObjectSafe(FoundProcess
))
931 *Process
= FoundProcess
;
932 Status
= STATUS_SUCCESS
;
936 /* Unlock the Entry */
937 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
940 /* Return to caller */
941 KeLeaveCriticalRegion();
950 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
951 OUT PEPROCESS
*Process OPTIONAL
,
952 OUT PETHREAD
*Thread
)
954 PHANDLE_TABLE_ENTRY CidEntry
;
955 PETHREAD FoundThread
;
956 NTSTATUS Status
= STATUS_INVALID_CID
;
958 PSTRACE(PS_PROCESS_DEBUG
, "Cid: %p\n", Cid
);
959 KeEnterCriticalRegion();
961 /* Get the CID Handle Entry */
962 CidEntry
= ExMapHandleToPointer(PspCidTable
, Cid
->UniqueThread
);
965 /* Get the Process */
966 FoundThread
= CidEntry
->Object
;
968 /* Make sure it's really a thread and this process' */
969 if ((FoundThread
->Tcb
.Header
.Type
== ThreadObject
) &&
970 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
972 /* Safe Reference and return it */
973 if (ObReferenceObjectSafe(FoundThread
))
975 *Thread
= FoundThread
;
976 Status
= STATUS_SUCCESS
;
978 /* Check if we should return the Process too */
981 /* Return it and reference it */
982 *Process
= FoundThread
->ThreadsProcess
;
983 ObReferenceObject(*Process
);
988 /* Unlock the Entry */
989 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
992 /* Return to caller */
993 KeLeaveCriticalRegion();
1002 PsGetProcessExitTime(VOID
)
1004 return PsGetCurrentProcess()->ExitTime
;
1012 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
1014 return Process
->CreateTime
.QuadPart
;
1022 PsGetProcessDebugPort(PEPROCESS Process
)
1024 return Process
->DebugPort
;
1032 PsGetProcessExitProcessCalled(PEPROCESS Process
)
1034 return (BOOLEAN
)Process
->ProcessExiting
;
1042 PsGetProcessExitStatus(PEPROCESS Process
)
1044 return Process
->ExitStatus
;
1052 PsGetProcessId(PEPROCESS Process
)
1054 return (HANDLE
)Process
->UniqueProcessId
;
1062 PsGetProcessImageFileName(PEPROCESS Process
)
1064 return (LPSTR
)Process
->ImageFileName
;
1072 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
1074 return Process
->InheritedFromUniqueProcessId
;
1082 PsGetProcessJob(PEPROCESS Process
)
1084 return Process
->Job
;
1092 PsGetProcessPeb(PEPROCESS Process
)
1094 return Process
->Peb
;
1102 PsGetProcessPriorityClass(PEPROCESS Process
)
1104 return Process
->PriorityClass
;
1112 PsGetCurrentProcessId(VOID
)
1114 return (HANDLE
)PsGetCurrentProcess()->UniqueProcessId
;
1122 PsGetCurrentProcessSessionId(VOID
)
1124 return MmGetSessionId(PsGetCurrentProcess());
1132 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
1134 return Process
->SectionBaseAddress
;
1142 PsGetProcessSecurityPort(PEPROCESS Process
)
1144 return Process
->SecurityPort
;
1152 PsGetProcessSessionId(IN PEPROCESS Process
)
1154 return MmGetSessionId(Process
);
1162 PsGetProcessSessionIdEx(IN PEPROCESS Process
)
1164 return MmGetSessionIdEx(Process
);
1172 PsGetCurrentProcessWin32Process(VOID
)
1174 return PsGetCurrentProcess()->Win32Process
;
1182 PsGetProcessWin32Process(PEPROCESS Process
)
1184 return Process
->Win32Process
;
1192 PsGetProcessWin32WindowStation(PEPROCESS Process
)
1194 return Process
->Win32WindowStation
;
1202 PsIsProcessBeingDebugged(PEPROCESS Process
)
1204 return Process
->DebugPort
!= NULL
;
1212 PsIsSystemProcess(IN PEPROCESS Process
)
1214 /* Return if this is the System Process */
1215 return Process
== PsInitialSystemProcess
;
1223 PsSetProcessPriorityClass(PEPROCESS Process
,
1224 ULONG PriorityClass
)
1226 Process
->PriorityClass
= (UCHAR
)PriorityClass
;
1234 PsSetProcessSecurityPort(PEPROCESS Process
,
1237 Process
->SecurityPort
= SecurityPort
;
1238 return STATUS_SUCCESS
;
1246 PsSetProcessWin32Process(
1247 _Inout_ PEPROCESS Process
,
1248 _In_opt_ PVOID Win32Process
,
1249 _In_opt_ PVOID OldWin32Process
)
1253 /* Assume success */
1254 Status
= STATUS_SUCCESS
;
1256 /* Lock the process */
1257 KeEnterCriticalRegion();
1258 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
1260 /* Check if we set a new win32 process */
1261 if (Win32Process
!= NULL
)
1263 /* Check if the process is in the right state */
1264 if (((Process
->Flags
& PSF_PROCESS_DELETE_BIT
) == 0) &&
1265 (Process
->Win32Process
== NULL
))
1267 /* Set the new win32 process */
1268 Process
->Win32Process
= Win32Process
;
1272 /* Otherwise fail */
1273 Status
= STATUS_PROCESS_IS_TERMINATING
;
1278 /* Reset the win32 process, did the caller specify the correct old value? */
1279 if (Process
->Win32Process
== OldWin32Process
)
1281 /* Yes, so reset the win32 process to NULL */
1282 Process
->Win32Process
= 0;
1286 /* Otherwise fail */
1287 Status
= STATUS_UNSUCCESSFUL
;
1291 /* Unlock the process */
1292 ExReleasePushLockExclusive(&Process
->ProcessLock
);
1293 KeLeaveCriticalRegion();
1303 PsSetProcessWindowStation(PEPROCESS Process
,
1304 PVOID WindowStation
)
1306 Process
->Win32WindowStation
= WindowStation
;
1314 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
1315 IN PSPROCESSPRIORITYMODE Type
)
1319 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Type: %lx\n", Process
, Type
);
1321 /* Compute quantum and priority */
1322 Priority
= PspComputeQuantumAndPriority(Process
, Type
, &Quantum
);
1325 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, Priority
, Quantum
);
1333 NtCreateProcessEx(OUT PHANDLE ProcessHandle
,
1334 IN ACCESS_MASK DesiredAccess
,
1335 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1336 IN HANDLE ParentProcess
,
1338 IN HANDLE SectionHandle OPTIONAL
,
1339 IN HANDLE DebugPort OPTIONAL
,
1340 IN HANDLE ExceptionPort OPTIONAL
,
1343 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1346 PSTRACE(PS_PROCESS_DEBUG
,
1347 "ParentProcess: %p Flags: %lx\n", ParentProcess
, Flags
);
1349 /* Check if we came from user mode */
1350 if (PreviousMode
!= KernelMode
)
1354 /* Probe process handle */
1355 ProbeForWriteHandle(ProcessHandle
);
1357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1359 /* Return the exception code */
1360 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1365 /* Make sure there's a parent process */
1368 /* Can't create System Processes like this */
1369 Status
= STATUS_INVALID_PARAMETER
;
1373 /* Create a user Process */
1374 Status
= PspCreateProcess(ProcessHandle
,
1394 NtCreateProcess(OUT PHANDLE ProcessHandle
,
1395 IN ACCESS_MASK DesiredAccess
,
1396 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1397 IN HANDLE ParentProcess
,
1398 IN BOOLEAN InheritObjectTable
,
1399 IN HANDLE SectionHandle OPTIONAL
,
1400 IN HANDLE DebugPort OPTIONAL
,
1401 IN HANDLE ExceptionPort OPTIONAL
)
1404 PSTRACE(PS_PROCESS_DEBUG
,
1405 "Parent: %p Attributes: %p\n", ParentProcess
, ObjectAttributes
);
1407 /* Set new-style flags */
1408 if ((ULONG
)SectionHandle
& 1) Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
1409 if ((ULONG
)DebugPort
& 1) Flags
|= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
;
1410 if (InheritObjectTable
) Flags
|= PROCESS_CREATE_FLAGS_INHERIT_HANDLES
;
1412 /* Call the new API */
1413 return NtCreateProcessEx(ProcessHandle
,
1429 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1430 IN ACCESS_MASK DesiredAccess
,
1431 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1432 IN PCLIENT_ID ClientId
)
1434 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1435 CLIENT_ID SafeClientId
;
1436 ULONG Attributes
= 0;
1438 BOOLEAN HasObjectName
= FALSE
;
1439 PETHREAD Thread
= NULL
;
1440 PEPROCESS Process
= NULL
;
1442 ACCESS_STATE AccessState
;
1443 AUX_ACCESS_DATA AuxData
;
1445 PSTRACE(PS_PROCESS_DEBUG
,
1446 "ClientId: %p Attributes: %p\n", ClientId
, ObjectAttributes
);
1448 /* Check if we were called from user mode */
1449 if (PreviousMode
!= KernelMode
)
1451 /* Enter SEH for probing */
1454 /* Probe the thread handle */
1455 ProbeForWriteHandle(ProcessHandle
);
1457 /* Check for a CID structure */
1460 /* Probe and capture it */
1461 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1462 SafeClientId
= *ClientId
;
1463 ClientId
= &SafeClientId
;
1467 * Just probe the object attributes structure, don't capture it
1468 * completely. This is done later if necessary
1470 ProbeForRead(ObjectAttributes
,
1471 sizeof(OBJECT_ATTRIBUTES
),
1473 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1474 Attributes
= ObjectAttributes
->Attributes
;
1476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1478 /* Return the exception code */
1479 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1485 /* Otherwise just get the data directly */
1486 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1487 Attributes
= ObjectAttributes
->Attributes
;
1490 /* Can't pass both, fail */
1491 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1493 /* Create an access state */
1494 Status
= SeCreateAccessState(&AccessState
,
1497 &PsProcessType
->TypeInfo
.GenericMapping
);
1498 if (!NT_SUCCESS(Status
)) return Status
;
1500 /* Check if this is a debugger */
1501 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1503 /* Did he want full access? */
1504 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1506 /* Give it to him */
1507 AccessState
.PreviouslyGrantedAccess
|= PROCESS_ALL_ACCESS
;
1511 /* Otherwise just give every other access he could want */
1512 AccessState
.PreviouslyGrantedAccess
|=
1513 AccessState
.RemainingDesiredAccess
;
1516 /* The caller desires nothing else now */
1517 AccessState
.RemainingDesiredAccess
= 0;
1520 /* Open by name if one was given */
1524 Status
= ObOpenObjectByName(ObjectAttributes
,
1532 /* Get rid of the access state */
1533 SeDeleteAccessState(&AccessState
);
1537 /* Open by Thread ID */
1538 if (ClientId
->UniqueThread
)
1540 /* Get the Process */
1541 Status
= PsLookupProcessThreadByCid(ClientId
, &Process
, &Thread
);
1545 /* Get the Process */
1546 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1550 /* Check if we didn't find anything */
1551 if (!NT_SUCCESS(Status
))
1553 /* Get rid of the access state and return */
1554 SeDeleteAccessState(&AccessState
);
1558 /* Open the Process Object */
1559 Status
= ObOpenObjectByPointer(Process
,
1567 /* Delete the access state */
1568 SeDeleteAccessState(&AccessState
);
1570 /* Dereference the thread if we used it */
1571 if (Thread
) ObDereferenceObject(Thread
);
1573 /* Dereference the Process */
1574 ObDereferenceObject(Process
);
1578 /* neither an object name nor a client id was passed */
1579 return STATUS_INVALID_PARAMETER_MIX
;
1582 /* Check for success */
1583 if (NT_SUCCESS(Status
))
1585 /* Use SEH for write back */
1588 /* Write back the handle */
1589 *ProcessHandle
= hProcess
;
1591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1593 /* Get the exception code */
1594 Status
= _SEH2_GetExceptionCode();