Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/process.c * PURPOSE: Process Manager: Process Management * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Thomas Weidenmueller (w3seek@reactos.org */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* GLOBALS *******************************************************************/
extern ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
POBJECT_TYPE PsProcessType = NULL;
LIST_ENTRY PsActiveProcessHead;KGUARDED_MUTEX PspActiveProcessMutex;
LARGE_INTEGER ShortPsLockDelay;
ULONG PsRawPrioritySeparation;ULONG PsPrioritySeparation;CHAR PspForegroundQuantum[3];
/* Fixed quantum table */CHAR PspFixedQuantums[6] ={ /* Short quantums */ 3 * 6, /* Level 1 */ 3 * 6, /* Level 2 */ 3 * 6, /* Level 3 */
/* Long quantums */ 6 * 6, /* Level 1 */ 6 * 6, /* Level 2 */ 6 * 6 /* Level 3 */};
/* Variable quantum table */CHAR PspVariableQuantums[6] ={ /* Short quantums */ 1 * 6, /* Level 1 */ 2 * 6, /* Level 2 */ 3 * 6, /* Level 3 */
/* Long quantums */ 2 * 6, /* Level 1 */ 4 * 6, /* Level 2 */ 6 * 6 /* Level 3 */};
/* Priority table */KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1] ={ 8, 4, 8, 13, 24, 6, 10};
/* PRIVATE FUNCTIONS *********************************************************/
PETHREADNTAPIPsGetNextProcessThread(IN PEPROCESS Process, IN PETHREAD Thread OPTIONAL){ PETHREAD FoundThread = NULL; PLIST_ENTRY ListHead, Entry; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "Process: %p Thread: %p\n", Process, Thread);
/* Lock the process */ KeEnterCriticalRegion(); ExAcquirePushLockShared(&Process->ProcessLock);
/* Check if we're already starting somewhere */ if (Thread) { /* Start where we left off */ Entry = Thread->ThreadListEntry.Flink; } else { /* Start at the beginning */ Entry = Process->ThreadListHead.Flink; }
/* Set the list head and start looping */ ListHead = &Process->ThreadListHead; while (ListHead != Entry) { /* Get the Thread */ FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
/* Safe reference the thread */ if (ObReferenceObjectSafe(FoundThread)) break;
/* Nothing found, keep looping */ FoundThread = NULL; Entry = Entry->Flink; }
/* Unlock the process */ ExReleasePushLockShared(&Process->ProcessLock); KeLeaveCriticalRegion();
/* Check if we had a starting thread, and dereference it */ if (Thread) ObDereferenceObject(Thread);
/* Return what we found */ return FoundThread;}
PEPROCESSNTAPIPsGetNextProcess(IN PEPROCESS OldProcess){ PLIST_ENTRY Entry; PEPROCESS FoundProcess = NULL; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "Process: %p\n", OldProcess);
/* Acquire the Active Process Lock */ KeAcquireGuardedMutex(&PspActiveProcessMutex);
/* Check if we're already starting somewhere */ if (OldProcess) { /* Start where we left off */ Entry = OldProcess->ActiveProcessLinks.Flink; } else { /* Start at the beginning */ Entry = PsActiveProcessHead.Flink; }
/* Loop the process list */ while (Entry != &PsActiveProcessHead) { /* Get the process */ FoundProcess = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
/* Reference the process */ if (ObReferenceObjectSafe(FoundProcess)) break;
/* Nothing found, keep trying */ FoundProcess = NULL; Entry = Entry->Flink; }
/* Release the lock */ KeReleaseGuardedMutex(&PspActiveProcessMutex);
/* Dereference the Process we had referenced earlier */ if (OldProcess) ObDereferenceObject(OldProcess); return FoundProcess;}
KPRIORITYNTAPIPspComputeQuantumAndPriority(IN PEPROCESS Process, IN PSPROCESSPRIORITYMODE Mode, OUT PUCHAR Quantum){ ULONG i; UCHAR LocalQuantum, MemoryPriority; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "Process: %p Mode: %lx\n", Process, Mode);
/* Check if this is a foreground process */ if (Mode == PsProcessPriorityForeground) { /* Set the memory priority and use priority separation */ MemoryPriority = MEMORY_PRIORITY_FOREGROUND; i = PsPrioritySeparation; } else { /* Set the background memory priority and no separation */ MemoryPriority = MEMORY_PRIORITY_BACKGROUND; i = 0; }
/* Make sure that the process mode isn't spinning */ if (Mode != PsProcessPrioritySpinning) { /* Set the priority */ MmSetMemoryPriorityProcess(Process, MemoryPriority); }
/* Make sure that the process isn't idle */ if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE) { /* Does the process have a job? */ if ((Process->Job) && (PspUseJobSchedulingClasses)) { /* Use job quantum */ LocalQuantum = PspJobSchedulingClasses[Process->Job-> SchedulingClass]; } else { /* Use calculated quantum */ LocalQuantum = PspForegroundQuantum[i]; } } else { /* Process is idle, use default quantum */ LocalQuantum = 6; }
/* Return quantum to caller */ *Quantum = LocalQuantum;
/* Return priority */ return PspPriorityTable[Process->PriorityClass];}
VOIDNTAPIPsChangeQuantumTable(IN BOOLEAN Immediate, IN ULONG PrioritySeparation){ PEPROCESS Process = NULL; ULONG i; UCHAR Quantum; PCHAR QuantumTable; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "%lx PrioritySeparation: %lx\n", Immediate, PrioritySeparation);
/* Write the current priority separation */ PsPrioritySeparation = PspPrioritySeparationFromMask(PrioritySeparation);
/* Normalize it if it was too high */ if (PsPrioritySeparation == 3) PsPrioritySeparation = 2;
/* Get the quantum table to use */ if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_VARIABLE_QUANTUMS) { /* Use a variable table */ QuantumTable = PspVariableQuantums; } else if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_FIXED_QUANTUMS) { /* Use fixed table */ QuantumTable = PspFixedQuantums; } else { /* Use default for the type of system we're on */ QuantumTable = MmIsThisAnNtAsSystem() ? PspFixedQuantums : PspVariableQuantums; }
/* Now check if we should use long or short */ if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_LONG_QUANTUMS) { /* Use long quantums */ QuantumTable += 3; } else if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_SHORT_QUANTUMS) { /* Keep existing table */ NOTHING; } else { /* Use default for the type of system we're on */ QuantumTable += MmIsThisAnNtAsSystem() ? 3 : 0; }
/* Check if we're using long fixed quantums */ if (QuantumTable == &PspFixedQuantums[3]) { /* Use Job scheduling classes */ PspUseJobSchedulingClasses = TRUE; } else { /* Otherwise, we don't */ PspUseJobSchedulingClasses = FALSE; }
/* Copy the selected table into the Foreground Quantum table */ RtlCopyMemory(PspForegroundQuantum, QuantumTable, sizeof(PspForegroundQuantum));
/* Check if we should apply these changes real-time */ if (Immediate) { /* We are...loop every process */ Process = PsGetNextProcess(Process); while (Process) { /* Use the priority separation if this is a foreground process */ i = (Process->Vm.Flags.MemoryPriority == MEMORY_PRIORITY_BACKGROUND) ? 0: PsPrioritySeparation;
/* Make sure that the process isn't idle */ if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE) { /* Does the process have a job? */ if ((Process->Job) && (PspUseJobSchedulingClasses)) { /* Use job quantum */ Quantum = PspJobSchedulingClasses[Process->Job->SchedulingClass]; } else { /* Use calculated quantum */ Quantum = PspForegroundQuantum[i]; } } else { /* Process is idle, use default quantum */ Quantum = 6; }
/* Now set the quantum */ KeSetQuantumProcess(&Process->Pcb, Quantum);
/* Get the next process */ Process = PsGetNextProcess(Process); } }}
NTSTATUSNTAPIPspCreateProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ParentProcess OPTIONAL, IN ULONG Flags, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL, IN BOOLEAN InJob){ HANDLE hProcess; PEPROCESS Process, Parent; PVOID ExceptionPortObject; PDEBUG_OBJECT DebugObject; PSECTION SectionObject; NTSTATUS Status, AccessStatus; ULONG_PTR DirectoryTableBase[2] = {0,0}; KAFFINITY Affinity; HANDLE_TABLE_ENTRY CidEntry; PETHREAD CurrentThread = PsGetCurrentThread(); KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PEPROCESS CurrentProcess = PsGetCurrentProcess(); ULONG MinWs, MaxWs; ACCESS_STATE LocalAccessState; PACCESS_STATE AccessState = &LocalAccessState; AUX_ACCESS_DATA AuxData; UCHAR Quantum; BOOLEAN Result, SdAllocated; PSECURITY_DESCRIPTOR SecurityDescriptor; SECURITY_SUBJECT_CONTEXT SubjectContext; BOOLEAN NeedsPeb = FALSE; INITIAL_PEB InitialPeb; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "ProcessHandle: %p Parent: %p\n", ProcessHandle, ParentProcess);
/* Validate flags */ if (Flags & ~PROCESS_CREATE_FLAGS_LEGAL_MASK) return STATUS_INVALID_PARAMETER;
/* Check for parent */ if (ParentProcess) { /* Reference it */ Status = ObReferenceObjectByHandle(ParentProcess, PROCESS_CREATE_PROCESS, PsProcessType, PreviousMode, (PVOID*)&Parent, NULL); if (!NT_SUCCESS(Status)) return Status;
/* If this process should be in a job but the parent isn't */ if ((InJob) && (!Parent->Job)) { /* This is illegal. Dereference the parent and fail */ ObDereferenceObject(Parent); return STATUS_INVALID_PARAMETER; }
/* Inherit Parent process's Affinity. */ Affinity = Parent->Pcb.Affinity; } else { /* We have no parent */ Parent = NULL; Affinity = KeActiveProcessors; }
/* Save working set data */ MinWs = PsMinimumWorkingSet; MaxWs = PsMaximumWorkingSet;
/* Create the Object */ Status = ObCreateObject(PreviousMode, PsProcessType, ObjectAttributes, PreviousMode, NULL, sizeof(EPROCESS), 0, 0, (PVOID*)&Process); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Clean up the Object */ RtlZeroMemory(Process, sizeof(EPROCESS));
/* Initialize pushlock and rundown protection */ ExInitializeRundownProtection(&Process->RundownProtect); Process->ProcessLock.Value = 0;
/* Setup the Thread List Head */ InitializeListHead(&Process->ThreadListHead);
/* Set up the Quota Block from the Parent */ PspInheritQuota(Process, Parent);
/* Set up Dos Device Map from the Parent */ ObInheritDeviceMap(Parent, Process);
/* Check if we have a parent */ if (Parent) { /* Inherit PID and hard-error processing */ Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId; Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing; } else { /* Use default hard-error processing */ Process->DefaultHardErrorProcessing = SEM_FAILCRITICALERRORS; }
/* Check for a section handle */ if (SectionHandle) { /* Get a pointer to it */ Status = ObReferenceObjectByHandle(SectionHandle, SECTION_MAP_EXECUTE, MmSectionObjectType, PreviousMode, (PVOID*)&SectionObject, NULL); if (!NT_SUCCESS(Status)) goto CleanupWithRef; } else { /* Assume no section object */ SectionObject = NULL;
/* Is the parent the initial process? * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */ if (Parent != PsInitialSystemProcess && (Parent != NULL)) { /* It's not, so acquire the process rundown */ if (ExAcquireRundownProtection(&Parent->RundownProtect)) { /* If the parent has a section, use it */ SectionObject = Parent->SectionObject; if (SectionObject) ObReferenceObject(SectionObject);
/* Release process rundown */ ExReleaseRundownProtection(&Parent->RundownProtect); }
/* If we don't have a section object */ if (!SectionObject) { /* Then the process is in termination, so fail */ Status = STATUS_PROCESS_IS_TERMINATING; goto CleanupWithRef; } } }
/* Save the pointer to the section object */ Process->SectionObject = SectionObject;
/* Check for the debug port */ if (DebugPort) { /* Reference it */ Status = ObReferenceObjectByHandle(DebugPort, DEBUG_OBJECT_ADD_REMOVE_PROCESS, DbgkDebugObjectType, PreviousMode, (PVOID*)&DebugObject, NULL); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
/* Save the debug object */ Process->DebugPort = DebugObject;
/* Check if the caller doesn't want the debug stuff inherited */ if (Flags & PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT) { /* Set the process flag */ InterlockedOr((PLONG)&Process->Flags, PSF_NO_DEBUG_INHERIT_BIT); } } else { /* Do we have a parent? Copy his debug port */ if (Parent) DbgkCopyProcessDebugPort(Process, Parent); }
/* Now check for an exception port */ if (ExceptionPort) { /* Reference it */ Status = ObReferenceObjectByHandle(ExceptionPort, PORT_ALL_ACCESS, LpcPortObjectType, PreviousMode, (PVOID*)&ExceptionPortObject, NULL); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
/* Save the exception port */ Process->ExceptionPort = ExceptionPortObject; }
/* Save the pointer to the section object */ Process->SectionObject = SectionObject;
/* Set default exit code */ Process->ExitStatus = STATUS_PENDING;
/* Check if this is the initial process being built */ if (Parent) { /* Create the address space for the child */ if (!MmCreateProcessAddressSpace(MinWs, Process, DirectoryTableBase)) { /* Failed */ Status = STATUS_INSUFFICIENT_RESOURCES; goto CleanupWithRef; } } else { /* Otherwise, we are the boot process, we're already semi-initialized */ Process->ObjectTable = CurrentProcess->ObjectTable; Status = MmInitializeHandBuiltProcess(Process, DirectoryTableBase); if (!NT_SUCCESS(Status)) goto CleanupWithRef; }
/* We now have an address space */ InterlockedOr((PLONG)&Process->Flags, PSF_HAS_ADDRESS_SPACE_BIT);
/* Set the maximum WS */ Process->Vm.MaximumWorkingSetSize = MaxWs;
/* Now initialize the Kernel Process */ KeInitializeProcess(&Process->Pcb, PROCESS_PRIORITY_NORMAL, Affinity, DirectoryTableBase, BooleanFlagOn(Process->DefaultHardErrorProcessing, SEM_NOALIGNMENTFAULTEXCEPT));
/* Duplicate Parent Token */ Status = PspInitializeProcessSecurity(Process, Parent); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
/* Set default priority class */ Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
/* Check if we have a parent */ if (Parent) { /* Check our priority class */ if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE || Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL) { /* Normalize it */ Process->PriorityClass = Parent->PriorityClass; }
/* Initialize object manager for the process */ Status = ObInitProcess(Flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES ? Parent : NULL, Process); if (!NT_SUCCESS(Status)) goto CleanupWithRef; } else { /* Do the second part of the boot process memory setup */ Status = MmInitializeHandBuiltProcess2(Process); if (!NT_SUCCESS(Status)) goto CleanupWithRef; }
/* Set success for now */ Status = STATUS_SUCCESS;
/* Check if this is a real user-mode process */ if (SectionHandle) { /* Initialize the address space */ Status = MmInitializeProcessAddressSpace(Process, NULL, SectionObject, &Flags, &Process-> SeAuditProcessCreationInfo. ImageFileName); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
// // We need a PEB // NeedsPeb = TRUE; } else if (Parent) { /* Check if this is a child of the system process */ if (Parent != PsInitialSystemProcess) { // // We need a PEB // NeedsPeb = TRUE;
/* This is a clone! */ ASSERTMSG("No support for cloning yet\n", FALSE); } else { /* This is the initial system process */ Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES; Status = MmInitializeProcessAddressSpace(Process, NULL, NULL, &Flags, NULL); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
/* Create a dummy image file name */ Process->SeAuditProcessCreationInfo.ImageFileName = ExAllocatePoolWithTag(PagedPool, sizeof(OBJECT_NAME_INFORMATION), TAG_SEPA); if (!Process->SeAuditProcessCreationInfo.ImageFileName) { /* Fail */ Status = STATUS_INSUFFICIENT_RESOURCES; goto CleanupWithRef; }
/* Zero it out */ RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName, sizeof(OBJECT_NAME_INFORMATION)); } }
#if MI_TRACE_PFNS /* Copy the process name now that we have it */ memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16); if (Process->Pcb.DirectoryTableBase[1]) memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16); if (Process->WorkingSetPage) memcpy(MiGetPfnEntry(Process->WorkingSetPage)->ProcessName, Process->ImageFileName, 16);#endif
/* Check if we have a section object and map the system DLL */ if (SectionObject) PspMapSystemDll(Process, NULL, FALSE);
/* Create a handle for the Process */ CidEntry.Object = Process; CidEntry.GrantedAccess = 0; Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry); if (!Process->UniqueProcessId) { /* Fail */ Status = STATUS_INSUFFICIENT_RESOURCES; goto CleanupWithRef; }
/* Set the handle table PID */ Process->ObjectTable->UniqueProcessId = Process->UniqueProcessId;
/* Check if we need to audit */ if (SeDetailedAuditingWithToken(NULL)) SeAuditProcessCreate(Process);
/* Check if the parent had a job */ if ((Parent) && (Parent->Job)) { /* FIXME: We need to insert this process */ DPRINT1("Jobs not yet supported\n"); }
/* Create PEB only for User-Mode Processes */ if ((Parent) && (NeedsPeb)) { // // Set up the initial PEB // RtlZeroMemory(&InitialPeb, sizeof(INITIAL_PEB)); InitialPeb.Mutant = (HANDLE)-1; InitialPeb.ImageUsesLargePages = 0; // FIXME: Not yet supported
// // Create it only if we have an image section // if (SectionHandle) { // // Create it // Status = MmCreatePeb(Process, &InitialPeb, &Process->Peb); if (!NT_SUCCESS(Status)) goto CleanupWithRef; } else { // // We have to clone it // ASSERTMSG("No support for cloning yet\n", FALSE); }
}
/* The process can now be activated */ KeAcquireGuardedMutex(&PspActiveProcessMutex); InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks); KeReleaseGuardedMutex(&PspActiveProcessMutex);
/* Create an access state */ Status = SeCreateAccessStateEx(CurrentThread, ((Parent) && (Parent == PsInitialSystemProcess)) ? Parent : CurrentProcess, &LocalAccessState, &AuxData, DesiredAccess, &PsProcessType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) goto CleanupWithRef;
/* Insert the Process into the Object Directory */ Status = ObInsertObject(Process, AccessState, DesiredAccess, 1, NULL, &hProcess);
/* Free the access state */ if (AccessState) SeDeleteAccessState(AccessState);
/* Cleanup on failure */ if (!NT_SUCCESS(Status)) goto Cleanup;
/* Compute Quantum and Priority */ ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE); Process->Pcb.BasePriority = (SCHAR)PspComputeQuantumAndPriority(Process, PsProcessPriorityBackground, &Quantum); Process->Pcb.QuantumReset = Quantum;
/* Check if we have a parent other then the initial system process */ Process->GrantedAccess = PROCESS_TERMINATE; if ((Parent) && (Parent != PsInitialSystemProcess)) { /* Get the process's SD */ Status = ObGetObjectSecurity(Process, &SecurityDescriptor, &SdAllocated); if (!NT_SUCCESS(Status)) { /* We failed, close the handle and clean up */ ObCloseHandle(hProcess, PreviousMode); goto CleanupWithRef; }
/* Create the subject context */ SubjectContext.ProcessAuditId = Process; SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); SubjectContext.ClientToken = NULL;
/* Do the access check */ Result = SeAccessCheck(SecurityDescriptor, &SubjectContext, FALSE, MAXIMUM_ALLOWED, 0, NULL, &PsProcessType->TypeInfo.GenericMapping, PreviousMode, &Process->GrantedAccess, &AccessStatus);
/* Dereference the token and let go the SD */ ObFastDereferenceObject(&Process->Token, SubjectContext.PrimaryToken); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
/* Remove access if it failed */ if (!Result) Process->GrantedAccess = 0;
/* Give the process some basic access */ Process->GrantedAccess |= (PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_INFORMATION | STANDARD_RIGHTS_ALL | PROCESS_SET_QUOTA); } else { /* Set full granted access */ Process->GrantedAccess = PROCESS_ALL_ACCESS; }
/* Set the Creation Time */ KeQuerySystemTime(&Process->CreateTime);
/* Protect against bad user-mode pointer */ _SEH2_TRY { /* Hacky way of returning the PEB to the user-mode creator */ if ((Process->Peb) && (CurrentThread->Tcb.Teb)) { CurrentThread->Tcb.Teb->NtTib.ArbitraryUserPointer = Process->Peb; }
/* Save the process handle */ *ProcessHandle = hProcess; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* Run the Notification Routines */ PspRunCreateProcessNotifyRoutines(Process, TRUE);
/* If 12 processes have been created, enough of user-mode is ready */ if (++ProcessCount == 12) Ki386PerfEnd();
CleanupWithRef: /* * Dereference the process. For failures, kills the process and does * cleanup present in PspDeleteProcess. For success, kills the extra * reference added by ObInsertObject. */ ObDereferenceObject(Process);
Cleanup: /* Dereference the parent */ if (Parent) ObDereferenceObject(Parent);
/* Return status to caller */ return Status;}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPIPsCreateSystemProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes){ /* Call the internal API */ return PspCreateProcess(ProcessHandle, DesiredAccess, ObjectAttributes, NULL, 0, NULL, NULL, NULL, FALSE);}
/* * @implemented */NTSTATUSNTAPIPsLookupProcessByProcessId(IN HANDLE ProcessId, OUT PEPROCESS *Process){ PHANDLE_TABLE_ENTRY CidEntry; PEPROCESS FoundProcess; NTSTATUS Status = STATUS_INVALID_PARAMETER; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId); KeEnterCriticalRegion();
/* Get the CID Handle Entry */ CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId); if (CidEntry) { /* Get the Process */ FoundProcess = CidEntry->Object;
/* Make sure it's really a process */ if (FoundProcess->Pcb.Header.Type == ProcessObject) { /* Safe Reference and return it */ if (ObReferenceObjectSafe(FoundProcess)) { *Process = FoundProcess; Status = STATUS_SUCCESS; } }
/* Unlock the Entry */ ExUnlockHandleTableEntry(PspCidTable, CidEntry); }
/* Return to caller */ KeLeaveCriticalRegion(); return Status;}
/* * @implemented */NTSTATUSNTAPIPsLookupProcessThreadByCid(IN PCLIENT_ID Cid, OUT PEPROCESS *Process OPTIONAL, OUT PETHREAD *Thread){ PHANDLE_TABLE_ENTRY CidEntry; PETHREAD FoundThread; NTSTATUS Status = STATUS_INVALID_CID; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "Cid: %p\n", Cid); KeEnterCriticalRegion();
/* Get the CID Handle Entry */ CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread); if (CidEntry) { /* Get the Process */ FoundThread = CidEntry->Object;
/* Make sure it's really a thread and this process' */ if ((FoundThread->Tcb.Header.Type == ThreadObject) && (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess)) { /* Safe Reference and return it */ if (ObReferenceObjectSafe(FoundThread)) { *Thread = FoundThread; Status = STATUS_SUCCESS;
/* Check if we should return the Process too */ if (Process) { /* Return it and reference it */ *Process = FoundThread->ThreadsProcess; ObReferenceObject(*Process); } } }
/* Unlock the Entry */ ExUnlockHandleTableEntry(PspCidTable, CidEntry); }
/* Return to caller */ KeLeaveCriticalRegion(); return Status;}
/* * @implemented */LARGE_INTEGERNTAPIPsGetProcessExitTime(VOID){ return PsGetCurrentProcess()->ExitTime;}
/* * @implemented */LONGLONGNTAPIPsGetProcessCreateTimeQuadPart(PEPROCESS Process){ return Process->CreateTime.QuadPart;}
/* * @implemented */PVOIDNTAPIPsGetProcessDebugPort(PEPROCESS Process){ return Process->DebugPort;}
/* * @implemented */BOOLEANNTAPIPsGetProcessExitProcessCalled(PEPROCESS Process){ return (BOOLEAN)Process->ProcessExiting;}
/* * @implemented */NTSTATUSNTAPIPsGetProcessExitStatus(PEPROCESS Process){ return Process->ExitStatus;}
/* * @implemented */HANDLENTAPIPsGetProcessId(PEPROCESS Process){ return (HANDLE)Process->UniqueProcessId;}
/* * @implemented */LPSTRNTAPIPsGetProcessImageFileName(PEPROCESS Process){ return (LPSTR)Process->ImageFileName;}
/* * @implemented */HANDLENTAPIPsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process){ return Process->InheritedFromUniqueProcessId;}
/* * @implemented */PEJOBNTAPIPsGetProcessJob(PEPROCESS Process){ return Process->Job;}
/* * @implemented */PPEBNTAPIPsGetProcessPeb(PEPROCESS Process){ return Process->Peb;}
/* * @implemented */ULONGNTAPIPsGetProcessPriorityClass(PEPROCESS Process){ return Process->PriorityClass;}
/* * @implemented */HANDLENTAPIPsGetCurrentProcessId(VOID){ return (HANDLE)PsGetCurrentProcess()->UniqueProcessId;}
/* * @implemented */ULONGNTAPIPsGetCurrentProcessSessionId(VOID){ return MmGetSessionId(PsGetCurrentProcess());}
/* * @implemented */PVOIDNTAPIPsGetProcessSectionBaseAddress(PEPROCESS Process){ return Process->SectionBaseAddress;}
/* * @implemented */PVOIDNTAPIPsGetProcessSecurityPort(PEPROCESS Process){ return Process->SecurityPort;}
/* * @implemented */ULONGNTAPIPsGetProcessSessionId(IN PEPROCESS Process){ return MmGetSessionId(Process);}
/* * @implemented */ULONGNTAPIPsGetProcessSessionIdEx(IN PEPROCESS Process){ return MmGetSessionIdEx(Process);}
/* * @implemented */PVOIDNTAPIPsGetCurrentProcessWin32Process(VOID){ return PsGetCurrentProcess()->Win32Process;}
/* * @implemented */PVOIDNTAPIPsGetProcessWin32Process(PEPROCESS Process){ return Process->Win32Process;}
/* * @implemented */PVOIDNTAPIPsGetProcessWin32WindowStation(PEPROCESS Process){ return Process->Win32WindowStation;}
/* * @implemented */BOOLEANNTAPIPsIsProcessBeingDebugged(PEPROCESS Process){ return Process->DebugPort != NULL;}
/* * @implemented */BOOLEANNTAPIPsIsSystemProcess(IN PEPROCESS Process){ /* Return if this is the System Process */ return Process == PsInitialSystemProcess;}
/* * @implemented */VOIDNTAPIPsSetProcessPriorityClass(PEPROCESS Process, ULONG PriorityClass){ Process->PriorityClass = (UCHAR)PriorityClass;}
/* * @implemented */NTSTATUSNTAPIPsSetProcessSecurityPort(PEPROCESS Process, PVOID SecurityPort){ Process->SecurityPort = SecurityPort; return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIPsSetProcessWin32Process( _Inout_ PEPROCESS Process, _In_opt_ PVOID Win32Process, _In_opt_ PVOID OldWin32Process){ NTSTATUS Status;
/* Assume success */ Status = STATUS_SUCCESS;
/* Lock the process */ KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&Process->ProcessLock);
/* Check if we set a new win32 process */ if (Win32Process != NULL) { /* Check if the process is in the right state */ if (((Process->Flags & PSF_PROCESS_DELETE_BIT) == 0) && (Process->Win32Process == NULL)) { /* Set the new win32 process */ Process->Win32Process = Win32Process; } else { /* Otherwise fail */ Status = STATUS_PROCESS_IS_TERMINATING; } } else { /* Reset the win32 process, did the caller specify the correct old value? */ if (Process->Win32Process == OldWin32Process) { /* Yes, so reset the win32 process to NULL */ Process->Win32Process = NULL; } else { /* Otherwise fail */ Status = STATUS_UNSUCCESSFUL; } }
/* Unlock the process */ ExReleasePushLockExclusive(&Process->ProcessLock); KeLeaveCriticalRegion();
return Status;}
/* * @implemented */VOIDNTAPIPsSetProcessWindowStation(PEPROCESS Process, PVOID WindowStation){ Process->Win32WindowStation = WindowStation;}
/* * @implemented */VOIDNTAPIPsSetProcessPriorityByClass(IN PEPROCESS Process, IN PSPROCESSPRIORITYMODE Type){ UCHAR Quantum; ULONG Priority; PSTRACE(PS_PROCESS_DEBUG, "Process: %p Type: %lx\n", Process, Type);
/* Compute quantum and priority */ Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
/* Set them */ KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);}
/* * @implemented */NTSTATUSNTAPINtCreateProcessEx(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ParentProcess, IN ULONG Flags, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL, IN BOOLEAN InJob){ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "ParentProcess: %p Flags: %lx\n", ParentProcess, Flags);
/* Check if we came from user mode */ if (PreviousMode != KernelMode) { _SEH2_TRY { /* Probe process handle */ ProbeForWriteHandle(ProcessHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Make sure there's a parent process */ if (!ParentProcess) { /* Can't create System Processes like this */ Status = STATUS_INVALID_PARAMETER; } else { /* Create a user Process */ Status = PspCreateProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ParentProcess, Flags, SectionHandle, DebugPort, ExceptionPort, InJob); }
/* Return Status */ return Status;}
/* * @implemented */NTSTATUSNTAPINtCreateProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ParentProcess, IN BOOLEAN InheritObjectTable, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL){ ULONG Flags = 0; PSTRACE(PS_PROCESS_DEBUG, "Parent: %p Attributes: %p\n", ParentProcess, ObjectAttributes);
/* Set new-style flags */ if ((ULONG_PTR)SectionHandle & 1) Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY; if ((ULONG_PTR)DebugPort & 1) Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT; if (InheritObjectTable) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
/* Call the new API */ return NtCreateProcessEx(ProcessHandle, DesiredAccess, ObjectAttributes, ParentProcess, Flags, SectionHandle, DebugPort, ExceptionPort, FALSE);}
/* * @implemented */NTSTATUSNTAPINtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId){ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); CLIENT_ID SafeClientId; ULONG Attributes = 0; HANDLE hProcess; BOOLEAN HasObjectName = FALSE; PETHREAD Thread = NULL; PEPROCESS Process = NULL; NTSTATUS Status; ACCESS_STATE AccessState; AUX_ACCESS_DATA AuxData; PAGED_CODE(); PSTRACE(PS_PROCESS_DEBUG, "ClientId: %p Attributes: %p\n", ClientId, ObjectAttributes);
/* Check if we were called from user mode */ if (PreviousMode != KernelMode) { /* Enter SEH for probing */ _SEH2_TRY { /* Probe the thread handle */ ProbeForWriteHandle(ProcessHandle);
/* Check for a CID structure */ if (ClientId) { /* Probe and capture it */ ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); SafeClientId = *ClientId; ClientId = &SafeClientId; }
/* * Just probe the object attributes structure, don't capture it * completely. This is done later if necessary */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); HasObjectName = (ObjectAttributes->ObjectName != NULL);
/* Validate user attributes */ Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Otherwise just get the data directly */ HasObjectName = (ObjectAttributes->ObjectName != NULL);
/* Still have to sanitize attributes */ Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode); }
/* Can't pass both, fail */ if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
/* Create an access state */ Status = SeCreateAccessState(&AccessState, &AuxData, DesiredAccess, &PsProcessType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) return Status;
/* Check if this is a debugger */ if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) { /* Did he want full access? */ if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) { /* Give it to him */ AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS; } else { /* Otherwise just give every other access he could want */ AccessState.PreviouslyGrantedAccess |= AccessState.RemainingDesiredAccess; }
/* The caller desires nothing else now */ AccessState.RemainingDesiredAccess = 0; }
/* Open by name if one was given */ if (HasObjectName) { /* Open it */ Status = ObOpenObjectByName(ObjectAttributes, PsProcessType, PreviousMode, &AccessState, 0, NULL, &hProcess);
/* Get rid of the access state */ SeDeleteAccessState(&AccessState); } else if (ClientId) { /* Open by Thread ID */ if (ClientId->UniqueThread) { /* Get the Process */ Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread); } else { /* Get the Process */ Status = PsLookupProcessByProcessId(ClientId->UniqueProcess, &Process); }
/* Check if we didn't find anything */ if (!NT_SUCCESS(Status)) { /* Get rid of the access state and return */ SeDeleteAccessState(&AccessState); return Status; }
/* Open the Process Object */ Status = ObOpenObjectByPointer(Process, Attributes, &AccessState, 0, PsProcessType, PreviousMode, &hProcess);
/* Delete the access state */ SeDeleteAccessState(&AccessState);
/* Dereference the thread if we used it */ if (Thread) ObDereferenceObject(Thread);
/* Dereference the Process */ ObDereferenceObject(Process); } else { /* neither an object name nor a client id was passed */ return STATUS_INVALID_PARAMETER_MIX; }
/* Check for success */ if (NT_SUCCESS(Status)) { /* Use SEH for write back */ _SEH2_TRY { /* Write back the handle */ *ProcessHandle = hProcess; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
/* Return status */ return Status;}
/* EOF */