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
)
130 PLIST_ENTRY Entry
, ListHead
;
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 /* Set the list head and start looping */
151 ListHead
= &PsActiveProcessHead
;
152 while (ListHead
!= Entry
)
155 FoundProcess
= CONTAINING_RECORD(Entry
, EPROCESS
, ActiveProcessLinks
);
157 /* Reference the process */
158 if (ObReferenceObjectSafe(FoundProcess
)) break;
160 /* Nothing found, keep trying */
162 Entry
= Entry
->Flink
;
165 /* Release the lock */
166 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
168 /* Reference the Process we had referenced earlier */
169 if (OldProcess
) ObDereferenceObject(OldProcess
);
175 PspComputeQuantumAndPriority(IN PEPROCESS Process
,
176 IN PSPROCESSPRIORITYMODE Mode
,
180 UCHAR LocalQuantum
, MemoryPriority
;
182 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Mode: %lx\n", Process
, Mode
);
184 /* Check if this is a foreground process */
185 if (Mode
== PsProcessPriorityForeground
)
187 /* Set the memory priority and use priority separation */
188 MemoryPriority
= MEMORY_PRIORITY_FOREGROUND
;
189 i
= PsPrioritySeparation
;
193 /* Set the background memory priority and no separation */
194 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
198 /* Make sure that the process mode isn't spinning */
199 if (Mode
!= PsProcessPrioritySpinning
)
201 /* Set the priority */
202 MmSetMemoryPriorityProcess(Process
, MemoryPriority
);
205 /* Make sure that the process isn't idle */
206 if (Process
->PriorityClass
!= PROCESS_PRIORITY_CLASS_IDLE
)
208 /* Does the process have a job? */
209 if ((Process
->Job
) && (PspUseJobSchedulingClasses
))
211 /* Use job quantum */
212 LocalQuantum
= PspJobSchedulingClasses
[Process
->Job
->
217 /* Use calculated quantum */
218 LocalQuantum
= PspForegroundQuantum
[i
];
223 /* Process is idle, use default quantum */
227 /* Return quantum to caller */
228 *Quantum
= LocalQuantum
;
230 /* Return priority */
231 return PspPriorityTable
[Process
->PriorityClass
];
236 PsChangeQuantumTable(IN BOOLEAN Immediate
,
237 IN ULONG PrioritySeparation
)
239 PEPROCESS Process
= NULL
;
244 PSTRACE(PS_PROCESS_DEBUG
,
245 "%lx PrioritySeparation: %lx\n", Immediate
, PrioritySeparation
);
247 /* Write the current priority separation */
248 PsPrioritySeparation
= PspPrioritySeparationFromMask(PrioritySeparation
);
250 /* Normalize it if it was too high */
251 if (PsPrioritySeparation
== 3) PsPrioritySeparation
= 2;
253 /* Get the quantum table to use */
254 if (PspQuantumTypeFromMask(PrioritySeparation
) == PSP_VARIABLE_QUANTUMS
)
256 /* Use a variable table */
257 QuantumTable
= PspVariableQuantums
;
261 /* Use fixed table */
262 QuantumTable
= PspFixedQuantums
;
265 /* Now check if we should use long or short */
266 if (PspQuantumLengthFromMask(PrioritySeparation
) == PSP_LONG_QUANTUMS
)
268 /* Use long quantums */
272 /* Check if we're using long fixed quantums */
273 if (QuantumTable
== &PspFixedQuantums
[3])
275 /* Use Job scheduling classes */
276 PspUseJobSchedulingClasses
= TRUE
;
280 /* Otherwise, we don't */
281 PspUseJobSchedulingClasses
= FALSE
;
284 /* Copy the selected table into the Foreground Quantum table */
285 RtlCopyMemory(PspForegroundQuantum
,
287 sizeof(PspForegroundQuantum
));
289 /* Check if we should apply these changes real-time */
292 /* We are...loop every process */
293 Process
= PsGetNextProcess(Process
);
297 * Use the priority separation, unless the process has
298 * low memory priority
300 i
= (Process
->Vm
.Flags
.MemoryPriority
== 1) ?
301 0: PsPrioritySeparation
;
303 /* Make sure that the process isn't idle */
304 if (Process
->PriorityClass
!= PROCESS_PRIORITY_CLASS_IDLE
)
306 /* Does the process have a job? */
307 if ((Process
->Job
) && (PspUseJobSchedulingClasses
))
309 /* Use job quantum */
310 Quantum
= PspJobSchedulingClasses
[Process
->Job
->
315 /* Use calculated quantum */
316 Quantum
= PspForegroundQuantum
[i
];
321 /* Process is idle, use default quantum */
325 /* Now set the quantum */
326 KeSetQuantumProcess(&Process
->Pcb
, Quantum
);
328 /* Get the next process */
329 Process
= PsGetNextProcess(Process
);
336 PspCreateProcess(OUT PHANDLE ProcessHandle
,
337 IN ACCESS_MASK DesiredAccess
,
338 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
339 IN HANDLE ParentProcess OPTIONAL
,
341 IN HANDLE SectionHandle OPTIONAL
,
342 IN HANDLE DebugPort OPTIONAL
,
343 IN HANDLE ExceptionPort OPTIONAL
,
347 PEPROCESS Process
, Parent
;
348 PVOID ExceptionPortObject
;
349 PDEBUG_OBJECT DebugObject
;
350 PSECTION_OBJECT SectionObject
;
351 NTSTATUS Status
, AccessStatus
;
352 ULONG DirectoryTableBase
[2] = {0,0};
354 HANDLE_TABLE_ENTRY CidEntry
;
355 PETHREAD CurrentThread
= PsGetCurrentThread();
356 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
357 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
359 ACCESS_STATE LocalAccessState
;
360 PACCESS_STATE AccessState
= &LocalAccessState
;
361 AUX_ACCESS_DATA AuxData
;
363 BOOLEAN Result
, SdAllocated
;
364 PSECURITY_DESCRIPTOR SecurityDescriptor
;
365 SECURITY_SUBJECT_CONTEXT SubjectContext
;
366 BOOLEAN NeedsPeb
= FALSE
;
367 INITIAL_PEB InitialPeb
;
369 PSTRACE(PS_PROCESS_DEBUG
,
370 "ProcessHandle: %p Parent: %p\n", ProcessHandle
, ParentProcess
);
373 if (Flags
& ~PS_ALL_FLAGS
) return STATUS_INVALID_PARAMETER
;
375 /* Check for parent */
379 Status
= ObReferenceObjectByHandle(ParentProcess
,
380 PROCESS_CREATE_PROCESS
,
385 if (!NT_SUCCESS(Status
)) return Status
;
387 /* If this process should be in a job but the parent isn't */
388 if ((InJob
) && (!Parent
->Job
))
390 /* This is illegal. Dereference the parent and fail */
391 ObDereferenceObject(Parent
);
392 return STATUS_INVALID_PARAMETER
;
395 /* Inherit Parent process's Affinity. */
396 Affinity
= Parent
->Pcb
.Affinity
;
400 /* We have no parent */
402 Affinity
= KeActiveProcessors
;
405 /* Save working set data */
406 MinWs
= PsMinimumWorkingSet
;
407 MaxWs
= PsMaximumWorkingSet
;
409 /* Create the Object */
410 Status
= ObCreateObject(PreviousMode
,
419 if (!NT_SUCCESS(Status
)) goto Cleanup
;
421 /* Clean up the Object */
422 RtlZeroMemory(Process
, sizeof(EPROCESS
));
424 /* Initialize pushlock and rundown protection */
425 ExInitializeRundownProtection(&Process
->RundownProtect
);
426 Process
->ProcessLock
.Value
= 0;
428 /* Setup the Thread List Head */
429 InitializeListHead(&Process
->ThreadListHead
);
431 /* Set up the Quota Block from the Parent */
432 PspInheritQuota(Process
, Parent
);
434 /* Set up Dos Device Map from the Parent */
435 ObInheritDeviceMap(Parent
, Process
);
437 /* Check if we have a parent */
440 /* Inherit PID and Hard Error Processing */
441 Process
->InheritedFromUniqueProcessId
= Parent
->UniqueProcessId
;
442 Process
->DefaultHardErrorProcessing
= Parent
->
443 DefaultHardErrorProcessing
;
447 /* Use default hard error processing */
448 Process
->DefaultHardErrorProcessing
= TRUE
;
451 /* Check for a section handle */
454 /* Get a pointer to it */
455 Status
= ObReferenceObjectByHandle(SectionHandle
,
459 (PVOID
*)&SectionObject
,
461 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
465 /* Assume no section object */
466 SectionObject
= NULL
;
468 /* Is the parent the initial process? */
469 if (Parent
!= PsInitialSystemProcess
)
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
));
672 /* Check if we have a section object and map the system DLL */
673 if (SectionObject
) PspMapSystemDll(Process
, NULL
, FALSE
);
675 /* Create a handle for the Process */
676 CidEntry
.Object
= Process
;
677 CidEntry
.GrantedAccess
= 0;
678 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
679 if (!Process
->UniqueProcessId
)
682 Status
= STATUS_INSUFFICIENT_RESOURCES
;
686 /* Set the handle table PID */
687 Process
->ObjectTable
->UniqueProcessId
= Process
->UniqueProcessId
;
689 /* Check if we need to audit */
690 if (SeDetailedAuditingWithToken(NULL
)) SeAuditProcessCreate(Process
);
692 /* Check if the parent had a job */
693 if ((Parent
) && (Parent
->Job
))
695 /* FIXME: We need to insert this process */
696 DPRINT1("Jobs not yet supported\n");
700 /* Create PEB only for User-Mode Processes */
701 if ((Parent
) && (NeedsPeb
))
704 // Set up the initial PEB
706 RtlZeroMemory(&InitialPeb
, sizeof(INITIAL_PEB
));
707 InitialPeb
.Mutant
= (HANDLE
)-1;
708 InitialPeb
.ImageUsesLargePages
= 0; // FIXME: Not yet supported
711 // Create it only if we have an image section
718 Status
= MmCreatePeb(Process
, &InitialPeb
, &Process
->Peb
);
719 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
724 // We have to clone it
726 ASSERTMSG("No support for cloning yet\n", FALSE
);
731 /* The process can now be activated */
732 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
733 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
734 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
736 /* Create an access state */
737 Status
= SeCreateAccessStateEx(CurrentThread
,
739 (Parent
== PsInitialSystemProcess
)) ?
740 Parent
: CurrentProcess
,
744 &PsProcessType
->TypeInfo
.GenericMapping
);
745 if (!NT_SUCCESS(Status
)) goto CleanupWithRef
;
747 /* Insert the Process into the Object Directory */
748 Status
= ObInsertObject(Process
,
755 /* Free the access state */
756 if (AccessState
) SeDeleteAccessState(AccessState
);
758 /* Cleanup on failure */
759 if (!NT_SUCCESS(Status
)) goto Cleanup
;
761 /* Compute Quantum and Priority */
762 ASSERT(IsListEmpty(&Process
->ThreadListHead
) == TRUE
);
763 Process
->Pcb
.BasePriority
=
764 (SCHAR
)PspComputeQuantumAndPriority(Process
,
765 PsProcessPriorityBackground
,
767 Process
->Pcb
.QuantumReset
= Quantum
;
769 /* Check if we have a parent other then the initial system process */
770 Process
->GrantedAccess
= PROCESS_TERMINATE
;
771 if ((Parent
) && (Parent
!= PsInitialSystemProcess
))
773 /* Get the process's SD */
774 Status
= ObGetObjectSecurity(Process
,
777 if (!NT_SUCCESS(Status
))
779 /* We failed, close the handle and clean up */
780 ObCloseHandle(hProcess
, PreviousMode
);
784 /* Create the subject context */
785 SubjectContext
.ProcessAuditId
= Process
;
786 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
787 SubjectContext
.ClientToken
= NULL
;
789 /* Do the access check */
790 Result
= SeAccessCheck(SecurityDescriptor
,
796 &PsProcessType
->TypeInfo
.GenericMapping
,
798 &Process
->GrantedAccess
,
801 /* Dereference the token and let go the SD */
802 ObFastDereferenceObject(&Process
->Token
,
803 SubjectContext
.PrimaryToken
);
804 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
806 /* Remove access if it failed */
807 if (!Result
) Process
->GrantedAccess
= 0;
809 /* Give the process some basic access */
810 Process
->GrantedAccess
|= (PROCESS_VM_OPERATION
|
813 PROCESS_QUERY_INFORMATION
|
815 PROCESS_CREATE_THREAD
|
817 PROCESS_CREATE_PROCESS
|
818 PROCESS_SET_INFORMATION
|
819 STANDARD_RIGHTS_ALL
|
824 /* Set full granted access */
825 Process
->GrantedAccess
= PROCESS_ALL_ACCESS
;
828 /* Set the Creation Time */
829 KeQuerySystemTime(&Process
->CreateTime
);
831 /* Protect against bad user-mode pointer */
834 /* Save the process handle */
835 *ProcessHandle
= hProcess
;
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
839 /* Get the exception code */
840 Status
= _SEH2_GetExceptionCode();
844 /* Run the Notification Routines */
845 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
847 /* If 12 processes have been created, enough of user-mode is ready */
848 if (++ProcessCount
== 12) Ki386PerfEnd();
852 * Dereference the process. For failures, kills the process and does
853 * cleanup present in PspDeleteProcess. For success, kills the extra
854 * reference added by ObInsertObject.
856 ObDereferenceObject(Process
);
859 /* Dereference the parent */
860 if (Parent
) ObDereferenceObject(Parent
);
862 /* Return status to caller */
866 /* PUBLIC FUNCTIONS **********************************************************/
873 PsCreateSystemProcess(OUT PHANDLE ProcessHandle
,
874 IN ACCESS_MASK DesiredAccess
,
875 IN POBJECT_ATTRIBUTES ObjectAttributes
)
877 /* Call the internal API */
878 return PspCreateProcess(ProcessHandle
,
894 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
895 OUT PEPROCESS
*Process
)
897 PHANDLE_TABLE_ENTRY CidEntry
;
898 PEPROCESS FoundProcess
;
899 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
901 PSTRACE(PS_PROCESS_DEBUG
, "ProcessId: %p\n", ProcessId
);
902 KeEnterCriticalRegion();
904 /* Get the CID Handle Entry */
905 CidEntry
= ExMapHandleToPointer(PspCidTable
, ProcessId
);
908 /* Get the Process */
909 FoundProcess
= CidEntry
->Object
;
911 /* Make sure it's really a process */
912 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
914 /* Safe Reference and return it */
915 if (ObReferenceObjectSafe(FoundProcess
))
917 *Process
= FoundProcess
;
918 Status
= STATUS_SUCCESS
;
922 /* Unlock the Entry */
923 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
926 /* Return to caller */
927 KeLeaveCriticalRegion();
936 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
937 OUT PEPROCESS
*Process OPTIONAL
,
938 OUT PETHREAD
*Thread
)
940 PHANDLE_TABLE_ENTRY CidEntry
;
941 PETHREAD FoundThread
;
942 NTSTATUS Status
= STATUS_INVALID_CID
;
944 PSTRACE(PS_PROCESS_DEBUG
, "Cid: %p\n", Cid
);
945 KeEnterCriticalRegion();
947 /* Get the CID Handle Entry */
948 CidEntry
= ExMapHandleToPointer(PspCidTable
, Cid
->UniqueThread
);
951 /* Get the Process */
952 FoundThread
= CidEntry
->Object
;
954 /* Make sure it's really a thread and this process' */
955 if ((FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
) &&
956 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
958 /* Safe Reference and return it */
959 if (ObReferenceObjectSafe(FoundThread
))
961 *Thread
= FoundThread
;
962 Status
= STATUS_SUCCESS
;
964 /* Check if we should return the Process too */
967 /* Return it and reference it */
968 *Process
= FoundThread
->ThreadsProcess
;
969 ObReferenceObject(*Process
);
974 /* Unlock the Entry */
975 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
978 /* Return to caller */
979 KeLeaveCriticalRegion();
988 PsGetProcessExitTime(VOID
)
990 return PsGetCurrentProcess()->ExitTime
;
998 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
1000 return Process
->CreateTime
.QuadPart
;
1008 PsGetProcessDebugPort(PEPROCESS Process
)
1010 return Process
->DebugPort
;
1018 PsGetProcessExitProcessCalled(PEPROCESS Process
)
1020 return (BOOLEAN
)Process
->ProcessExiting
;
1028 PsGetProcessExitStatus(PEPROCESS Process
)
1030 return Process
->ExitStatus
;
1038 PsGetProcessId(PEPROCESS Process
)
1040 return (HANDLE
)Process
->UniqueProcessId
;
1048 PsGetProcessImageFileName(PEPROCESS Process
)
1050 return (LPSTR
)Process
->ImageFileName
;
1058 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
1060 return Process
->InheritedFromUniqueProcessId
;
1068 PsGetProcessJob(PEPROCESS Process
)
1070 return Process
->Job
;
1078 PsGetProcessPeb(PEPROCESS Process
)
1080 return Process
->Peb
;
1088 PsGetProcessPriorityClass(PEPROCESS Process
)
1090 return Process
->PriorityClass
;
1098 PsGetCurrentProcessId(VOID
)
1100 return (HANDLE
)PsGetCurrentProcess()->UniqueProcessId
;
1108 PsGetCurrentProcessSessionId(VOID
)
1110 return PsGetCurrentProcess()->Session
;
1118 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
1120 return Process
->SectionBaseAddress
;
1128 PsGetProcessSecurityPort(PEPROCESS Process
)
1130 return Process
->SecurityPort
;
1138 PsGetProcessSessionId(PEPROCESS Process
)
1140 return (HANDLE
)Process
->Session
;
1148 PsGetCurrentProcessWin32Process(VOID
)
1150 return PsGetCurrentProcess()->Win32Process
;
1158 PsGetProcessWin32Process(PEPROCESS Process
)
1160 return Process
->Win32Process
;
1168 PsGetProcessWin32WindowStation(PEPROCESS Process
)
1170 return Process
->Win32WindowStation
;
1178 PsIsProcessBeingDebugged(PEPROCESS Process
)
1180 return Process
->DebugPort
!= NULL
;
1188 PsIsSystemProcess(IN PEPROCESS Process
)
1190 /* Return if this is the System Process */
1191 return Process
== PsInitialSystemProcess
;
1199 PsSetProcessPriorityClass(PEPROCESS Process
,
1200 ULONG PriorityClass
)
1202 Process
->PriorityClass
= (UCHAR
)PriorityClass
;
1210 PsSetProcessSecurityPort(PEPROCESS Process
,
1213 Process
->SecurityPort
= SecurityPort
;
1221 PsSetProcessWin32Process(PEPROCESS Process
,
1224 Process
->Win32Process
= Win32Process
;
1232 PsSetProcessWindowStation(PEPROCESS Process
,
1233 PVOID WindowStation
)
1235 Process
->Win32WindowStation
= WindowStation
;
1243 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
1244 IN PSPROCESSPRIORITYMODE Type
)
1248 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Type: %lx\n", Process
, Type
);
1250 /* Compute quantum and priority */
1251 Priority
= PspComputeQuantumAndPriority(Process
, Type
, &Quantum
);
1254 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, Priority
, Quantum
);
1262 NtCreateProcessEx(OUT PHANDLE ProcessHandle
,
1263 IN ACCESS_MASK DesiredAccess
,
1264 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1265 IN HANDLE ParentProcess
,
1267 IN HANDLE SectionHandle OPTIONAL
,
1268 IN HANDLE DebugPort OPTIONAL
,
1269 IN HANDLE ExceptionPort OPTIONAL
,
1272 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1275 PSTRACE(PS_PROCESS_DEBUG
,
1276 "ParentProcess: %p Flags: %lx\n", ParentProcess
, Flags
);
1278 /* Check if we came from user mode */
1279 if (PreviousMode
!= KernelMode
)
1283 /* Probe process handle */
1284 ProbeForWriteHandle(ProcessHandle
);
1286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1288 /* Return the exception code */
1289 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1294 /* Make sure there's a parent process */
1297 /* Can't create System Processes like this */
1298 Status
= STATUS_INVALID_PARAMETER
;
1302 /* Create a user Process */
1303 Status
= PspCreateProcess(ProcessHandle
,
1323 NtCreateProcess(OUT PHANDLE ProcessHandle
,
1324 IN ACCESS_MASK DesiredAccess
,
1325 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1326 IN HANDLE ParentProcess
,
1327 IN BOOLEAN InheritObjectTable
,
1328 IN HANDLE SectionHandle OPTIONAL
,
1329 IN HANDLE DebugPort OPTIONAL
,
1330 IN HANDLE ExceptionPort OPTIONAL
)
1333 PSTRACE(PS_PROCESS_DEBUG
,
1334 "Parent: %p Attributes: %p\n", ParentProcess
, ObjectAttributes
);
1336 /* Set new-style flags */
1337 if ((ULONG
)SectionHandle
& 1) Flags
= PS_REQUEST_BREAKAWAY
;
1338 if ((ULONG
)DebugPort
& 1) Flags
|= PS_NO_DEBUG_INHERIT
;
1339 if (InheritObjectTable
) Flags
|= PS_INHERIT_HANDLES
;
1341 /* Call the new API */
1342 return NtCreateProcessEx(ProcessHandle
,
1358 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1359 IN ACCESS_MASK DesiredAccess
,
1360 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1361 IN PCLIENT_ID ClientId
)
1363 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1364 CLIENT_ID SafeClientId
;
1365 ULONG Attributes
= 0;
1367 BOOLEAN HasObjectName
= FALSE
;
1368 PETHREAD Thread
= NULL
;
1369 PEPROCESS Process
= NULL
;
1371 ACCESS_STATE AccessState
;
1372 AUX_ACCESS_DATA AuxData
;
1374 PSTRACE(PS_PROCESS_DEBUG
,
1375 "ClientId: %p Attributes: %p\n", ClientId
, ObjectAttributes
);
1377 /* Check if we were called from user mode */
1378 if (PreviousMode
!= KernelMode
)
1380 /* Enter SEH for probing */
1383 /* Probe the thread handle */
1384 ProbeForWriteHandle(ProcessHandle
);
1386 /* Check for a CID structure */
1389 /* Probe and capture it */
1390 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1391 SafeClientId
= *ClientId
;
1392 ClientId
= &SafeClientId
;
1396 * Just probe the object attributes structure, don't capture it
1397 * completely. This is done later if necessary
1399 ProbeForRead(ObjectAttributes
,
1400 sizeof(OBJECT_ATTRIBUTES
),
1402 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1403 Attributes
= ObjectAttributes
->Attributes
;
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1407 /* Return the exception code */
1408 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1414 /* Otherwise just get the data directly */
1415 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1416 Attributes
= ObjectAttributes
->Attributes
;
1419 /* Can't pass both, fail */
1420 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1422 /* Create an access state */
1423 Status
= SeCreateAccessState(&AccessState
,
1426 &PsProcessType
->TypeInfo
.GenericMapping
);
1427 if (!NT_SUCCESS(Status
)) return Status
;
1429 /* Check if this is a debugger */
1430 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1432 /* Did he want full access? */
1433 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1435 /* Give it to him */
1436 AccessState
.PreviouslyGrantedAccess
|= PROCESS_ALL_ACCESS
;
1440 /* Otherwise just give every other access he could want */
1441 AccessState
.PreviouslyGrantedAccess
|=
1442 AccessState
.RemainingDesiredAccess
;
1445 /* The caller desires nothing else now */
1446 AccessState
.RemainingDesiredAccess
= 0;
1449 /* Open by name if one was given */
1453 Status
= ObOpenObjectByName(ObjectAttributes
,
1461 /* Get rid of the access state */
1462 SeDeleteAccessState(&AccessState
);
1466 /* Open by Thread ID */
1467 if (ClientId
->UniqueThread
)
1469 /* Get the Process */
1470 Status
= PsLookupProcessThreadByCid(ClientId
, &Process
, &Thread
);
1474 /* Get the Process */
1475 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1479 /* Check if we didn't find anything */
1480 if (!NT_SUCCESS(Status
))
1482 /* Get rid of the access state and return */
1483 SeDeleteAccessState(&AccessState
);
1487 /* Open the Process Object */
1488 Status
= ObOpenObjectByPointer(Process
,
1496 /* Delete the access state */
1497 SeDeleteAccessState(&AccessState
);
1499 /* Dereference the thread if we used it */
1500 if (Thread
) ObDereferenceObject(Thread
);
1502 /* Dereference the Process */
1503 ObDereferenceObject(Process
);
1507 /* neither an object name nor a client id was passed */
1508 return STATUS_INVALID_PARAMETER_MIX
;
1511 /* Check for success */
1512 if (NT_SUCCESS(Status
))
1514 /* Use SEH for write back */
1517 /* Write back the handle */
1518 *ProcessHandle
= hProcess
;
1520 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1522 /* Get the exception code */
1523 Status
= _SEH2_GetExceptionCode();