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 /* Hacky way of returning the PEB to the user-mode creator */
842 if ((Process
->Peb
) && (CurrentThread
->Tcb
.Teb
))
844 CurrentThread
->Tcb
.Teb
->NtTib
.ArbitraryUserPointer
= Process
->Peb
;
847 /* Save the process handle */
848 *ProcessHandle
= hProcess
;
850 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
852 /* Get the exception code */
853 Status
= _SEH2_GetExceptionCode();
857 /* Run the Notification Routines */
858 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
860 /* If 12 processes have been created, enough of user-mode is ready */
861 if (++ProcessCount
== 12) Ki386PerfEnd();
865 * Dereference the process. For failures, kills the process and does
866 * cleanup present in PspDeleteProcess. For success, kills the extra
867 * reference added by ObInsertObject.
869 ObDereferenceObject(Process
);
872 /* Dereference the parent */
873 if (Parent
) ObDereferenceObject(Parent
);
875 /* Return status to caller */
879 /* PUBLIC FUNCTIONS **********************************************************/
886 PsCreateSystemProcess(OUT PHANDLE ProcessHandle
,
887 IN ACCESS_MASK DesiredAccess
,
888 IN POBJECT_ATTRIBUTES ObjectAttributes
)
890 /* Call the internal API */
891 return PspCreateProcess(ProcessHandle
,
907 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
908 OUT PEPROCESS
*Process
)
910 PHANDLE_TABLE_ENTRY CidEntry
;
911 PEPROCESS FoundProcess
;
912 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
914 PSTRACE(PS_PROCESS_DEBUG
, "ProcessId: %p\n", ProcessId
);
915 KeEnterCriticalRegion();
917 /* Get the CID Handle Entry */
918 CidEntry
= ExMapHandleToPointer(PspCidTable
, ProcessId
);
921 /* Get the Process */
922 FoundProcess
= CidEntry
->Object
;
924 /* Make sure it's really a process */
925 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
927 /* Safe Reference and return it */
928 if (ObReferenceObjectSafe(FoundProcess
))
930 *Process
= FoundProcess
;
931 Status
= STATUS_SUCCESS
;
935 /* Unlock the Entry */
936 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
939 /* Return to caller */
940 KeLeaveCriticalRegion();
949 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
950 OUT PEPROCESS
*Process OPTIONAL
,
951 OUT PETHREAD
*Thread
)
953 PHANDLE_TABLE_ENTRY CidEntry
;
954 PETHREAD FoundThread
;
955 NTSTATUS Status
= STATUS_INVALID_CID
;
957 PSTRACE(PS_PROCESS_DEBUG
, "Cid: %p\n", Cid
);
958 KeEnterCriticalRegion();
960 /* Get the CID Handle Entry */
961 CidEntry
= ExMapHandleToPointer(PspCidTable
, Cid
->UniqueThread
);
964 /* Get the Process */
965 FoundThread
= CidEntry
->Object
;
967 /* Make sure it's really a thread and this process' */
968 if ((FoundThread
->Tcb
.Header
.Type
== ThreadObject
) &&
969 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
971 /* Safe Reference and return it */
972 if (ObReferenceObjectSafe(FoundThread
))
974 *Thread
= FoundThread
;
975 Status
= STATUS_SUCCESS
;
977 /* Check if we should return the Process too */
980 /* Return it and reference it */
981 *Process
= FoundThread
->ThreadsProcess
;
982 ObReferenceObject(*Process
);
987 /* Unlock the Entry */
988 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
991 /* Return to caller */
992 KeLeaveCriticalRegion();
1001 PsGetProcessExitTime(VOID
)
1003 return PsGetCurrentProcess()->ExitTime
;
1011 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
1013 return Process
->CreateTime
.QuadPart
;
1021 PsGetProcessDebugPort(PEPROCESS Process
)
1023 return Process
->DebugPort
;
1031 PsGetProcessExitProcessCalled(PEPROCESS Process
)
1033 return (BOOLEAN
)Process
->ProcessExiting
;
1041 PsGetProcessExitStatus(PEPROCESS Process
)
1043 return Process
->ExitStatus
;
1051 PsGetProcessId(PEPROCESS Process
)
1053 return (HANDLE
)Process
->UniqueProcessId
;
1061 PsGetProcessImageFileName(PEPROCESS Process
)
1063 return (LPSTR
)Process
->ImageFileName
;
1071 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
1073 return Process
->InheritedFromUniqueProcessId
;
1081 PsGetProcessJob(PEPROCESS Process
)
1083 return Process
->Job
;
1091 PsGetProcessPeb(PEPROCESS Process
)
1093 return Process
->Peb
;
1101 PsGetProcessPriorityClass(PEPROCESS Process
)
1103 return Process
->PriorityClass
;
1111 PsGetCurrentProcessId(VOID
)
1113 return (HANDLE
)PsGetCurrentProcess()->UniqueProcessId
;
1121 PsGetCurrentProcessSessionId(VOID
)
1123 return MmGetSessionId(PsGetCurrentProcess());
1131 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
1133 return Process
->SectionBaseAddress
;
1141 PsGetProcessSecurityPort(PEPROCESS Process
)
1143 return Process
->SecurityPort
;
1151 PsGetProcessSessionId(PEPROCESS Process
)
1153 return (HANDLE
)Process
->Session
;
1161 PsGetCurrentProcessWin32Process(VOID
)
1163 return PsGetCurrentProcess()->Win32Process
;
1171 PsGetProcessWin32Process(PEPROCESS Process
)
1173 return Process
->Win32Process
;
1181 PsGetProcessWin32WindowStation(PEPROCESS Process
)
1183 return Process
->Win32WindowStation
;
1191 PsIsProcessBeingDebugged(PEPROCESS Process
)
1193 return Process
->DebugPort
!= NULL
;
1201 PsIsSystemProcess(IN PEPROCESS Process
)
1203 /* Return if this is the System Process */
1204 return Process
== PsInitialSystemProcess
;
1212 PsSetProcessPriorityClass(PEPROCESS Process
,
1213 ULONG PriorityClass
)
1215 Process
->PriorityClass
= (UCHAR
)PriorityClass
;
1223 PsSetProcessSecurityPort(PEPROCESS Process
,
1226 Process
->SecurityPort
= SecurityPort
;
1234 PsSetProcessWin32Process(PEPROCESS Process
,
1237 Process
->Win32Process
= Win32Process
;
1245 PsSetProcessWindowStation(PEPROCESS Process
,
1246 PVOID WindowStation
)
1248 Process
->Win32WindowStation
= WindowStation
;
1256 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
1257 IN PSPROCESSPRIORITYMODE Type
)
1261 PSTRACE(PS_PROCESS_DEBUG
, "Process: %p Type: %lx\n", Process
, Type
);
1263 /* Compute quantum and priority */
1264 Priority
= PspComputeQuantumAndPriority(Process
, Type
, &Quantum
);
1267 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, Priority
, Quantum
);
1275 NtCreateProcessEx(OUT PHANDLE ProcessHandle
,
1276 IN ACCESS_MASK DesiredAccess
,
1277 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1278 IN HANDLE ParentProcess
,
1280 IN HANDLE SectionHandle OPTIONAL
,
1281 IN HANDLE DebugPort OPTIONAL
,
1282 IN HANDLE ExceptionPort OPTIONAL
,
1285 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1288 PSTRACE(PS_PROCESS_DEBUG
,
1289 "ParentProcess: %p Flags: %lx\n", ParentProcess
, Flags
);
1291 /* Check if we came from user mode */
1292 if (PreviousMode
!= KernelMode
)
1296 /* Probe process handle */
1297 ProbeForWriteHandle(ProcessHandle
);
1299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1301 /* Return the exception code */
1302 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1307 /* Make sure there's a parent process */
1310 /* Can't create System Processes like this */
1311 Status
= STATUS_INVALID_PARAMETER
;
1315 /* Create a user Process */
1316 Status
= PspCreateProcess(ProcessHandle
,
1336 NtCreateProcess(OUT PHANDLE ProcessHandle
,
1337 IN ACCESS_MASK DesiredAccess
,
1338 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1339 IN HANDLE ParentProcess
,
1340 IN BOOLEAN InheritObjectTable
,
1341 IN HANDLE SectionHandle OPTIONAL
,
1342 IN HANDLE DebugPort OPTIONAL
,
1343 IN HANDLE ExceptionPort OPTIONAL
)
1346 PSTRACE(PS_PROCESS_DEBUG
,
1347 "Parent: %p Attributes: %p\n", ParentProcess
, ObjectAttributes
);
1349 /* Set new-style flags */
1350 if ((ULONG
)SectionHandle
& 1) Flags
= PS_REQUEST_BREAKAWAY
;
1351 if ((ULONG
)DebugPort
& 1) Flags
|= PS_NO_DEBUG_INHERIT
;
1352 if (InheritObjectTable
) Flags
|= PS_INHERIT_HANDLES
;
1354 /* Call the new API */
1355 return NtCreateProcessEx(ProcessHandle
,
1371 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1372 IN ACCESS_MASK DesiredAccess
,
1373 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1374 IN PCLIENT_ID ClientId
)
1376 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1377 CLIENT_ID SafeClientId
;
1378 ULONG Attributes
= 0;
1380 BOOLEAN HasObjectName
= FALSE
;
1381 PETHREAD Thread
= NULL
;
1382 PEPROCESS Process
= NULL
;
1384 ACCESS_STATE AccessState
;
1385 AUX_ACCESS_DATA AuxData
;
1387 PSTRACE(PS_PROCESS_DEBUG
,
1388 "ClientId: %p Attributes: %p\n", ClientId
, ObjectAttributes
);
1390 /* Check if we were called from user mode */
1391 if (PreviousMode
!= KernelMode
)
1393 /* Enter SEH for probing */
1396 /* Probe the thread handle */
1397 ProbeForWriteHandle(ProcessHandle
);
1399 /* Check for a CID structure */
1402 /* Probe and capture it */
1403 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1404 SafeClientId
= *ClientId
;
1405 ClientId
= &SafeClientId
;
1409 * Just probe the object attributes structure, don't capture it
1410 * completely. This is done later if necessary
1412 ProbeForRead(ObjectAttributes
,
1413 sizeof(OBJECT_ATTRIBUTES
),
1415 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1416 Attributes
= ObjectAttributes
->Attributes
;
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1420 /* Return the exception code */
1421 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1427 /* Otherwise just get the data directly */
1428 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1429 Attributes
= ObjectAttributes
->Attributes
;
1432 /* Can't pass both, fail */
1433 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1435 /* Create an access state */
1436 Status
= SeCreateAccessState(&AccessState
,
1439 &PsProcessType
->TypeInfo
.GenericMapping
);
1440 if (!NT_SUCCESS(Status
)) return Status
;
1442 /* Check if this is a debugger */
1443 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1445 /* Did he want full access? */
1446 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1448 /* Give it to him */
1449 AccessState
.PreviouslyGrantedAccess
|= PROCESS_ALL_ACCESS
;
1453 /* Otherwise just give every other access he could want */
1454 AccessState
.PreviouslyGrantedAccess
|=
1455 AccessState
.RemainingDesiredAccess
;
1458 /* The caller desires nothing else now */
1459 AccessState
.RemainingDesiredAccess
= 0;
1462 /* Open by name if one was given */
1466 Status
= ObOpenObjectByName(ObjectAttributes
,
1474 /* Get rid of the access state */
1475 SeDeleteAccessState(&AccessState
);
1479 /* Open by Thread ID */
1480 if (ClientId
->UniqueThread
)
1482 /* Get the Process */
1483 Status
= PsLookupProcessThreadByCid(ClientId
, &Process
, &Thread
);
1487 /* Get the Process */
1488 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1492 /* Check if we didn't find anything */
1493 if (!NT_SUCCESS(Status
))
1495 /* Get rid of the access state and return */
1496 SeDeleteAccessState(&AccessState
);
1500 /* Open the Process Object */
1501 Status
= ObOpenObjectByPointer(Process
,
1509 /* Delete the access state */
1510 SeDeleteAccessState(&AccessState
);
1512 /* Dereference the thread if we used it */
1513 if (Thread
) ObDereferenceObject(Thread
);
1515 /* Dereference the Process */
1516 ObDereferenceObject(Process
);
1520 /* neither an object name nor a client id was passed */
1521 return STATUS_INVALID_PARAMETER_MIX
;
1524 /* Check for success */
1525 if (NT_SUCCESS(Status
))
1527 /* Use SEH for write back */
1530 /* Write back the handle */
1531 *ProcessHandle
= hProcess
;
1533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1535 /* Get the exception code */
1536 Status
= _SEH2_GetExceptionCode();