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
;
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
;
258 else if (PspQuantumTypeFromMask(PrioritySeparation
) == PSP_FIXED_QUANTUMS
)
260 /* Use fixed table */
261 QuantumTable
= PspFixedQuantums
;
265 /* Use default for the type of system we're on */
266 QuantumTable
= MmIsThisAnNtAsSystem() ? PspFixedQuantums
: PspVariableQuantums
;
269 /* Now check if we should use long or short */
270 if (PspQuantumLengthFromMask(PrioritySeparation
) == PSP_LONG_QUANTUMS
)
272 /* Use long quantums */
275 else if (PspQuantumLengthFromMask(PrioritySeparation
) == PSP_SHORT_QUANTUMS
)
277 /* Keep existing table */
282 /* Use default for the type of system we're on */
283 QuantumTable
+= MmIsThisAnNtAsSystem() ? 3 : 0;
286 /* Check if we're using long fixed quantums */
287 if (QuantumTable
== &PspFixedQuantums
[3])
289 /* Use Job scheduling classes */
290 PspUseJobSchedulingClasses
= TRUE
;
294 /* Otherwise, we don't */
295 PspUseJobSchedulingClasses
= FALSE
;
298 /* Copy the selected table into the Foreground Quantum table */
299 RtlCopyMemory(PspForegroundQuantum
,
301 sizeof(PspForegroundQuantum
));
303 /* Check if we should apply these changes real-time */
306 /* We are...loop every process */
307 Process
= PsGetNextProcess(Process
);
310 /* Use the priority separation if this is a foreground process */
311 i
= (Process
->Vm
.Flags
.MemoryPriority
==
312 MEMORY_PRIORITY_BACKGROUND
) ?
313 0: PsPrioritySeparation
;
315 /* Make sure that the process isn't idle */
316 if (Process
->PriorityClass
!= PROCESS_PRIORITY_CLASS_IDLE
)
318 /* Does the process have a job? */
319 if ((Process
->Job
) && (PspUseJobSchedulingClasses
))
321 /* Use job quantum */
322 Quantum
= PspJobSchedulingClasses
[Process
->Job
->SchedulingClass
];
326 /* Use calculated quantum */
327 Quantum
= PspForegroundQuantum
[i
];
332 /* Process is idle, use default quantum */
336 /* Now set the quantum */
337 KeSetQuantumProcess(&Process
->Pcb
, Quantum
);
339 /* Get the next process */
340 Process
= PsGetNextProcess(Process
);
347 PspCreateProcess(OUT PHANDLE ProcessHandle
,
348 IN ACCESS_MASK DesiredAccess
,
349 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
350 IN HANDLE ParentProcess OPTIONAL
,
352 IN HANDLE SectionHandle OPTIONAL
,
353 IN HANDLE DebugPort OPTIONAL
,
354 IN HANDLE ExceptionPort OPTIONAL
,
358 PEPROCESS Process
, Parent
;
359 PVOID ExceptionPortObject
;
360 PDEBUG_OBJECT DebugObject
;
361 PSECTION_OBJECT SectionObject
;
362 NTSTATUS Status
, AccessStatus
;
363 ULONG_PTR DirectoryTableBase
[2] = {0,0};
365 HANDLE_TABLE_ENTRY CidEntry
;
366 PETHREAD CurrentThread
= PsGetCurrentThread();
367 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
368 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
370 ACCESS_STATE LocalAccessState
;
371 PACCESS_STATE AccessState
= &LocalAccessState
;
372 AUX_ACCESS_DATA AuxData
;
374 BOOLEAN Result
, SdAllocated
;
375 PSECURITY_DESCRIPTOR SecurityDescriptor
;
376 SECURITY_SUBJECT_CONTEXT SubjectContext
;
377 BOOLEAN NeedsPeb
= FALSE
;
378 INITIAL_PEB InitialPeb
;
380 PSTRACE(PS_PROCESS_DEBUG
,
381 "ProcessHandle: %p Parent: %p\n", ProcessHandle
, ParentProcess
);
384 if (Flags
& ~PROCESS_CREATE_FLAGS_LEGAL_MASK
) return STATUS_INVALID_PARAMETER
;
386 /* Check for parent */
390 Status
= ObReferenceObjectByHandle(ParentProcess
,
391 PROCESS_CREATE_PROCESS
,
396 if (!NT_SUCCESS(Status
)) return Status
;
398 /* If this process should be in a job but the parent isn't */
399 if ((InJob
) && (!Parent
->Job
))
401 /* This is illegal. Dereference the parent and fail */
402 ObDereferenceObject(Parent
);
403 return STATUS_INVALID_PARAMETER
;
406 /* Inherit Parent process's Affinity. */
407 Affinity
= Parent
->Pcb
.Affinity
;
411 /* We have no parent */
413 Affinity
= KeActiveProcessors
;
416 /* Save working set data */
417 MinWs
= PsMinimumWorkingSet
;
418 MaxWs
= PsMaximumWorkingSet
;
420 /* Create the Object */
421 Status
= ObCreateObject(PreviousMode
,
430 if (!NT_SUCCESS(Status
)) goto Cleanup
;
432 /* Clean up the Object */
433 RtlZeroMemory(Process
, sizeof(EPROCESS
));
435 /* Initialize pushlock and rundown protection */
436 ExInitializeRundownProtection(&Process
->RundownProtect
);
437 Process
->ProcessLock
.Value
= 0;
439 /* Setup the Thread List Head */
440 InitializeListHead(&Process
->ThreadListHead
);
442 /* Set up the Quota Block from the Parent */
443 PspInheritQuota(Process
, Parent
);
445 /* Set up Dos Device Map from the Parent */
446 ObInheritDeviceMap(Parent
, Process
);
448 /* Check if we have a parent */
451 /* Inherit PID and hard-error processing */
452 Process
->InheritedFromUniqueProcessId
= Parent
->UniqueProcessId
;
453 Process
->DefaultHardErrorProcessing
= Parent
->DefaultHardErrorProcessing
;
457 /* Use default hard-error processing */
458 Process
->DefaultHardErrorProcessing
= SEM_FAILCRITICALERRORS
;
461 /* Check for a section handle */
464 /* Get a pointer to it */
465 Status
= ObReferenceObjectByHandle(SectionHandle
,
469 (PVOID
*)&SectionObject
,
471 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
475 /* Assume no section object */
476 SectionObject
= NULL
;
478 /* Is the parent the initial process?
479 * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */
480 if (Parent
!= PsInitialSystemProcess
&& (Parent
!= NULL
))
482 /* It's not, so acquire the process rundown */
483 if (ExAcquireRundownProtection(&Parent
->RundownProtect
))
485 /* If the parent has a section, use it */
486 SectionObject
= Parent
->SectionObject
;
487 if (SectionObject
) ObReferenceObject(SectionObject
);
489 /* Release process rundown */
490 ExReleaseRundownProtection(&Parent
->RundownProtect
);
493 /* If we don't have a section object */
496 /* Then the process is in termination, so fail */
497 Status
= STATUS_PROCESS_IS_TERMINATING
;
503 /* Save the pointer to the section object */
504 Process
->SectionObject
= SectionObject
;
506 /* Check for the debug port */
510 Status
= ObReferenceObjectByHandle(DebugPort
,
511 DEBUG_OBJECT_ADD_REMOVE_PROCESS
,
514 (PVOID
*)&DebugObject
,
516 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
518 /* Save the debug object */
519 Process
->DebugPort
= DebugObject
;
521 /* Check if the caller doesn't want the debug stuff inherited */
522 if (Flags
& PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
)
524 /* Set the process flag */
525 InterlockedOr((PLONG
)&Process
->Flags
, PSF_NO_DEBUG_INHERIT_BIT
);
530 /* Do we have a parent? Copy his debug port */
531 if (Parent
) DbgkCopyProcessDebugPort(Process
, Parent
);
534 /* Now check for an exception port */
538 Status
= ObReferenceObjectByHandle(ExceptionPort
,
542 (PVOID
*)&ExceptionPortObject
,
544 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
546 /* Save the exception port */
547 Process
->ExceptionPort
= ExceptionPortObject
;
550 /* Save the pointer to the section object */
551 Process
->SectionObject
= SectionObject
;
553 /* Set default exit code */
554 Process
->ExitStatus
= STATUS_PENDING
;
556 /* Check if this is the initial process being built */
559 /* Create the address space for the child */
560 if (!MmCreateProcessAddressSpace(MinWs
,
565 Status
= STATUS_INSUFFICIENT_RESOURCES
;
571 /* Otherwise, we are the boot process, we're already semi-initialized */
572 Process
->ObjectTable
= CurrentProcess
->ObjectTable
;
573 Status
= MmInitializeHandBuiltProcess(Process
, DirectoryTableBase
);
574 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
577 /* We now have an address space */
578 InterlockedOr((PLONG
)&Process
->Flags
, PSF_HAS_ADDRESS_SPACE_BIT
);
580 /* Set the maximum WS */
581 Process
->Vm
.MaximumWorkingSetSize
= MaxWs
;
583 /* Now initialize the Kernel Process */
584 KeInitializeProcess(&Process
->Pcb
,
585 PROCESS_PRIORITY_NORMAL
,
588 BooleanFlagOn(Process
->DefaultHardErrorProcessing
,
589 SEM_NOALIGNMENTFAULTEXCEPT
));
591 /* Duplicate Parent Token */
592 Status
= PspInitializeProcessSecurity(Process
, Parent
);
593 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
595 /* Set default priority class */
596 Process
->PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
598 /* Check if we have a parent */
601 /* Check our priority class */
602 if (Parent
->PriorityClass
== PROCESS_PRIORITY_CLASS_IDLE
||
603 Parent
->PriorityClass
== PROCESS_PRIORITY_CLASS_BELOW_NORMAL
)
606 Process
->PriorityClass
= Parent
->PriorityClass
;
609 /* Initialize object manager for the process */
610 Status
= ObInitProcess(Flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
?
613 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
617 /* Do the second part of the boot process memory setup */
618 Status
= MmInitializeHandBuiltProcess2(Process
);
619 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
622 /* Set success for now */
623 Status
= STATUS_SUCCESS
;
625 /* Check if this is a real user-mode process */
628 /* Initialize the address space */
629 Status
= MmInitializeProcessAddressSpace(Process
,
634 SeAuditProcessCreationInfo
.
636 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
645 /* Check if this is a child of the system process */
646 if (Parent
!= PsInitialSystemProcess
)
653 /* This is a clone! */
654 ASSERTMSG("No support for cloning yet\n", FALSE
);
658 /* This is the initial system process */
659 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
660 Status
= MmInitializeProcessAddressSpace(Process
,
665 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
667 /* Create a dummy image file name */
668 Process
->SeAuditProcessCreationInfo
.ImageFileName
=
669 ExAllocatePoolWithTag(PagedPool
,
670 sizeof(OBJECT_NAME_INFORMATION
),
672 if (!Process
->SeAuditProcessCreationInfo
.ImageFileName
)
675 Status
= STATUS_INSUFFICIENT_RESOURCES
;
680 RtlZeroMemory(Process
->SeAuditProcessCreationInfo
.ImageFileName
,
681 sizeof(OBJECT_NAME_INFORMATION
));
686 /* Copy the process name now that we have it */
687 memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
688 if (Process
->Pcb
.DirectoryTableBase
[1]) memcpy(MiGetPfnEntry(Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
)->ProcessName
, Process
->ImageFileName
, 16);
689 if (Process
->WorkingSetPage
) memcpy(MiGetPfnEntry(Process
->WorkingSetPage
)->ProcessName
, Process
->ImageFileName
, 16);
692 /* Check if we have a section object and map the system DLL */
693 if (SectionObject
) PspMapSystemDll(Process
, NULL
, FALSE
);
695 /* Create a handle for the Process */
696 CidEntry
.Object
= Process
;
697 CidEntry
.GrantedAccess
= 0;
698 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
699 if (!Process
->UniqueProcessId
)
702 Status
= STATUS_INSUFFICIENT_RESOURCES
;
706 /* Set the handle table PID */
707 Process
->ObjectTable
->UniqueProcessId
= Process
->UniqueProcessId
;
709 /* Check if we need to audit */
710 if (SeDetailedAuditingWithToken(NULL
)) SeAuditProcessCreate(Process
);
712 /* Check if the parent had a job */
713 if ((Parent
) && (Parent
->Job
))
715 /* FIXME: We need to insert this process */
716 DPRINT1("Jobs not yet supported\n");
719 /* Create PEB only for User-Mode Processes */
720 if ((Parent
) && (NeedsPeb
))
723 // Set up the initial PEB
725 RtlZeroMemory(&InitialPeb
, sizeof(INITIAL_PEB
));
726 InitialPeb
.Mutant
= (HANDLE
)-1;
727 InitialPeb
.ImageUsesLargePages
= 0; // FIXME: Not yet supported
730 // Create it only if we have an image section
737 Status
= MmCreatePeb(Process
, &InitialPeb
, &Process
->Peb
);
738 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
743 // We have to clone it
745 ASSERTMSG("No support for cloning yet\n", FALSE
);
750 /* The process can now be activated */
751 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
752 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
753 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
755 /* Create an access state */
756 Status
= SeCreateAccessStateEx(CurrentThread
,
758 (Parent
== PsInitialSystemProcess
)) ?
759 Parent
: CurrentProcess
,
763 &PsProcessType
->TypeInfo
.GenericMapping
);
764 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
766 /* Insert the Process into the Object Directory */
767 Status
= ObInsertObject(Process
,
774 /* Free the access state */
775 if (AccessState
) SeDeleteAccessState(AccessState
);
777 /* Cleanup on failure */
778 if (!NT_SUCCESS(Status
)) goto Cleanup
;
780 /* Compute Quantum and Priority */
781 ASSERT(IsListEmpty(&Process
->ThreadListHead
) == TRUE
);
782 Process
->Pcb
.BasePriority
=
783 (SCHAR
)PspComputeQuantumAndPriority(Process
,
784 PsProcessPriorityBackground
,
786 Process
->Pcb
.QuantumReset
= Quantum
;
788 /* Check if we have a parent other then the initial system process */
789 Process
->GrantedAccess
= PROCESS_TERMINATE
;
790 if ((Parent
) && (Parent
!= PsInitialSystemProcess
))
792 /* Get the process's SD */
793 Status
= ObGetObjectSecurity(Process
,
796 if (!NT_SUCCESS(Status
))
798 /* We failed, close the handle and clean up */
799 ObCloseHandle(hProcess
, PreviousMode
);
803 /* Create the subject context */
804 SubjectContext
.ProcessAuditId
= Process
;
805 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
806 SubjectContext
.ClientToken
= NULL
;
808 /* Do the access check */
809 Result
= SeAccessCheck(SecurityDescriptor
,
815 &PsProcessType
->TypeInfo
.GenericMapping
,
817 &Process
->GrantedAccess
,
820 /* Dereference the token and let go the SD */
821 ObFastDereferenceObject(&Process
->Token
,
822 SubjectContext
.PrimaryToken
);
823 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
825 /* Remove access if it failed */
826 if (!Result
) Process
->GrantedAccess
= 0;
828 /* Give the process some basic access */
829 Process
->GrantedAccess
|= (PROCESS_VM_OPERATION
|
832 PROCESS_QUERY_INFORMATION
|
834 PROCESS_CREATE_THREAD
|
836 PROCESS_CREATE_PROCESS
|
837 PROCESS_SET_INFORMATION
|
838 STANDARD_RIGHTS_ALL
|
843 /* Set full granted access */
844 Process
->GrantedAccess
= PROCESS_ALL_ACCESS
;
847 /* Set the Creation Time */
848 KeQuerySystemTime(&Process
->CreateTime
);
850 /* Protect against bad user-mode pointer */
853 /* Hacky way of returning the PEB to the user-mode creator */
854 if ((Process
->Peb
) && (CurrentThread
->Tcb
.Teb
))
856 CurrentThread
->Tcb
.Teb
->NtTib
.ArbitraryUserPointer
= Process
->Peb
;
859 /* Save the process handle */
860 *ProcessHandle
= hProcess
;
862 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
864 /* Get the exception code */
865 Status
= _SEH2_GetExceptionCode();
869 /* Run the Notification Routines */
870 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
872 /* If 12 processes have been created, enough of user-mode is ready */
873 if (++ProcessCount
== 12) Ki386PerfEnd();
877 * Dereference the process. For failures, kills the process and does
878 * cleanup present in PspDeleteProcess. For success, kills the extra
879 * reference added by ObInsertObject.
881 ObDereferenceObject(Process
);
884 /* Dereference the parent */
885 if (Parent
) ObDereferenceObject(Parent
);
887 /* Return status to caller */
891 /* PUBLIC FUNCTIONS **********************************************************/
898 PsCreateSystemProcess(OUT PHANDLE ProcessHandle
,
899 IN ACCESS_MASK DesiredAccess
,
900 IN POBJECT_ATTRIBUTES ObjectAttributes
)
902 /* Call the internal API */
903 return PspCreateProcess(ProcessHandle
,
919 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
920 OUT PEPROCESS
*Process
)
922 PHANDLE_TABLE_ENTRY CidEntry
;
923 PEPROCESS FoundProcess
;
924 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
926 PSTRACE(PS_PROCESS_DEBUG
, "ProcessId: %p\n", ProcessId
);
927 KeEnterCriticalRegion();
929 /* Get the CID Handle Entry */
930 CidEntry
= ExMapHandleToPointer(PspCidTable
, ProcessId
);
933 /* Get the Process */
934 FoundProcess
= CidEntry
->Object
;
936 /* Make sure it's really a process */
937 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
939 /* Safe Reference and return it */
940 if (ObReferenceObjectSafe(FoundProcess
))
942 *Process
= FoundProcess
;
943 Status
= STATUS_SUCCESS
;
947 /* Unlock the Entry */
948 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
951 /* Return to caller */
952 KeLeaveCriticalRegion();
961 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
962 OUT PEPROCESS
*Process OPTIONAL
,
963 OUT PETHREAD
*Thread
)
965 PHANDLE_TABLE_ENTRY CidEntry
;
966 PETHREAD FoundThread
;
967 NTSTATUS Status
= STATUS_INVALID_CID
;
969 PSTRACE(PS_PROCESS_DEBUG
, "Cid: %p\n", Cid
);
970 KeEnterCriticalRegion();
972 /* Get the CID Handle Entry */
973 CidEntry
= ExMapHandleToPointer(PspCidTable
, Cid
->UniqueThread
);
976 /* Get the Process */
977 FoundThread
= CidEntry
->Object
;
979 /* Make sure it's really a thread and this process' */
980 if ((FoundThread
->Tcb
.Header
.Type
== ThreadObject
) &&
981 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
983 /* Safe Reference and return it */
984 if (ObReferenceObjectSafe(FoundThread
))
986 *Thread
= FoundThread
;
987 Status
= STATUS_SUCCESS
;
989 /* Check if we should return the Process too */
992 /* Return it and reference it */
993 *Process
= FoundThread
->ThreadsProcess
;
994 ObReferenceObject(*Process
);
999 /* Unlock the Entry */
1000 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
1003 /* Return to caller */
1004 KeLeaveCriticalRegion();
1013 PsGetProcessExitTime(VOID
)
1015 return PsGetCurrentProcess()->ExitTime
;
1023 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
1025 return Process
->CreateTime
.QuadPart
;
1033 PsGetProcessDebugPort(PEPROCESS Process
)
1035 return Process
->DebugPort
;
1043 PsGetProcessExitProcessCalled(PEPROCESS Process
)
1045 return (BOOLEAN
)Process
->ProcessExiting
;
1053 PsGetProcessExitStatus(PEPROCESS Process
)
1055 return Process
->ExitStatus
;
1063 PsGetProcessId(PEPROCESS Process
)
1065 return (HANDLE
)Process
->UniqueProcessId
;
1073 PsGetProcessImageFileName(PEPROCESS Process
)
1075 return (LPSTR
)Process
->ImageFileName
;
1083 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
1085 return Process
->InheritedFromUniqueProcessId
;
1093 PsGetProcessJob(PEPROCESS Process
)
1095 return Process
->Job
;
1103 PsGetProcessPeb(PEPROCESS Process
)
1105 return Process
->Peb
;
1113 PsGetProcessPriorityClass(PEPROCESS Process
)
1115 return Process
->PriorityClass
;
1123 PsGetCurrentProcessId(VOID
)
1125 return (HANDLE
)PsGetCurrentProcess()->UniqueProcessId
;
1133 PsGetCurrentProcessSessionId(VOID
)
1135 return MmGetSessionId(PsGetCurrentProcess());
1143 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
1145 return Process
->SectionBaseAddress
;
1153 PsGetProcessSecurityPort(PEPROCESS Process
)
1155 return Process
->SecurityPort
;
1163 PsGetProcessSessionId(IN PEPROCESS Process
)
1165 return MmGetSessionId(Process
);
1173 PsGetProcessSessionIdEx(IN PEPROCESS Process
)
1175 return MmGetSessionIdEx(Process
);
1183 PsGetCurrentProcessWin32Process(VOID
)
1185 return PsGetCurrentProcess()->Win32Process
;
1193 PsGetProcessWin32Process(PEPROCESS Process
)
1195 return Process
->Win32Process
;
1203 PsGetProcessWin32WindowStation(PEPROCESS Process
)
1205 return Process
->Win32WindowStation
;
1213 PsIsProcessBeingDebugged(PEPROCESS Process
)
1215 return Process
->DebugPort
!= NULL
;
1223 PsIsSystemProcess(IN PEPROCESS Process
)
1225 /* Return if this is the System Process */
1226 return Process
== PsInitialSystemProcess
;
1234 PsSetProcessPriorityClass(PEPROCESS Process
,
1235 ULONG PriorityClass
)
1237 Process
->PriorityClass
= (UCHAR
)PriorityClass
;
1245 PsSetProcessSecurityPort(PEPROCESS Process
,
1248 Process
->SecurityPort
= SecurityPort
;
1249 return STATUS_SUCCESS
;
1257 PsSetProcessWin32Process(
1258 _Inout_ PEPROCESS Process
,
1259 _In_opt_ PVOID Win32Process
,
1260 _In_opt_ PVOID OldWin32Process
)
1264 /* Assume success */
1265 Status
= STATUS_SUCCESS
;
1267 /* Lock the process */
1268 KeEnterCriticalRegion();
1269 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
1271 /* Check if we set a new win32 process */
1272 if (Win32Process
!= NULL
)
1274 /* Check if the process is in the right state */
1275 if (((Process
->Flags
& PSF_PROCESS_DELETE_BIT
) == 0) &&
1276 (Process
->Win32Process
== NULL
))
1278 /* Set the new win32 process */
1279 Process
->Win32Process
= Win32Process
;
1283 /* Otherwise fail */
1284 Status
= STATUS_PROCESS_IS_TERMINATING
;
1289 /* Reset the win32 process, did the caller specify the correct old value? */
1290 if (Process
->Win32Process
== OldWin32Process
)
1292 /* Yes, so reset the win32 process to NULL */
1293 Process
->Win32Process
= NULL
;
1297 /* Otherwise fail */
1298 Status
= STATUS_UNSUCCESSFUL
;
1302 /* Unlock the process */
1303 ExReleasePushLockExclusive(&Process
->ProcessLock
);
1304 KeLeaveCriticalRegion();
1314 PsSetProcessWindowStation(PEPROCESS Process
,
1315 PVOID WindowStation
)
1317 Process
->Win32WindowStation
= WindowStation
;
1325 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
1326 IN PSPROCESSPRIORITYMODE Type
)
1330 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Type: %lx\n", Process
, Type
);
1332 /* Compute quantum and priority */
1333 Priority
= PspComputeQuantumAndPriority(Process
, Type
, &Quantum
);
1336 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, Priority
, Quantum
);
1344 NtCreateProcessEx(OUT PHANDLE ProcessHandle
,
1345 IN ACCESS_MASK DesiredAccess
,
1346 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1347 IN HANDLE ParentProcess
,
1349 IN HANDLE SectionHandle OPTIONAL
,
1350 IN HANDLE DebugPort OPTIONAL
,
1351 IN HANDLE ExceptionPort OPTIONAL
,
1354 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1357 PSTRACE(PS_PROCESS_DEBUG
,
1358 "ParentProcess: %p Flags: %lx\n", ParentProcess
, Flags
);
1360 /* Check if we came from user mode */
1361 if (PreviousMode
!= KernelMode
)
1365 /* Probe process handle */
1366 ProbeForWriteHandle(ProcessHandle
);
1368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1370 /* Return the exception code */
1371 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1376 /* Make sure there's a parent process */
1379 /* Can't create System Processes like this */
1380 Status
= STATUS_INVALID_PARAMETER
;
1384 /* Create a user Process */
1385 Status
= PspCreateProcess(ProcessHandle
,
1405 NtCreateProcess(OUT PHANDLE ProcessHandle
,
1406 IN ACCESS_MASK DesiredAccess
,
1407 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1408 IN HANDLE ParentProcess
,
1409 IN BOOLEAN InheritObjectTable
,
1410 IN HANDLE SectionHandle OPTIONAL
,
1411 IN HANDLE DebugPort OPTIONAL
,
1412 IN HANDLE ExceptionPort OPTIONAL
)
1415 PSTRACE(PS_PROCESS_DEBUG
,
1416 "Parent: %p Attributes: %p\n", ParentProcess
, ObjectAttributes
);
1418 /* Set new-style flags */
1419 if ((ULONG_PTR
)SectionHandle
& 1) Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
1420 if ((ULONG_PTR
)DebugPort
& 1) Flags
|= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
;
1421 if (InheritObjectTable
) Flags
|= PROCESS_CREATE_FLAGS_INHERIT_HANDLES
;
1423 /* Call the new API */
1424 return NtCreateProcessEx(ProcessHandle
,
1440 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1441 IN ACCESS_MASK DesiredAccess
,
1442 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1443 IN PCLIENT_ID ClientId
)
1445 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1446 CLIENT_ID SafeClientId
;
1447 ULONG Attributes
= 0;
1449 BOOLEAN HasObjectName
= FALSE
;
1450 PETHREAD Thread
= NULL
;
1451 PEPROCESS Process
= NULL
;
1453 ACCESS_STATE AccessState
;
1454 AUX_ACCESS_DATA AuxData
;
1456 PSTRACE(PS_PROCESS_DEBUG
,
1457 "ClientId: %p Attributes: %p\n", ClientId
, ObjectAttributes
);
1459 /* Check if we were called from user mode */
1460 if (PreviousMode
!= KernelMode
)
1462 /* Enter SEH for probing */
1465 /* Probe the thread handle */
1466 ProbeForWriteHandle(ProcessHandle
);
1468 /* Check for a CID structure */
1471 /* Probe and capture it */
1472 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1473 SafeClientId
= *ClientId
;
1474 ClientId
= &SafeClientId
;
1478 * Just probe the object attributes structure, don't capture it
1479 * completely. This is done later if necessary
1481 ProbeForRead(ObjectAttributes
,
1482 sizeof(OBJECT_ATTRIBUTES
),
1484 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1486 /* Validate user attributes */
1487 Attributes
= ObpValidateAttributes(ObjectAttributes
->Attributes
, PreviousMode
);
1489 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1491 /* Return the exception code */
1492 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1498 /* Otherwise just get the data directly */
1499 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1501 /* Still have to sanitize attributes */
1502 Attributes
= ObpValidateAttributes(ObjectAttributes
->Attributes
, PreviousMode
);
1505 /* Can't pass both, fail */
1506 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1508 /* Create an access state */
1509 Status
= SeCreateAccessState(&AccessState
,
1512 &PsProcessType
->TypeInfo
.GenericMapping
);
1513 if (!NT_SUCCESS(Status
)) return Status
;
1515 /* Check if this is a debugger */
1516 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1518 /* Did he want full access? */
1519 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1521 /* Give it to him */
1522 AccessState
.PreviouslyGrantedAccess
|= PROCESS_ALL_ACCESS
;
1526 /* Otherwise just give every other access he could want */
1527 AccessState
.PreviouslyGrantedAccess
|=
1528 AccessState
.RemainingDesiredAccess
;
1531 /* The caller desires nothing else now */
1532 AccessState
.RemainingDesiredAccess
= 0;
1535 /* Open by name if one was given */
1539 Status
= ObOpenObjectByName(ObjectAttributes
,
1547 /* Get rid of the access state */
1548 SeDeleteAccessState(&AccessState
);
1552 /* Open by Thread ID */
1553 if (ClientId
->UniqueThread
)
1555 /* Get the Process */
1556 Status
= PsLookupProcessThreadByCid(ClientId
, &Process
, &Thread
);
1560 /* Get the Process */
1561 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1565 /* Check if we didn't find anything */
1566 if (!NT_SUCCESS(Status
))
1568 /* Get rid of the access state and return */
1569 SeDeleteAccessState(&AccessState
);
1573 /* Open the Process Object */
1574 Status
= ObOpenObjectByPointer(Process
,
1582 /* Delete the access state */
1583 SeDeleteAccessState(&AccessState
);
1585 /* Dereference the thread if we used it */
1586 if (Thread
) ObDereferenceObject(Thread
);
1588 /* Dereference the Process */
1589 ObDereferenceObject(Process
);
1593 /* neither an object name nor a client id was passed */
1594 return STATUS_INVALID_PARAMETER_MIX
;
1597 /* Check for success */
1598 if (NT_SUCCESS(Status
))
1600 /* Use SEH for write back */
1603 /* Write back the handle */
1604 *ProcessHandle
= hProcess
;
1606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1608 /* Get the exception code */
1609 Status
= _SEH2_GetExceptionCode();