xref: /reactos/ntoskrnl/ps/process.c (revision 073ec9b0)
1 /*
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
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 extern ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
19 
20 POBJECT_TYPE PsProcessType = NULL;
21 
22 LIST_ENTRY PsActiveProcessHead;
23 KGUARDED_MUTEX PspActiveProcessMutex;
24 
25 LARGE_INTEGER ShortPsLockDelay;
26 
27 ULONG PsRawPrioritySeparation;
28 ULONG PsPrioritySeparation;
29 CHAR PspForegroundQuantum[3];
30 
31 /* Fixed quantum table */
32 CHAR PspFixedQuantums[6] =
33 {
34     /* Short quantums */
35     3 * 6, /* Level 1 */
36     3 * 6, /* Level 2 */
37     3 * 6, /* Level 3 */
38 
39     /* Long quantums */
40     6 * 6, /* Level 1 */
41     6 * 6, /* Level 2 */
42     6 * 6  /* Level 3 */
43 };
44 
45 /* Variable quantum table */
46 CHAR PspVariableQuantums[6] =
47 {
48     /* Short quantums */
49     1 * 6, /* Level 1 */
50     2 * 6, /* Level 2 */
51     3 * 6, /* Level 3 */
52 
53     /* Long quantums */
54     2 * 6, /* Level 1 */
55     4 * 6, /* Level 2 */
56     6 * 6  /* Level 3 */
57 };
58 
59 /* Priority table */
60 KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1] =
61 {
62     8,
63     4,
64     8,
65     13,
66     24,
67     6,
68     10
69 };
70 
71 /* PRIVATE FUNCTIONS *********************************************************/
72 
73 PETHREAD
74 NTAPI
PsGetNextProcessThread(IN PEPROCESS Process,IN PETHREAD Thread OPTIONAL)75 PsGetNextProcessThread(IN PEPROCESS Process,
76                        IN PETHREAD Thread OPTIONAL)
77 {
78     PETHREAD FoundThread = NULL;
79     PLIST_ENTRY ListHead, Entry;
80     PAGED_CODE();
81     PSTRACE(PS_PROCESS_DEBUG,
82             "Process: %p Thread: %p\n", Process, Thread);
83 
84     /* Lock the process */
85     KeEnterCriticalRegion();
86     ExAcquirePushLockShared(&Process->ProcessLock);
87 
88     /* Check if we're already starting somewhere */
89     if (Thread)
90     {
91         /* Start where we left off */
92         Entry = Thread->ThreadListEntry.Flink;
93     }
94     else
95     {
96         /* Start at the beginning */
97         Entry = Process->ThreadListHead.Flink;
98     }
99 
100     /* Set the list head and start looping */
101     ListHead = &Process->ThreadListHead;
102     while (ListHead != Entry)
103     {
104         /* Get the Thread */
105         FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
106 
107         /* Safe reference the thread */
108         if (ObReferenceObjectSafe(FoundThread)) break;
109 
110         /* Nothing found, keep looping */
111         FoundThread = NULL;
112         Entry = Entry->Flink;
113     }
114 
115     /* Unlock the process */
116     ExReleasePushLockShared(&Process->ProcessLock);
117     KeLeaveCriticalRegion();
118 
119     /* Check if we had a starting thread, and dereference it */
120     if (Thread) ObDereferenceObject(Thread);
121 
122     /* Return what we found */
123     return FoundThread;
124 }
125 
126 PEPROCESS
127 NTAPI
PsGetNextProcess(IN PEPROCESS OldProcess)128 PsGetNextProcess(IN PEPROCESS OldProcess)
129 {
130     PLIST_ENTRY Entry;
131     PEPROCESS FoundProcess = NULL;
132     PAGED_CODE();
133     PSTRACE(PS_PROCESS_DEBUG, "Process: %p\n", OldProcess);
134 
135     /* Acquire the Active Process Lock */
136     KeAcquireGuardedMutex(&PspActiveProcessMutex);
137 
138     /* Check if we're already starting somewhere */
139     if (OldProcess)
140     {
141         /* Start where we left off */
142         Entry = OldProcess->ActiveProcessLinks.Flink;
143     }
144     else
145     {
146         /* Start at the beginning */
147         Entry = PsActiveProcessHead.Flink;
148     }
149 
150     /* Loop the process list */
151     while (Entry != &PsActiveProcessHead)
152     {
153         /* Get the process */
154         FoundProcess = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
155 
156         /* Reference the process */
157         if (ObReferenceObjectSafe(FoundProcess)) break;
158 
159         /* Nothing found, keep trying */
160         FoundProcess = NULL;
161         Entry = Entry->Flink;
162     }
163 
164     /* Release the lock */
165     KeReleaseGuardedMutex(&PspActiveProcessMutex);
166 
167     /* Dereference the Process we had referenced earlier */
168     if (OldProcess) ObDereferenceObject(OldProcess);
169     return FoundProcess;
170 }
171 
172 KPRIORITY
173 NTAPI
PspComputeQuantumAndPriority(IN PEPROCESS Process,IN PSPROCESSPRIORITYMODE Mode,OUT PUCHAR Quantum)174 PspComputeQuantumAndPriority(IN PEPROCESS Process,
175                              IN PSPROCESSPRIORITYMODE Mode,
176                              OUT PUCHAR Quantum)
177 {
178     ULONG i;
179     UCHAR LocalQuantum, MemoryPriority;
180     PAGED_CODE();
181     PSTRACE(PS_PROCESS_DEBUG, "Process: %p Mode: %lx\n", Process, Mode);
182 
183     /* Check if this is a foreground process */
184     if (Mode == PsProcessPriorityForeground)
185     {
186         /* Set the memory priority and use priority separation */
187         MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
188         i = PsPrioritySeparation;
189     }
190     else
191     {
192         /* Set the background memory priority and no separation */
193         MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
194         i = 0;
195     }
196 
197     /* Make sure that the process mode isn't spinning */
198     if (Mode != PsProcessPrioritySpinning)
199     {
200         /* Set the priority */
201         MmSetMemoryPriorityProcess(Process, MemoryPriority);
202     }
203 
204     /* Make sure that the process isn't idle */
205     if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
206     {
207         /* Does the process have a job? */
208         if ((Process->Job) && (PspUseJobSchedulingClasses))
209         {
210             /* Use job quantum */
211             LocalQuantum = PspJobSchedulingClasses[Process->Job->
212                                                    SchedulingClass];
213         }
214         else
215         {
216             /* Use calculated quantum */
217             LocalQuantum = PspForegroundQuantum[i];
218         }
219     }
220     else
221     {
222         /* Process is idle, use default quantum */
223         LocalQuantum = 6;
224     }
225 
226     /* Return quantum to caller */
227     *Quantum = LocalQuantum;
228 
229     /* Return priority */
230     return PspPriorityTable[Process->PriorityClass];
231 }
232 
233 VOID
234 NTAPI
PsChangeQuantumTable(IN BOOLEAN Immediate,IN ULONG PrioritySeparation)235 PsChangeQuantumTable(IN BOOLEAN Immediate,
236                      IN ULONG PrioritySeparation)
237 {
238     PEPROCESS Process = NULL;
239     ULONG i;
240     UCHAR Quantum;
241     PCHAR QuantumTable;
242     PAGED_CODE();
243     PSTRACE(PS_PROCESS_DEBUG,
244             "%lx PrioritySeparation: %lx\n", Immediate, PrioritySeparation);
245 
246     /* Write the current priority separation */
247     PsPrioritySeparation = PspPrioritySeparationFromMask(PrioritySeparation);
248 
249     /* Normalize it if it was too high */
250     if (PsPrioritySeparation == 3) PsPrioritySeparation = 2;
251 
252     /* Get the quantum table to use */
253     if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_VARIABLE_QUANTUMS)
254     {
255         /* Use a variable table */
256         QuantumTable = PspVariableQuantums;
257     }
258     else if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_FIXED_QUANTUMS)
259     {
260         /* Use fixed table */
261         QuantumTable = PspFixedQuantums;
262     }
263     else
264     {
265         /* Use default for the type of system we're on */
266         QuantumTable = MmIsThisAnNtAsSystem() ? PspFixedQuantums : PspVariableQuantums;
267     }
268 
269     /* Now check if we should use long or short */
270     if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_LONG_QUANTUMS)
271     {
272         /* Use long quantums */
273         QuantumTable += 3;
274     }
275     else if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_SHORT_QUANTUMS)
276     {
277         /* Keep existing table */
278         NOTHING;
279     }
280     else
281     {
282         /* Use default for the type of system we're on */
283         QuantumTable += MmIsThisAnNtAsSystem() ? 3 : 0;
284     }
285 
286     /* Check if we're using long fixed quantums */
287     if (QuantumTable == &PspFixedQuantums[3])
288     {
289         /* Use Job scheduling classes */
290          PspUseJobSchedulingClasses = TRUE;
291     }
292     else
293     {
294         /* Otherwise, we don't */
295         PspUseJobSchedulingClasses = FALSE;
296     }
297 
298     /* Copy the selected table into the Foreground Quantum table */
299     RtlCopyMemory(PspForegroundQuantum,
300                   QuantumTable,
301                   sizeof(PspForegroundQuantum));
302 
303     /* Check if we should apply these changes real-time */
304     if (Immediate)
305     {
306         /* We are...loop every process */
307         Process = PsGetNextProcess(Process);
308         while (Process)
309         {
310             /* Use the priority separation if this is a foreground process */
311             i = (Process->Vm.Flags.MemoryPriority ==
312                  MEMORY_PRIORITY_BACKGROUND) ?
313                  0: PsPrioritySeparation;
314 
315             /* Make sure that the process isn't idle */
316             if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
317             {
318                 /* Does the process have a job? */
319                 if ((Process->Job) && (PspUseJobSchedulingClasses))
320                 {
321                     /* Use job quantum */
322                     Quantum = PspJobSchedulingClasses[Process->Job->SchedulingClass];
323                 }
324                 else
325                 {
326                     /* Use calculated quantum */
327                     Quantum = PspForegroundQuantum[i];
328                 }
329             }
330             else
331             {
332                 /* Process is idle, use default quantum */
333                 Quantum = 6;
334             }
335 
336             /* Now set the quantum */
337             KeSetQuantumProcess(&Process->Pcb, Quantum);
338 
339             /* Get the next process */
340             Process = PsGetNextProcess(Process);
341         }
342     }
343 }
344 
345 NTSTATUS
346 NTAPI
PspCreateProcess(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)347 PspCreateProcess(OUT PHANDLE ProcessHandle,
348                  IN ACCESS_MASK DesiredAccess,
349                  IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
350                  IN HANDLE ParentProcess OPTIONAL,
351                  IN ULONG Flags,
352                  IN HANDLE SectionHandle OPTIONAL,
353                  IN HANDLE DebugPort OPTIONAL,
354                  IN HANDLE ExceptionPort OPTIONAL,
355                  IN BOOLEAN InJob)
356 {
357     HANDLE hProcess;
358     PEPROCESS Process, Parent;
359     PVOID ExceptionPortObject;
360     PDEBUG_OBJECT DebugObject;
361     PSECTION SectionObject;
362     NTSTATUS Status, AccessStatus;
363     ULONG_PTR DirectoryTableBase[2] = {0,0};
364     KAFFINITY Affinity;
365     HANDLE_TABLE_ENTRY CidEntry;
366     PETHREAD CurrentThread = PsGetCurrentThread();
367     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
368     PEPROCESS CurrentProcess = PsGetCurrentProcess();
369     ULONG MinWs, MaxWs;
370     ACCESS_STATE LocalAccessState;
371     PACCESS_STATE AccessState = &LocalAccessState;
372     AUX_ACCESS_DATA AuxData;
373     UCHAR Quantum;
374     BOOLEAN Result, SdAllocated;
375     PSECURITY_DESCRIPTOR SecurityDescriptor;
376     SECURITY_SUBJECT_CONTEXT SubjectContext;
377     BOOLEAN NeedsPeb = FALSE;
378     INITIAL_PEB InitialPeb;
379     PAGED_CODE();
380     PSTRACE(PS_PROCESS_DEBUG,
381             "ProcessHandle: %p Parent: %p\n", ProcessHandle, ParentProcess);
382 
383     /* Validate flags */
384     if (Flags & ~PROCESS_CREATE_FLAGS_LEGAL_MASK) return STATUS_INVALID_PARAMETER;
385 
386     /* Check for parent */
387     if (ParentProcess)
388     {
389         /* Reference it */
390         Status = ObReferenceObjectByHandle(ParentProcess,
391                                            PROCESS_CREATE_PROCESS,
392                                            PsProcessType,
393                                            PreviousMode,
394                                            (PVOID*)&Parent,
395                                            NULL);
396         if (!NT_SUCCESS(Status)) return Status;
397 
398         /* If this process should be in a job but the parent isn't */
399         if ((InJob) && (!Parent->Job))
400         {
401             /* This is illegal. Dereference the parent and fail */
402             ObDereferenceObject(Parent);
403             return STATUS_INVALID_PARAMETER;
404         }
405 
406         /* Inherit Parent process's Affinity. */
407         Affinity = Parent->Pcb.Affinity;
408     }
409     else
410     {
411         /* We have no parent */
412         Parent = NULL;
413         Affinity = KeActiveProcessors;
414     }
415 
416     /* Save working set data */
417     MinWs = PsMinimumWorkingSet;
418     MaxWs = PsMaximumWorkingSet;
419 
420     /* Create the Object */
421     Status = ObCreateObject(PreviousMode,
422                             PsProcessType,
423                             ObjectAttributes,
424                             PreviousMode,
425                             NULL,
426                             sizeof(EPROCESS),
427                             0,
428                             0,
429                             (PVOID*)&Process);
430     if (!NT_SUCCESS(Status)) goto Cleanup;
431 
432     /* Clean up the Object */
433     RtlZeroMemory(Process, sizeof(EPROCESS));
434 
435     /* Initialize pushlock and rundown protection */
436     ExInitializeRundownProtection(&Process->RundownProtect);
437     Process->ProcessLock.Value = 0;
438 
439     /* Setup the Thread List Head */
440     InitializeListHead(&Process->ThreadListHead);
441 
442     /* Set up the Quota Block from the Parent */
443     PspInheritQuota(Process, Parent);
444 
445     /* Set up Dos Device Map from the Parent */
446     ObInheritDeviceMap(Parent, Process);
447 
448     /* Check if we have a parent */
449     if (Parent)
450     {
451         /* Inherit PID and hard-error processing */
452         Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
453         Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
454     }
455     else
456     {
457         /* Use default hard-error processing */
458         Process->DefaultHardErrorProcessing = SEM_FAILCRITICALERRORS;
459     }
460 
461     /* Check for a section handle */
462     if (SectionHandle)
463     {
464         /* Get a pointer to it */
465         Status = ObReferenceObjectByHandle(SectionHandle,
466                                            SECTION_MAP_EXECUTE,
467                                            MmSectionObjectType,
468                                            PreviousMode,
469                                            (PVOID*)&SectionObject,
470                                            NULL);
471         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
472     }
473     else
474     {
475         /* Assume no section object */
476         SectionObject = NULL;
477 
478         /* Is the parent the initial process?
479          * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */
480         if (Parent != PsInitialSystemProcess && (Parent != NULL))
481         {
482             /* It's not, so acquire the process rundown */
483             if (ExAcquireRundownProtection(&Parent->RundownProtect))
484             {
485                 /* If the parent has a section, use it */
486                 SectionObject = Parent->SectionObject;
487                 if (SectionObject) ObReferenceObject(SectionObject);
488 
489                 /* Release process rundown */
490                 ExReleaseRundownProtection(&Parent->RundownProtect);
491             }
492 
493             /* If we don't have a section object */
494             if (!SectionObject)
495             {
496                 /* Then the process is in termination, so fail */
497                 Status = STATUS_PROCESS_IS_TERMINATING;
498                 goto CleanupWithRef;
499             }
500         }
501     }
502 
503     /* Save the pointer to the section object */
504     Process->SectionObject = SectionObject;
505 
506     /* Check for the debug port */
507     if (DebugPort)
508     {
509         /* Reference it */
510         Status = ObReferenceObjectByHandle(DebugPort,
511                                            DEBUG_OBJECT_ADD_REMOVE_PROCESS,
512                                            DbgkDebugObjectType,
513                                            PreviousMode,
514                                            (PVOID*)&DebugObject,
515                                            NULL);
516         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
517 
518         /* Save the debug object */
519         Process->DebugPort = DebugObject;
520 
521         /* Check if the caller doesn't want the debug stuff inherited */
522         if (Flags & PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT)
523         {
524             /* Set the process flag */
525             InterlockedOr((PLONG)&Process->Flags, PSF_NO_DEBUG_INHERIT_BIT);
526         }
527     }
528     else
529     {
530         /* Do we have a parent? Copy his debug port */
531         if (Parent) DbgkCopyProcessDebugPort(Process, Parent);
532     }
533 
534     /* Now check for an exception port */
535     if (ExceptionPort)
536     {
537         /* Reference it */
538         Status = ObReferenceObjectByHandle(ExceptionPort,
539                                            PORT_ALL_ACCESS,
540                                            LpcPortObjectType,
541                                            PreviousMode,
542                                            (PVOID*)&ExceptionPortObject,
543                                            NULL);
544         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
545 
546         /* Save the exception port */
547         Process->ExceptionPort = ExceptionPortObject;
548     }
549 
550     /* Save the pointer to the section object */
551     Process->SectionObject = SectionObject;
552 
553     /* Set default exit code */
554     Process->ExitStatus = STATUS_PENDING;
555 
556     /* Check if this is the initial process being built */
557     if (Parent)
558     {
559         /* Create the address space for the child */
560         if (!MmCreateProcessAddressSpace(MinWs,
561                                          Process,
562                                          DirectoryTableBase))
563         {
564             /* Failed */
565             Status = STATUS_INSUFFICIENT_RESOURCES;
566             goto CleanupWithRef;
567         }
568     }
569     else
570     {
571         /* Otherwise, we are the boot process, we're already semi-initialized */
572         Process->ObjectTable = CurrentProcess->ObjectTable;
573         Status = MmInitializeHandBuiltProcess(Process, DirectoryTableBase);
574         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
575     }
576 
577     /* We now have an address space */
578     InterlockedOr((PLONG)&Process->Flags, PSF_HAS_ADDRESS_SPACE_BIT);
579 
580     /* Set the maximum WS */
581     Process->Vm.MaximumWorkingSetSize = MaxWs;
582 
583     /* Now initialize the Kernel Process */
584     KeInitializeProcess(&Process->Pcb,
585                         PROCESS_PRIORITY_NORMAL,
586                         Affinity,
587                         DirectoryTableBase,
588                         BooleanFlagOn(Process->DefaultHardErrorProcessing,
589                                       SEM_NOALIGNMENTFAULTEXCEPT));
590 
591     /* Duplicate Parent Token */
592     Status = PspInitializeProcessSecurity(Process, Parent);
593     if (!NT_SUCCESS(Status)) goto CleanupWithRef;
594 
595     /* Set default priority class */
596     Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
597 
598     /* Check if we have a parent */
599     if (Parent)
600     {
601         /* Check our priority class */
602         if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||
603             Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL)
604         {
605             /* Normalize it */
606             Process->PriorityClass = Parent->PriorityClass;
607         }
608 
609         /* Initialize object manager for the process */
610         Status = ObInitProcess(Flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES ?
611                                Parent : NULL,
612                                Process);
613         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
614     }
615     else
616     {
617         /* Do the second part of the boot process memory setup */
618         Status = MmInitializeHandBuiltProcess2(Process);
619         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
620     }
621 
622     /* Set success for now */
623     Status = STATUS_SUCCESS;
624 
625     /* Check if this is a real user-mode process */
626     if (SectionHandle)
627     {
628         /* Initialize the address space */
629         Status = MmInitializeProcessAddressSpace(Process,
630                                                  NULL,
631                                                  SectionObject,
632                                                  &Flags,
633                                                  &Process->
634                                                  SeAuditProcessCreationInfo.
635                                                  ImageFileName);
636         if (!NT_SUCCESS(Status)) goto CleanupWithRef;
637 
638         //
639         // We need a PEB
640         //
641         NeedsPeb = TRUE;
642     }
643     else if (Parent)
644     {
645         /* Check if this is a child of the system process */
646         if (Parent != PsInitialSystemProcess)
647         {
648             //
649             // We need a PEB
650             //
651             NeedsPeb = TRUE;
652 
653             /* This is a clone! */
654             ASSERTMSG("No support for cloning yet\n", FALSE);
655         }
656         else
657         {
658             /* This is the initial system process */
659             Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES;
660             Status = MmInitializeProcessAddressSpace(Process,
661                                                      NULL,
662                                                      NULL,
663                                                      &Flags,
664                                                      NULL);
665             if (!NT_SUCCESS(Status)) goto CleanupWithRef;
666 
667             /* Create a dummy image file name */
668             Process->SeAuditProcessCreationInfo.ImageFileName =
669                 ExAllocatePoolWithTag(PagedPool,
670                                       sizeof(OBJECT_NAME_INFORMATION),
671                                       TAG_SEPA);
672             if (!Process->SeAuditProcessCreationInfo.ImageFileName)
673             {
674                 /* Fail */
675                 Status = STATUS_INSUFFICIENT_RESOURCES;
676                 goto CleanupWithRef;
677             }
678 
679             /* Zero it out */
680             RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName,
681                           sizeof(OBJECT_NAME_INFORMATION));
682         }
683     }
684 
685 #if MI_TRACE_PFNS
686     /* Copy the process name now that we have it */
687     memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
688     if (Process->Pcb.DirectoryTableBase[1]) memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
689     if (Process->WorkingSetPage) memcpy(MiGetPfnEntry(Process->WorkingSetPage)->ProcessName, Process->ImageFileName, 16);
690 #endif
691 
692     /* Check if we have a section object and map the system DLL */
693     if (SectionObject) PspMapSystemDll(Process, NULL, FALSE);
694 
695     /* Create a handle for the Process */
696     CidEntry.Object = Process;
697     CidEntry.GrantedAccess = 0;
698     Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
699     if (!Process->UniqueProcessId)
700     {
701         /* Fail */
702         Status = STATUS_INSUFFICIENT_RESOURCES;
703         goto CleanupWithRef;
704     }
705 
706     /* Set the handle table PID */
707     Process->ObjectTable->UniqueProcessId = Process->UniqueProcessId;
708 
709     /* Check if we need to audit */
710     if (SeDetailedAuditingWithToken(NULL)) SeAuditProcessCreate(Process);
711 
712     /* Check if the parent had a job */
713     if ((Parent) && (Parent->Job))
714     {
715         /* FIXME: We need to insert this process */
716         DPRINT1("Jobs not yet supported\n");
717     }
718 
719     /* Create PEB only for User-Mode Processes */
720     if ((Parent) && (NeedsPeb))
721     {
722         //
723         // Set up the initial PEB
724         //
725         RtlZeroMemory(&InitialPeb, sizeof(INITIAL_PEB));
726         InitialPeb.Mutant = (HANDLE)-1;
727         InitialPeb.ImageUsesLargePages = 0; // FIXME: Not yet supported
728 
729         //
730         // Create it only if we have an image section
731         //
732         if (SectionHandle)
733         {
734             //
735             // Create it
736             //
737             Status = MmCreatePeb(Process, &InitialPeb, &Process->Peb);
738             if (!NT_SUCCESS(Status)) goto CleanupWithRef;
739         }
740         else
741         {
742             //
743             // We have to clone it
744             //
745             ASSERTMSG("No support for cloning yet\n", FALSE);
746         }
747 
748     }
749 
750     /* The process can now be activated */
751     KeAcquireGuardedMutex(&PspActiveProcessMutex);
752     InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks);
753     KeReleaseGuardedMutex(&PspActiveProcessMutex);
754 
755     /* Create an access state */
756     Status = SeCreateAccessStateEx(CurrentThread,
757                                    ((Parent) &&
758                                    (Parent == PsInitialSystemProcess)) ?
759                                     Parent : CurrentProcess,
760                                    &LocalAccessState,
761                                    &AuxData,
762                                    DesiredAccess,
763                                    &PsProcessType->TypeInfo.GenericMapping);
764     if (!NT_SUCCESS(Status)) goto CleanupWithRef;
765 
766     /* Insert the Process into the Object Directory */
767     Status = ObInsertObject(Process,
768                             AccessState,
769                             DesiredAccess,
770                             1,
771                             NULL,
772                             &hProcess);
773 
774     /* Free the access state */
775     if (AccessState) SeDeleteAccessState(AccessState);
776 
777     /* Cleanup on failure */
778     if (!NT_SUCCESS(Status)) goto Cleanup;
779 
780     /* Compute Quantum and Priority */
781     ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);
782     Process->Pcb.BasePriority =
783         (SCHAR)PspComputeQuantumAndPriority(Process,
784                                             PsProcessPriorityBackground,
785                                             &Quantum);
786     Process->Pcb.QuantumReset = Quantum;
787 
788     /* Check if we have a parent other then the initial system process */
789     Process->GrantedAccess = PROCESS_TERMINATE;
790     if ((Parent) && (Parent != PsInitialSystemProcess))
791     {
792         /* Get the process's SD */
793         Status = ObGetObjectSecurity(Process,
794                                      &SecurityDescriptor,
795                                      &SdAllocated);
796         if (!NT_SUCCESS(Status))
797         {
798             /* We failed, close the handle and clean up */
799             ObCloseHandle(hProcess, PreviousMode);
800             goto CleanupWithRef;
801         }
802 
803         /* Create the subject context */
804         SubjectContext.ProcessAuditId = Process;
805         SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
806         SubjectContext.ClientToken = NULL;
807 
808         /* Do the access check */
809         Result = SeAccessCheck(SecurityDescriptor,
810                                &SubjectContext,
811                                FALSE,
812                                MAXIMUM_ALLOWED,
813                                0,
814                                NULL,
815                                &PsProcessType->TypeInfo.GenericMapping,
816                                PreviousMode,
817                                &Process->GrantedAccess,
818                                &AccessStatus);
819 
820         /* Dereference the token and let go the SD */
821         ObFastDereferenceObject(&Process->Token,
822                                 SubjectContext.PrimaryToken);
823         ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
824 
825         /* Remove access if it failed */
826         if (!Result) Process->GrantedAccess = 0;
827 
828         /* Give the process some basic access */
829         Process->GrantedAccess |= (PROCESS_VM_OPERATION |
830                                    PROCESS_VM_READ |
831                                    PROCESS_VM_WRITE |
832                                    PROCESS_QUERY_INFORMATION |
833                                    PROCESS_TERMINATE |
834                                    PROCESS_CREATE_THREAD |
835                                    PROCESS_DUP_HANDLE |
836                                    PROCESS_CREATE_PROCESS |
837                                    PROCESS_SET_INFORMATION |
838                                    STANDARD_RIGHTS_ALL |
839                                    PROCESS_SET_QUOTA);
840     }
841     else
842     {
843         /* Set full granted access */
844         Process->GrantedAccess = PROCESS_ALL_ACCESS;
845     }
846 
847     /* Set the Creation Time */
848     KeQuerySystemTime(&Process->CreateTime);
849 
850     /* Protect against bad user-mode pointer */
851     _SEH2_TRY
852     {
853         /* Hacky way of returning the PEB to the user-mode creator */
854         if ((Process->Peb) && (CurrentThread->Tcb.Teb))
855         {
856             CurrentThread->Tcb.Teb->NtTib.ArbitraryUserPointer = Process->Peb;
857         }
858 
859         /* Save the process handle */
860        *ProcessHandle = hProcess;
861     }
862     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
863     {
864         /* Get the exception code */
865        Status = _SEH2_GetExceptionCode();
866     }
867     _SEH2_END;
868 
869     /* Run the Notification Routines */
870     PspRunCreateProcessNotifyRoutines(Process, TRUE);
871 
872     /* If 12 processes have been created, enough of user-mode is ready */
873     if (++ProcessCount == 12) Ki386PerfEnd();
874 
875 CleanupWithRef:
876     /*
877      * Dereference the process. For failures, kills the process and does
878      * cleanup present in PspDeleteProcess. For success, kills the extra
879      * reference added by ObInsertObject.
880      */
881     ObDereferenceObject(Process);
882 
883 Cleanup:
884     /* Dereference the parent */
885     if (Parent) ObDereferenceObject(Parent);
886 
887     /* Return status to caller */
888     return Status;
889 }
890 
891 /* PUBLIC FUNCTIONS **********************************************************/
892 
893 /*
894  * @implemented
895  */
896 NTSTATUS
897 NTAPI
PsCreateSystemProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes)898 PsCreateSystemProcess(OUT PHANDLE ProcessHandle,
899                       IN ACCESS_MASK DesiredAccess,
900                       IN POBJECT_ATTRIBUTES ObjectAttributes)
901 {
902     /* Call the internal API */
903     return PspCreateProcess(ProcessHandle,
904                             DesiredAccess,
905                             ObjectAttributes,
906                             NULL,
907                             0,
908                             NULL,
909                             NULL,
910                             NULL,
911                             FALSE);
912 }
913 
914 /*
915  * @implemented
916  */
917 NTSTATUS
918 NTAPI
PsLookupProcessByProcessId(IN HANDLE ProcessId,OUT PEPROCESS * Process)919 PsLookupProcessByProcessId(IN HANDLE ProcessId,
920                            OUT PEPROCESS *Process)
921 {
922     PHANDLE_TABLE_ENTRY CidEntry;
923     PEPROCESS FoundProcess;
924     NTSTATUS Status = STATUS_INVALID_PARAMETER;
925     PAGED_CODE();
926     PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId);
927     KeEnterCriticalRegion();
928 
929     /* Get the CID Handle Entry */
930     CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
931     if (CidEntry)
932     {
933         /* Get the Process */
934         FoundProcess = CidEntry->Object;
935 
936         /* Make sure it's really a process */
937         if (FoundProcess->Pcb.Header.Type == ProcessObject)
938         {
939             /* Safe Reference and return it */
940             if (ObReferenceObjectSafe(FoundProcess))
941             {
942                 *Process = FoundProcess;
943                 Status = STATUS_SUCCESS;
944             }
945         }
946 
947         /* Unlock the Entry */
948         ExUnlockHandleTableEntry(PspCidTable, CidEntry);
949     }
950 
951     /* Return to caller */
952     KeLeaveCriticalRegion();
953     return Status;
954 }
955 
956 /*
957  * @implemented
958  */
959 NTSTATUS
960 NTAPI
PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,OUT PEPROCESS * Process OPTIONAL,OUT PETHREAD * Thread)961 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
962                            OUT PEPROCESS *Process OPTIONAL,
963                            OUT PETHREAD *Thread)
964 {
965     PHANDLE_TABLE_ENTRY CidEntry;
966     PETHREAD FoundThread;
967     NTSTATUS Status = STATUS_INVALID_CID;
968     PAGED_CODE();
969     PSTRACE(PS_PROCESS_DEBUG, "Cid: %p\n", Cid);
970     KeEnterCriticalRegion();
971 
972     /* Get the CID Handle Entry */
973     CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread);
974     if (CidEntry)
975     {
976         /* Get the Process */
977         FoundThread = CidEntry->Object;
978 
979         /* Make sure it's really a thread and this process' */
980         if ((FoundThread->Tcb.Header.Type == ThreadObject) &&
981             (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess))
982         {
983             /* Safe Reference and return it */
984             if (ObReferenceObjectSafe(FoundThread))
985             {
986                 *Thread = FoundThread;
987                 Status = STATUS_SUCCESS;
988 
989                 /* Check if we should return the Process too */
990                 if (Process)
991                 {
992                     /* Return it and reference it */
993                     *Process = FoundThread->ThreadsProcess;
994                     ObReferenceObject(*Process);
995                 }
996             }
997         }
998 
999         /* Unlock the Entry */
1000         ExUnlockHandleTableEntry(PspCidTable, CidEntry);
1001     }
1002 
1003     /* Return to caller */
1004     KeLeaveCriticalRegion();
1005     return Status;
1006 }
1007 
1008 /*
1009  * @implemented
1010  */
1011 LARGE_INTEGER
1012 NTAPI
PsGetProcessExitTime(VOID)1013 PsGetProcessExitTime(VOID)
1014 {
1015     return PsGetCurrentProcess()->ExitTime;
1016 }
1017 
1018 /*
1019  * @implemented
1020  */
1021 LONGLONG
1022 NTAPI
PsGetProcessCreateTimeQuadPart(PEPROCESS Process)1023 PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
1024 {
1025     return Process->CreateTime.QuadPart;
1026 }
1027 
1028 /*
1029  * @implemented
1030  */
1031 PVOID
1032 NTAPI
PsGetProcessDebugPort(PEPROCESS Process)1033 PsGetProcessDebugPort(PEPROCESS Process)
1034 {
1035     return Process->DebugPort;
1036 }
1037 
1038 /*
1039  * @implemented
1040  */
1041 BOOLEAN
1042 NTAPI
PsGetProcessExitProcessCalled(PEPROCESS Process)1043 PsGetProcessExitProcessCalled(PEPROCESS Process)
1044 {
1045     return (BOOLEAN)Process->ProcessExiting;
1046 }
1047 
1048 /*
1049  * @implemented
1050  */
1051 NTSTATUS
1052 NTAPI
PsGetProcessExitStatus(PEPROCESS Process)1053 PsGetProcessExitStatus(PEPROCESS Process)
1054 {
1055     return Process->ExitStatus;
1056 }
1057 
1058 /*
1059  * @implemented
1060  */
1061 HANDLE
1062 NTAPI
PsGetProcessId(PEPROCESS Process)1063 PsGetProcessId(PEPROCESS Process)
1064 {
1065     return (HANDLE)Process->UniqueProcessId;
1066 }
1067 
1068 /*
1069  * @implemented
1070  */
1071 LPSTR
1072 NTAPI
PsGetProcessImageFileName(PEPROCESS Process)1073 PsGetProcessImageFileName(PEPROCESS Process)
1074 {
1075     return (LPSTR)Process->ImageFileName;
1076 }
1077 
1078 /*
1079  * @implemented
1080  */
1081 HANDLE
1082 NTAPI
PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)1083 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
1084 {
1085     return Process->InheritedFromUniqueProcessId;
1086 }
1087 
1088 /*
1089  * @implemented
1090  */
1091 PEJOB
1092 NTAPI
PsGetProcessJob(PEPROCESS Process)1093 PsGetProcessJob(PEPROCESS Process)
1094 {
1095     return Process->Job;
1096 }
1097 
1098 /*
1099  * @implemented
1100  */
1101 PPEB
1102 NTAPI
PsGetProcessPeb(PEPROCESS Process)1103 PsGetProcessPeb(PEPROCESS Process)
1104 {
1105     return Process->Peb;
1106 }
1107 
1108 /*
1109  * @implemented
1110  */
1111 ULONG
1112 NTAPI
PsGetProcessPriorityClass(PEPROCESS Process)1113 PsGetProcessPriorityClass(PEPROCESS Process)
1114 {
1115     return Process->PriorityClass;
1116 }
1117 
1118 /*
1119  * @implemented
1120  */
1121 HANDLE
1122 NTAPI
PsGetCurrentProcessId(VOID)1123 PsGetCurrentProcessId(VOID)
1124 {
1125     return (HANDLE)PsGetCurrentProcess()->UniqueProcessId;
1126 }
1127 
1128 /*
1129  * @implemented
1130  */
1131 ULONG
1132 NTAPI
PsGetCurrentProcessSessionId(VOID)1133 PsGetCurrentProcessSessionId(VOID)
1134 {
1135     return MmGetSessionId(PsGetCurrentProcess());
1136 }
1137 
1138 /*
1139  * @implemented
1140  */
1141 PVOID
1142 NTAPI
PsGetProcessSectionBaseAddress(PEPROCESS Process)1143 PsGetProcessSectionBaseAddress(PEPROCESS Process)
1144 {
1145     return Process->SectionBaseAddress;
1146 }
1147 
1148 /*
1149  * @implemented
1150  */
1151 PVOID
1152 NTAPI
PsGetProcessSecurityPort(PEPROCESS Process)1153 PsGetProcessSecurityPort(PEPROCESS Process)
1154 {
1155     return Process->SecurityPort;
1156 }
1157 
1158 /*
1159  * @implemented
1160  */
1161 ULONG
1162 NTAPI
PsGetProcessSessionId(IN PEPROCESS Process)1163 PsGetProcessSessionId(IN PEPROCESS Process)
1164 {
1165     return MmGetSessionId(Process);
1166 }
1167 
1168 /*
1169  * @implemented
1170  */
1171 ULONG
1172 NTAPI
PsGetProcessSessionIdEx(IN PEPROCESS Process)1173 PsGetProcessSessionIdEx(IN PEPROCESS Process)
1174 {
1175     return MmGetSessionIdEx(Process);
1176 }
1177 
1178 /*
1179  * @implemented
1180  */
1181 PVOID
1182 NTAPI
PsGetCurrentProcessWin32Process(VOID)1183 PsGetCurrentProcessWin32Process(VOID)
1184 {
1185     return PsGetCurrentProcess()->Win32Process;
1186 }
1187 
1188 /*
1189  * @implemented
1190  */
1191 PVOID
1192 NTAPI
PsGetProcessWin32Process(PEPROCESS Process)1193 PsGetProcessWin32Process(PEPROCESS Process)
1194 {
1195     return Process->Win32Process;
1196 }
1197 
1198 /*
1199  * @implemented
1200  */
1201 PVOID
1202 NTAPI
PsGetProcessWin32WindowStation(PEPROCESS Process)1203 PsGetProcessWin32WindowStation(PEPROCESS Process)
1204 {
1205     return Process->Win32WindowStation;
1206 }
1207 
1208 /*
1209  * @implemented
1210  */
1211 BOOLEAN
1212 NTAPI
PsIsProcessBeingDebugged(PEPROCESS Process)1213 PsIsProcessBeingDebugged(PEPROCESS Process)
1214 {
1215     return Process->DebugPort != NULL;
1216 }
1217 
1218 /*
1219  * @implemented
1220  */
1221 BOOLEAN
1222 NTAPI
PsIsSystemProcess(IN PEPROCESS Process)1223 PsIsSystemProcess(IN PEPROCESS Process)
1224 {
1225     /* Return if this is the System Process */
1226     return Process == PsInitialSystemProcess;
1227 }
1228 
1229 /*
1230  * @implemented
1231  */
1232 VOID
1233 NTAPI
PsSetProcessPriorityClass(PEPROCESS Process,ULONG PriorityClass)1234 PsSetProcessPriorityClass(PEPROCESS Process,
1235                           ULONG PriorityClass)
1236 {
1237     Process->PriorityClass = (UCHAR)PriorityClass;
1238 }
1239 
1240 /*
1241  * @implemented
1242  */
1243 NTSTATUS
1244 NTAPI
PsSetProcessSecurityPort(PEPROCESS Process,PVOID SecurityPort)1245 PsSetProcessSecurityPort(PEPROCESS Process,
1246                          PVOID SecurityPort)
1247 {
1248     Process->SecurityPort = SecurityPort;
1249     return STATUS_SUCCESS;
1250 }
1251 
1252 /*
1253  * @implemented
1254  */
1255 NTSTATUS
1256 NTAPI
PsSetProcessWin32Process(_Inout_ PEPROCESS Process,_In_opt_ PVOID Win32Process,_In_opt_ PVOID OldWin32Process)1257 PsSetProcessWin32Process(
1258     _Inout_ PEPROCESS Process,
1259     _In_opt_ PVOID Win32Process,
1260     _In_opt_ PVOID OldWin32Process)
1261 {
1262     NTSTATUS Status;
1263 
1264     /* Assume success */
1265     Status = STATUS_SUCCESS;
1266 
1267     /* Lock the process */
1268     KeEnterCriticalRegion();
1269     ExAcquirePushLockExclusive(&Process->ProcessLock);
1270 
1271     /* Check if we set a new win32 process */
1272     if (Win32Process != NULL)
1273     {
1274         /* Check if the process is in the right state */
1275         if (((Process->Flags & PSF_PROCESS_DELETE_BIT) == 0) &&
1276             (Process->Win32Process == NULL))
1277         {
1278             /* Set the new win32 process */
1279             Process->Win32Process = Win32Process;
1280         }
1281         else
1282         {
1283             /* Otherwise fail */
1284             Status = STATUS_PROCESS_IS_TERMINATING;
1285         }
1286     }
1287     else
1288     {
1289         /* Reset the win32 process, did the caller specify the correct old value? */
1290         if (Process->Win32Process == OldWin32Process)
1291         {
1292             /* Yes, so reset the win32 process to NULL */
1293             Process->Win32Process = NULL;
1294         }
1295         else
1296         {
1297             /* Otherwise fail */
1298             Status = STATUS_UNSUCCESSFUL;
1299         }
1300     }
1301 
1302     /* Unlock the process */
1303     ExReleasePushLockExclusive(&Process->ProcessLock);
1304     KeLeaveCriticalRegion();
1305 
1306     return Status;
1307 }
1308 
1309 /*
1310  * @implemented
1311  */
1312 VOID
1313 NTAPI
PsSetProcessWindowStation(PEPROCESS Process,PVOID WindowStation)1314 PsSetProcessWindowStation(PEPROCESS Process,
1315                           PVOID WindowStation)
1316 {
1317     Process->Win32WindowStation = WindowStation;
1318 }
1319 
1320 /*
1321  * @implemented
1322  */
1323 VOID
1324 NTAPI
PsSetProcessPriorityByClass(IN PEPROCESS Process,IN PSPROCESSPRIORITYMODE Type)1325 PsSetProcessPriorityByClass(IN PEPROCESS Process,
1326                             IN PSPROCESSPRIORITYMODE Type)
1327 {
1328     UCHAR Quantum;
1329     ULONG Priority;
1330     PSTRACE(PS_PROCESS_DEBUG, "Process: %p Type: %lx\n", Process, Type);
1331 
1332     /* Compute quantum and priority */
1333     Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
1334 
1335     /* Set them */
1336     KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);
1337 }
1338 
1339 /*
1340  * @implemented
1341  */
1342 NTSTATUS
1343 NTAPI
NtCreateProcessEx(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)1344 NtCreateProcessEx(OUT PHANDLE ProcessHandle,
1345                   IN ACCESS_MASK DesiredAccess,
1346                   IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1347                   IN HANDLE ParentProcess,
1348                   IN ULONG Flags,
1349                   IN HANDLE SectionHandle OPTIONAL,
1350                   IN HANDLE DebugPort OPTIONAL,
1351                   IN HANDLE ExceptionPort OPTIONAL,
1352                   IN BOOLEAN InJob)
1353 {
1354     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1355     NTSTATUS Status;
1356     PAGED_CODE();
1357     PSTRACE(PS_PROCESS_DEBUG,
1358             "ParentProcess: %p Flags: %lx\n", ParentProcess, Flags);
1359 
1360     /* Check if we came from user mode */
1361     if (PreviousMode != KernelMode)
1362     {
1363         _SEH2_TRY
1364         {
1365             /* Probe process handle */
1366             ProbeForWriteHandle(ProcessHandle);
1367         }
1368         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1369         {
1370             /* Return the exception code */
1371             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1372         }
1373         _SEH2_END;
1374     }
1375 
1376     /* Make sure there's a parent process */
1377     if (!ParentProcess)
1378     {
1379         /* Can't create System Processes like this */
1380         Status = STATUS_INVALID_PARAMETER;
1381     }
1382     else
1383     {
1384         /* Create a user Process */
1385         Status = PspCreateProcess(ProcessHandle,
1386                                   DesiredAccess,
1387                                   ObjectAttributes,
1388                                   ParentProcess,
1389                                   Flags,
1390                                   SectionHandle,
1391                                   DebugPort,
1392                                   ExceptionPort,
1393                                   InJob);
1394     }
1395 
1396     /* Return Status */
1397     return Status;
1398 }
1399 
1400 /*
1401  * @implemented
1402  */
1403 NTSTATUS
1404 NTAPI
NtCreateProcess(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)1405 NtCreateProcess(OUT PHANDLE ProcessHandle,
1406                 IN ACCESS_MASK DesiredAccess,
1407                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1408                 IN HANDLE ParentProcess,
1409                 IN BOOLEAN InheritObjectTable,
1410                 IN HANDLE SectionHandle OPTIONAL,
1411                 IN HANDLE DebugPort OPTIONAL,
1412                 IN HANDLE ExceptionPort OPTIONAL)
1413 {
1414     ULONG Flags = 0;
1415     PSTRACE(PS_PROCESS_DEBUG,
1416             "Parent: %p Attributes: %p\n", ParentProcess, ObjectAttributes);
1417 
1418     /* Set new-style flags */
1419     if ((ULONG_PTR)SectionHandle & 1) Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
1420     if ((ULONG_PTR)DebugPort & 1) Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
1421     if (InheritObjectTable) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
1422 
1423     /* Call the new API */
1424     return NtCreateProcessEx(ProcessHandle,
1425                              DesiredAccess,
1426                              ObjectAttributes,
1427                              ParentProcess,
1428                              Flags,
1429                              SectionHandle,
1430                              DebugPort,
1431                              ExceptionPort,
1432                              FALSE);
1433 }
1434 
1435 /*
1436  * @implemented
1437  */
1438 NTSTATUS
1439 NTAPI
NtOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId)1440 NtOpenProcess(OUT PHANDLE ProcessHandle,
1441               IN ACCESS_MASK DesiredAccess,
1442               IN POBJECT_ATTRIBUTES ObjectAttributes,
1443               IN PCLIENT_ID ClientId)
1444 {
1445     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1446     CLIENT_ID SafeClientId;
1447     ULONG Attributes = 0;
1448     HANDLE hProcess;
1449     BOOLEAN HasObjectName = FALSE;
1450     PETHREAD Thread = NULL;
1451     PEPROCESS Process = NULL;
1452     NTSTATUS Status;
1453     ACCESS_STATE AccessState;
1454     AUX_ACCESS_DATA AuxData;
1455     PAGED_CODE();
1456     PSTRACE(PS_PROCESS_DEBUG,
1457             "ClientId: %p Attributes: %p\n", ClientId, ObjectAttributes);
1458 
1459     /* Check if we were called from user mode */
1460     if (PreviousMode != KernelMode)
1461     {
1462         /* Enter SEH for probing */
1463         _SEH2_TRY
1464         {
1465             /* Probe the thread handle */
1466             ProbeForWriteHandle(ProcessHandle);
1467 
1468             /* Check for a CID structure */
1469             if (ClientId)
1470             {
1471                 /* Probe and capture it */
1472                 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
1473                 SafeClientId = *ClientId;
1474                 ClientId = &SafeClientId;
1475             }
1476 
1477             /*
1478              * Just probe the object attributes structure, don't capture it
1479              * completely. This is done later if necessary
1480              */
1481             ProbeForRead(ObjectAttributes,
1482                          sizeof(OBJECT_ATTRIBUTES),
1483                          sizeof(ULONG));
1484             HasObjectName = (ObjectAttributes->ObjectName != NULL);
1485 
1486             /* Validate user attributes */
1487             Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
1488         }
1489         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1490         {
1491             /* Return the exception code */
1492             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1493         }
1494         _SEH2_END;
1495     }
1496     else
1497     {
1498         /* Otherwise just get the data directly */
1499         HasObjectName = (ObjectAttributes->ObjectName != NULL);
1500 
1501         /* Still have to sanitize attributes */
1502         Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
1503     }
1504 
1505     /* Can't pass both, fail */
1506     if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1507 
1508     /* Create an access state */
1509     Status = SeCreateAccessState(&AccessState,
1510                                  &AuxData,
1511                                  DesiredAccess,
1512                                  &PsProcessType->TypeInfo.GenericMapping);
1513     if (!NT_SUCCESS(Status)) return Status;
1514 
1515     /* Check if this is a debugger */
1516     if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1517     {
1518         /* Did he want full access? */
1519         if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1520         {
1521             /* Give it to him */
1522             AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
1523         }
1524         else
1525         {
1526             /* Otherwise just give every other access he could want */
1527             AccessState.PreviouslyGrantedAccess |=
1528                 AccessState.RemainingDesiredAccess;
1529         }
1530 
1531         /* The caller desires nothing else now */
1532         AccessState.RemainingDesiredAccess = 0;
1533     }
1534 
1535     /* Open by name if one was given */
1536     if (HasObjectName)
1537     {
1538         /* Open it */
1539         Status = ObOpenObjectByName(ObjectAttributes,
1540                                     PsProcessType,
1541                                     PreviousMode,
1542                                     &AccessState,
1543                                     0,
1544                                     NULL,
1545                                     &hProcess);
1546 
1547         /* Get rid of the access state */
1548         SeDeleteAccessState(&AccessState);
1549     }
1550     else if (ClientId)
1551     {
1552         /* Open by Thread ID */
1553         if (ClientId->UniqueThread)
1554         {
1555             /* Get the Process */
1556             Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread);
1557         }
1558         else
1559         {
1560             /* Get the Process */
1561             Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
1562                                                 &Process);
1563         }
1564 
1565         /* Check if we didn't find anything */
1566         if (!NT_SUCCESS(Status))
1567         {
1568             /* Get rid of the access state and return */
1569             SeDeleteAccessState(&AccessState);
1570             return Status;
1571         }
1572 
1573         /* Open the Process Object */
1574         Status = ObOpenObjectByPointer(Process,
1575                                        Attributes,
1576                                        &AccessState,
1577                                        0,
1578                                        PsProcessType,
1579                                        PreviousMode,
1580                                        &hProcess);
1581 
1582         /* Delete the access state */
1583         SeDeleteAccessState(&AccessState);
1584 
1585         /* Dereference the thread if we used it */
1586         if (Thread) ObDereferenceObject(Thread);
1587 
1588         /* Dereference the Process */
1589         ObDereferenceObject(Process);
1590     }
1591     else
1592     {
1593         /* neither an object name nor a client id was passed */
1594         return STATUS_INVALID_PARAMETER_MIX;
1595     }
1596 
1597     /* Check for success */
1598     if (NT_SUCCESS(Status))
1599     {
1600         /* Use SEH for write back */
1601         _SEH2_TRY
1602         {
1603             /* Write back the handle */
1604             *ProcessHandle = hProcess;
1605         }
1606         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1607         {
1608             /* Get the exception code */
1609             Status = _SEH2_GetExceptionCode();
1610         }
1611         _SEH2_END;
1612     }
1613 
1614     /* Return status */
1615     return Status;
1616 }
1617 
1618 /* EOF */
1619