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
& ~PS_ALL_FLAGS
) 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
& PS_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
& PS_INHERIT_HANDLES
? Parent
: NULL
,
600 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
604 /* Do the second part of the boot process memory setup */
605 Status
= MmInitializeHandBuiltProcess2(Process
);
606 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
609 /* Set success for now */
610 Status
= STATUS_SUCCESS
;
612 /* Check if this is a real user-mode process */
615 /* Initialize the address space */
616 Status
= MmInitializeProcessAddressSpace(Process
,
621 SeAuditProcessCreationInfo
.
623 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
632 /* Check if this is a child of the system process */
633 if (Parent
!= PsInitialSystemProcess
)
640 /* This is a clone! */
641 ASSERTMSG("No support for cloning yet\n", FALSE
);
645 /* This is the initial system process */
646 Flags
&= ~PS_LARGE_PAGES
;
647 Status
= MmInitializeProcessAddressSpace(Process
,
652 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
654 /* Create a dummy image file name */
655 Process
->SeAuditProcessCreationInfo
.ImageFileName
=
656 ExAllocatePoolWithTag(PagedPool
,
657 sizeof(OBJECT_NAME_INFORMATION
),
659 if (!Process
->SeAuditProcessCreationInfo
.ImageFileName
)
662 Status
= STATUS_INSUFFICIENT_RESOURCES
;
667 RtlZeroMemory(Process
->SeAuditProcessCreationInfo
.ImageFileName
,
668 sizeof(OBJECT_NAME_INFORMATION
));
673 /* Copy the process name now that we have it */
674 memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
675 if (Process
->Pcb
.DirectoryTableBase
[1]) memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
676 if (Process
->WorkingSetPage
) memcpy(MiGetPfnEntry(Process
->WorkingSetPage
)->ProcessName
, Process
->ImageFileName
, 16);
679 /* Check if we have a section object and map the system DLL */
680 if (SectionObject
) PspMapSystemDll(Process
, NULL
, FALSE
);
682 /* Create a handle for the Process */
683 CidEntry
.Object
= Process
;
684 CidEntry
.GrantedAccess
= 0;
685 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
686 if (!Process
->UniqueProcessId
)
689 Status
= STATUS_INSUFFICIENT_RESOURCES
;
693 /* Set the handle table PID */
694 Process
->ObjectTable
->UniqueProcessId
= Process
->UniqueProcessId
;
696 /* Check if we need to audit */
697 if (SeDetailedAuditingWithToken(NULL
)) SeAuditProcessCreate(Process
);
699 /* Check if the parent had a job */
700 if ((Parent
) && (Parent
->Job
))
702 /* FIXME: We need to insert this process */
703 DPRINT1("Jobs not yet supported\n");
707 /* Create PEB only for User-Mode Processes */
708 if ((Parent
) && (NeedsPeb
))
711 // Set up the initial PEB
713 RtlZeroMemory(&InitialPeb
, sizeof(INITIAL_PEB
));
714 InitialPeb
.Mutant
= (HANDLE
)-1;
715 InitialPeb
.ImageUsesLargePages
= 0; // FIXME: Not yet supported
718 // Create it only if we have an image section
725 Status
= MmCreatePeb(Process
, &InitialPeb
, &Process
->Peb
);
726 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
731 // We have to clone it
733 ASSERTMSG("No support for cloning yet\n", FALSE
);
738 /* The process can now be activated */
739 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
740 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
741 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
743 /* Create an access state */
744 Status
= SeCreateAccessStateEx(CurrentThread
,
746 (Parent
== PsInitialSystemProcess
)) ?
747 Parent
: CurrentProcess
,
751 &PsProcessType
->TypeInfo
.GenericMapping
);
752 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
754 /* Insert the Process into the Object Directory */
755 Status
= ObInsertObject(Process
,
762 /* Free the access state */
763 if (AccessState
) SeDeleteAccessState(AccessState
);
765 /* Cleanup on failure */
766 if (!NT_SUCCESS(Status
)) goto Cleanup
;
768 /* Compute Quantum and Priority */
769 ASSERT(IsListEmpty(&Process
->ThreadListHead
) == TRUE
);
770 Process
->Pcb
.BasePriority
=
771 (SCHAR
)PspComputeQuantumAndPriority(Process
,
772 PsProcessPriorityBackground
,
774 Process
->Pcb
.QuantumReset
= Quantum
;
776 /* Check if we have a parent other then the initial system process */
777 Process
->GrantedAccess
= PROCESS_TERMINATE
;
778 if ((Parent
) && (Parent
!= PsInitialSystemProcess
))
780 /* Get the process's SD */
781 Status
= ObGetObjectSecurity(Process
,
784 if (!NT_SUCCESS(Status
))
786 /* We failed, close the handle and clean up */
787 ObCloseHandle(hProcess
, PreviousMode
);
791 /* Create the subject context */
792 SubjectContext
.ProcessAuditId
= Process
;
793 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
794 SubjectContext
.ClientToken
= NULL
;
796 /* Do the access check */
797 Result
= SeAccessCheck(SecurityDescriptor
,
803 &PsProcessType
->TypeInfo
.GenericMapping
,
805 &Process
->GrantedAccess
,
808 /* Dereference the token and let go the SD */
809 ObFastDereferenceObject(&Process
->Token
,
810 SubjectContext
.PrimaryToken
);
811 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
813 /* Remove access if it failed */
814 if (!Result
) Process
->GrantedAccess
= 0;
816 /* Give the process some basic access */
817 Process
->GrantedAccess
|= (PROCESS_VM_OPERATION
|
820 PROCESS_QUERY_INFORMATION
|
822 PROCESS_CREATE_THREAD
|
824 PROCESS_CREATE_PROCESS
|
825 PROCESS_SET_INFORMATION
|
826 STANDARD_RIGHTS_ALL
|
831 /* Set full granted access */
832 Process
->GrantedAccess
= PROCESS_ALL_ACCESS
;
835 /* Set the Creation Time */
836 KeQuerySystemTime(&Process
->CreateTime
);
838 /* Protect against bad user-mode pointer */
841 /* Save the process handle */
842 *ProcessHandle
= hProcess
;
844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
846 /* Get the exception code */
847 Status
= _SEH2_GetExceptionCode();
851 /* Run the Notification Routines */
852 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
854 /* If 12 processes have been created, enough of user-mode is ready */
855 if (++ProcessCount
== 12) Ki386PerfEnd();
859 * Dereference the process. For failures, kills the process and does
860 * cleanup present in PspDeleteProcess. For success, kills the extra
861 * reference added by ObInsertObject.
863 ObDereferenceObject(Process
);
866 /* Dereference the parent */
867 if (Parent
) ObDereferenceObject(Parent
);
869 /* Return status to caller */
873 /* PUBLIC FUNCTIONS **********************************************************/
880 PsCreateSystemProcess(OUT PHANDLE ProcessHandle
,
881 IN ACCESS_MASK DesiredAccess
,
882 IN POBJECT_ATTRIBUTES ObjectAttributes
)
884 /* Call the internal API */
885 return PspCreateProcess(ProcessHandle
,
901 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
902 OUT PEPROCESS
*Process
)
904 PHANDLE_TABLE_ENTRY CidEntry
;
905 PEPROCESS FoundProcess
;
906 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
908 PSTRACE(PS_PROCESS_DEBUG
, "ProcessId: %p\n", ProcessId
);
909 KeEnterCriticalRegion();
911 /* Get the CID Handle Entry */
912 CidEntry
= ExMapHandleToPointer(PspCidTable
, ProcessId
);
915 /* Get the Process */
916 FoundProcess
= CidEntry
->Object
;
918 /* Make sure it's really a process */
919 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
921 /* Safe Reference and return it */
922 if (ObReferenceObjectSafe(FoundProcess
))
924 *Process
= FoundProcess
;
925 Status
= STATUS_SUCCESS
;
929 /* Unlock the Entry */
930 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
933 /* Return to caller */
934 KeLeaveCriticalRegion();
943 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
944 OUT PEPROCESS
*Process OPTIONAL
,
945 OUT PETHREAD
*Thread
)
947 PHANDLE_TABLE_ENTRY CidEntry
;
948 PETHREAD FoundThread
;
949 NTSTATUS Status
= STATUS_INVALID_CID
;
951 PSTRACE(PS_PROCESS_DEBUG
, "Cid: %p\n", Cid
);
952 KeEnterCriticalRegion();
954 /* Get the CID Handle Entry */
955 CidEntry
= ExMapHandleToPointer(PspCidTable
, Cid
->UniqueThread
);
958 /* Get the Process */
959 FoundThread
= CidEntry
->Object
;
961 /* Make sure it's really a thread and this process' */
962 if ((FoundThread
->Tcb
.Header
.Type
== ThreadObject
) &&
963 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
965 /* Safe Reference and return it */
966 if (ObReferenceObjectSafe(FoundThread
))
968 *Thread
= FoundThread
;
969 Status
= STATUS_SUCCESS
;
971 /* Check if we should return the Process too */
974 /* Return it and reference it */
975 *Process
= FoundThread
->ThreadsProcess
;
976 ObReferenceObject(*Process
);
981 /* Unlock the Entry */
982 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
985 /* Return to caller */
986 KeLeaveCriticalRegion();
995 PsGetProcessExitTime(VOID
)
997 return PsGetCurrentProcess()->ExitTime
;
1005 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
1007 return Process
->CreateTime
.QuadPart
;
1015 PsGetProcessDebugPort(PEPROCESS Process
)
1017 return Process
->DebugPort
;
1025 PsGetProcessExitProcessCalled(PEPROCESS Process
)
1027 return (BOOLEAN
)Process
->ProcessExiting
;
1035 PsGetProcessExitStatus(PEPROCESS Process
)
1037 return Process
->ExitStatus
;
1045 PsGetProcessId(PEPROCESS Process
)
1047 return (HANDLE
)Process
->UniqueProcessId
;
1055 PsGetProcessImageFileName(PEPROCESS Process
)
1057 return (LPSTR
)Process
->ImageFileName
;
1065 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
1067 return Process
->InheritedFromUniqueProcessId
;
1075 PsGetProcessJob(PEPROCESS Process
)
1077 return Process
->Job
;
1085 PsGetProcessPeb(PEPROCESS Process
)
1087 return Process
->Peb
;
1095 PsGetProcessPriorityClass(PEPROCESS Process
)
1097 return Process
->PriorityClass
;
1105 PsGetCurrentProcessId(VOID
)
1107 return (HANDLE
)PsGetCurrentProcess()->UniqueProcessId
;
1115 PsGetCurrentProcessSessionId(VOID
)
1117 return MmGetSessionId(PsGetCurrentProcess());
1125 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
1127 return Process
->SectionBaseAddress
;
1135 PsGetProcessSecurityPort(PEPROCESS Process
)
1137 return Process
->SecurityPort
;
1145 PsGetProcessSessionId(PEPROCESS Process
)
1147 return (HANDLE
)Process
->Session
;
1155 PsGetCurrentProcessWin32Process(VOID
)
1157 return PsGetCurrentProcess()->Win32Process
;
1165 PsGetProcessWin32Process(PEPROCESS Process
)
1167 return Process
->Win32Process
;
1175 PsGetProcessWin32WindowStation(PEPROCESS Process
)
1177 return Process
->Win32WindowStation
;
1185 PsIsProcessBeingDebugged(PEPROCESS Process
)
1187 return Process
->DebugPort
!= NULL
;
1195 PsIsSystemProcess(IN PEPROCESS Process
)
1197 /* Return if this is the System Process */
1198 return Process
== PsInitialSystemProcess
;
1206 PsSetProcessPriorityClass(PEPROCESS Process
,
1207 ULONG PriorityClass
)
1209 Process
->PriorityClass
= (UCHAR
)PriorityClass
;
1217 PsSetProcessSecurityPort(PEPROCESS Process
,
1220 Process
->SecurityPort
= SecurityPort
;
1228 PsSetProcessWin32Process(PEPROCESS Process
,
1231 Process
->Win32Process
= Win32Process
;
1239 PsSetProcessWindowStation(PEPROCESS Process
,
1240 PVOID WindowStation
)
1242 Process
->Win32WindowStation
= WindowStation
;
1250 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
1251 IN PSPROCESSPRIORITYMODE Type
)
1255 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Type: %lx\n", Process
, Type
);
1257 /* Compute quantum and priority */
1258 Priority
= PspComputeQuantumAndPriority(Process
, Type
, &Quantum
);
1261 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, Priority
, Quantum
);
1269 NtCreateProcessEx(OUT PHANDLE ProcessHandle
,
1270 IN ACCESS_MASK DesiredAccess
,
1271 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1272 IN HANDLE ParentProcess
,
1274 IN HANDLE SectionHandle OPTIONAL
,
1275 IN HANDLE DebugPort OPTIONAL
,
1276 IN HANDLE ExceptionPort OPTIONAL
,
1279 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1282 PSTRACE(PS_PROCESS_DEBUG
,
1283 "ParentProcess: %p Flags: %lx\n", ParentProcess
, Flags
);
1285 /* Check if we came from user mode */
1286 if (PreviousMode
!= KernelMode
)
1290 /* Probe process handle */
1291 ProbeForWriteHandle(ProcessHandle
);
1293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1295 /* Return the exception code */
1296 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1301 /* Make sure there's a parent process */
1304 /* Can't create System Processes like this */
1305 Status
= STATUS_INVALID_PARAMETER
;
1309 /* Create a user Process */
1310 Status
= PspCreateProcess(ProcessHandle
,
1330 NtCreateProcess(OUT PHANDLE ProcessHandle
,
1331 IN ACCESS_MASK DesiredAccess
,
1332 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1333 IN HANDLE ParentProcess
,
1334 IN BOOLEAN InheritObjectTable
,
1335 IN HANDLE SectionHandle OPTIONAL
,
1336 IN HANDLE DebugPort OPTIONAL
,
1337 IN HANDLE ExceptionPort OPTIONAL
)
1340 PSTRACE(PS_PROCESS_DEBUG
,
1341 "Parent: %p Attributes: %p\n", ParentProcess
, ObjectAttributes
);
1343 /* Set new-style flags */
1344 if ((ULONG
)SectionHandle
& 1) Flags
= PS_REQUEST_BREAKAWAY
;
1345 if ((ULONG
)DebugPort
& 1) Flags
|= PS_NO_DEBUG_INHERIT
;
1346 if (InheritObjectTable
) Flags
|= PS_INHERIT_HANDLES
;
1348 /* Call the new API */
1349 return NtCreateProcessEx(ProcessHandle
,
1365 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1366 IN ACCESS_MASK DesiredAccess
,
1367 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1368 IN PCLIENT_ID ClientId
)
1370 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1371 CLIENT_ID SafeClientId
;
1372 ULONG Attributes
= 0;
1374 BOOLEAN HasObjectName
= FALSE
;
1375 PETHREAD Thread
= NULL
;
1376 PEPROCESS Process
= NULL
;
1378 ACCESS_STATE AccessState
;
1379 AUX_ACCESS_DATA AuxData
;
1381 PSTRACE(PS_PROCESS_DEBUG
,
1382 "ClientId: %p Attributes: %p\n", ClientId
, ObjectAttributes
);
1384 /* Check if we were called from user mode */
1385 if (PreviousMode
!= KernelMode
)
1387 /* Enter SEH for probing */
1390 /* Probe the thread handle */
1391 ProbeForWriteHandle(ProcessHandle
);
1393 /* Check for a CID structure */
1396 /* Probe and capture it */
1397 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1398 SafeClientId
= *ClientId
;
1399 ClientId
= &SafeClientId
;
1403 * Just probe the object attributes structure, don't capture it
1404 * completely. This is done later if necessary
1406 ProbeForRead(ObjectAttributes
,
1407 sizeof(OBJECT_ATTRIBUTES
),
1409 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1410 Attributes
= ObjectAttributes
->Attributes
;
1412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1414 /* Return the exception code */
1415 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1421 /* Otherwise just get the data directly */
1422 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1423 Attributes
= ObjectAttributes
->Attributes
;
1426 /* Can't pass both, fail */
1427 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1429 /* Create an access state */
1430 Status
= SeCreateAccessState(&AccessState
,
1433 &PsProcessType
->TypeInfo
.GenericMapping
);
1434 if (!NT_SUCCESS(Status
)) return Status
;
1436 /* Check if this is a debugger */
1437 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1439 /* Did he want full access? */
1440 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1442 /* Give it to him */
1443 AccessState
.PreviouslyGrantedAccess
|= PROCESS_ALL_ACCESS
;
1447 /* Otherwise just give every other access he could want */
1448 AccessState
.PreviouslyGrantedAccess
|=
1449 AccessState
.RemainingDesiredAccess
;
1452 /* The caller desires nothing else now */
1453 AccessState
.RemainingDesiredAccess
= 0;
1456 /* Open by name if one was given */
1460 Status
= ObOpenObjectByName(ObjectAttributes
,
1468 /* Get rid of the access state */
1469 SeDeleteAccessState(&AccessState
);
1473 /* Open by Thread ID */
1474 if (ClientId
->UniqueThread
)
1476 /* Get the Process */
1477 Status
= PsLookupProcessThreadByCid(ClientId
, &Process
, &Thread
);
1481 /* Get the Process */
1482 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1486 /* Check if we didn't find anything */
1487 if (!NT_SUCCESS(Status
))
1489 /* Get rid of the access state and return */
1490 SeDeleteAccessState(&AccessState
);
1494 /* Open the Process Object */
1495 Status
= ObOpenObjectByPointer(Process
,
1503 /* Delete the access state */
1504 SeDeleteAccessState(&AccessState
);
1506 /* Dereference the thread if we used it */
1507 if (Thread
) ObDereferenceObject(Thread
);
1509 /* Dereference the Process */
1510 ObDereferenceObject(Process
);
1514 /* neither an object name nor a client id was passed */
1515 return STATUS_INVALID_PARAMETER_MIX
;
1518 /* Check for success */
1519 if (NT_SUCCESS(Status
))
1521 /* Use SEH for write back */
1524 /* Write back the handle */
1525 *ProcessHandle
= hProcess
;
1527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1529 /* Get the exception code */
1530 Status
= _SEH2_GetExceptionCode();