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