/* Validate flags */
if (Flags & ~PS_ALL_FLAGS) 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));
/* 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 = TRUE;
}
/* 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? */
if (Parent != PsInitialSystemProcess)
{
/* It's not, so acquire the process rundown */
if (ExAcquireRundownProtection(&Process->RundownProtect))
{
/* If the parent has a section, use it */
SectionObject = Parent->SectionObject;
if (SectionObject) ObReferenceObject(SectionObject);
/* Release process rundown */
ExReleaseRundownProtection(&Process->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 & PS_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,
(BOOLEAN)(Process->DefaultHardErrorProcessing & 4));
/* 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 & PS_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 &= ~PS_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),
'aPeS');
if (!Process->SeAuditProcessCreationInfo.ImageFileName)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
goto CleanupWithRef;
}
/* Zero it out */
RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName,
sizeof(OBJECT_NAME_INFORMATION));
}
}
/* 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");
ASSERT(FALSE);
}
/* 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;
/* 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;
}
/* 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
{
/* Save the process handle */
*ProcessHandle = hProcess;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Run the Notification Routines 这里才调回调,进城都创建好了,浪费cpu*/
PspRunCreateProcessNotifyRoutines(Process, TRUE);
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);