Synchronize with trunk r58457.
[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;
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
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
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
259 {
260 /* Use fixed table */
261 QuantumTable = PspFixedQuantums;
262 }
263
264 /* Now check if we should use long or short */
265 if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_LONG_QUANTUMS)
266 {
267 /* Use long quantums */
268 QuantumTable += 3;
269 }
270
271 /* Check if we're using long fixed quantums */
272 if (QuantumTable == &PspFixedQuantums[3])
273 {
274 /* Use Job scheduling classes */
275 PspUseJobSchedulingClasses = TRUE;
276 }
277 else
278 {
279 /* Otherwise, we don't */
280 PspUseJobSchedulingClasses = FALSE;
281 }
282
283 /* Copy the selected table into the Foreground Quantum table */
284 RtlCopyMemory(PspForegroundQuantum,
285 QuantumTable,
286 sizeof(PspForegroundQuantum));
287
288 /* Check if we should apply these changes real-time */
289 if (Immediate)
290 {
291 /* We are...loop every process */
292 Process = PsGetNextProcess(Process);
293 while (Process)
294 {
295 /*
296 * Use the priority separation, unless the process has
297 * low memory priority
298 */
299 i = (Process->Vm.Flags.MemoryPriority == 1) ?
300 0: PsPrioritySeparation;
301
302 /* Make sure that the process isn't idle */
303 if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
304 {
305 /* Does the process have a job? */
306 if ((Process->Job) && (PspUseJobSchedulingClasses))
307 {
308 /* Use job quantum */
309 Quantum = PspJobSchedulingClasses[Process->Job->
310 SchedulingClass];
311 }
312 else
313 {
314 /* Use calculated quantum */
315 Quantum = PspForegroundQuantum[i];
316 }
317 }
318 else
319 {
320 /* Process is idle, use default quantum */
321 Quantum = 6;
322 }
323
324 /* Now set the quantum */
325 KeSetQuantumProcess(&Process->Pcb, Quantum);
326
327 /* Get the next process */
328 Process = PsGetNextProcess(Process);
329 }
330 }
331 }
332
333 NTSTATUS
334 NTAPI
335 PspCreateProcess(OUT PHANDLE ProcessHandle,
336 IN ACCESS_MASK DesiredAccess,
337 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
338 IN HANDLE ParentProcess OPTIONAL,
339 IN ULONG Flags,
340 IN HANDLE SectionHandle OPTIONAL,
341 IN HANDLE DebugPort OPTIONAL,
342 IN HANDLE ExceptionPort OPTIONAL,
343 IN BOOLEAN InJob)
344 {
345 HANDLE hProcess;
346 PEPROCESS Process, Parent;
347 PVOID ExceptionPortObject;
348 PDEBUG_OBJECT DebugObject;
349 PSECTION_OBJECT SectionObject;
350 NTSTATUS Status, AccessStatus;
351 ULONG_PTR DirectoryTableBase[2] = {0,0};
352 KAFFINITY Affinity;
353 HANDLE_TABLE_ENTRY CidEntry;
354 PETHREAD CurrentThread = PsGetCurrentThread();
355 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
356 PEPROCESS CurrentProcess = PsGetCurrentProcess();
357 ULONG MinWs, MaxWs;
358 ACCESS_STATE LocalAccessState;
359 PACCESS_STATE AccessState = &LocalAccessState;
360 AUX_ACCESS_DATA AuxData;
361 UCHAR Quantum;
362 BOOLEAN Result, SdAllocated;
363 PSECURITY_DESCRIPTOR SecurityDescriptor;
364 SECURITY_SUBJECT_CONTEXT SubjectContext;
365 BOOLEAN NeedsPeb = FALSE;
366 INITIAL_PEB InitialPeb;
367 PAGED_CODE();
368 PSTRACE(PS_PROCESS_DEBUG,
369 "ProcessHandle: %p Parent: %p\n", ProcessHandle, ParentProcess);
370
371 /* Validate flags */
372 if (Flags & ~PS_ALL_FLAGS) return STATUS_INVALID_PARAMETER;
373
374 /* Check for parent */
375 if (ParentProcess)
376 {
377 /* Reference it */
378 Status = ObReferenceObjectByHandle(ParentProcess,
379 PROCESS_CREATE_PROCESS,
380 PsProcessType,
381 PreviousMode,
382 (PVOID*)&Parent,
383 NULL);
384 if (!NT_SUCCESS(Status)) return Status;
385
386 /* If this process should be in a job but the parent isn't */
387 if ((InJob) && (!Parent->Job))
388 {
389 /* This is illegal. Dereference the parent and fail */
390 ObDereferenceObject(Parent);
391 return STATUS_INVALID_PARAMETER;
392 }
393
394 /* Inherit Parent process's Affinity. */
395 Affinity = Parent->Pcb.Affinity;
396 }
397 else
398 {
399 /* We have no parent */
400 Parent = NULL;
401 Affinity = KeActiveProcessors;
402 }
403
404 /* Save working set data */
405 MinWs = PsMinimumWorkingSet;
406 MaxWs = PsMaximumWorkingSet;
407
408 /* Create the Object */
409 Status = ObCreateObject(PreviousMode,
410 PsProcessType,
411 ObjectAttributes,
412 PreviousMode,
413 NULL,
414 sizeof(EPROCESS),
415 0,
416 0,
417 (PVOID*)&Process);
418 if (!NT_SUCCESS(Status)) goto Cleanup;
419
420 /* Clean up the Object */
421 RtlZeroMemory(Process, sizeof(EPROCESS));
422
423 /* Initialize pushlock and rundown protection */
424 ExInitializeRundownProtection(&Process->RundownProtect);
425 Process->ProcessLock.Value = 0;
426
427 /* Setup the Thread List Head */
428 InitializeListHead(&Process->ThreadListHead);
429
430 /* Set up the Quota Block from the Parent */
431 PspInheritQuota(Process, Parent);
432
433 /* Set up Dos Device Map from the Parent */
434 ObInheritDeviceMap(Parent, Process);
435
436 /* Check if we have a parent */
437 if (Parent)
438 {
439 /* Inherit PID and Hard Error Processing */
440 Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
441 Process->DefaultHardErrorProcessing = Parent->
442 DefaultHardErrorProcessing;
443 }
444 else
445 {
446 /* Use default hard error processing */
447 Process->DefaultHardErrorProcessing = TRUE;
448 }
449
450 /* Check for a section handle */
451 if (SectionHandle)
452 {
453 /* Get a pointer to it */
454 Status = ObReferenceObjectByHandle(SectionHandle,
455 SECTION_MAP_EXECUTE,
456 MmSectionObjectType,
457 PreviousMode,
458 (PVOID*)&SectionObject,
459 NULL);
460 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
461 }
462 else
463 {
464 /* Assume no section object */
465 SectionObject = NULL;
466
467 /* Is the parent the initial process?
468 * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */
469 if (Parent != PsInitialSystemProcess && (Parent != NULL))
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 #if MI_TRACE_PFNS
673 /* Copy the process name now that we have it */
674 memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
675 if (Process->Pcb.DirectoryTableBase[1]) memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
676 if (Process->WorkingSetPage) memcpy(MiGetPfnEntry(Process->WorkingSetPage)->ProcessName, Process->ImageFileName, 16);
677 #endif
678
679 /* Check if we have a section object and map the system DLL */
680 if (SectionObject) PspMapSystemDll(Process, NULL, FALSE);
681
682 /* Create a handle for the Process */
683 CidEntry.Object = Process;
684 CidEntry.GrantedAccess = 0;
685 Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
686 if (!Process->UniqueProcessId)
687 {
688 /* Fail */
689 Status = STATUS_INSUFFICIENT_RESOURCES;
690 goto CleanupWithRef;
691 }
692
693 /* Set the handle table PID */
694 Process->ObjectTable->UniqueProcessId = Process->UniqueProcessId;
695
696 /* Check if we need to audit */
697 if (SeDetailedAuditingWithToken(NULL)) SeAuditProcessCreate(Process);
698
699 /* Check if the parent had a job */
700 if ((Parent) && (Parent->Job))
701 {
702 /* FIXME: We need to insert this process */
703 DPRINT1("Jobs not yet supported\n");
704 ASSERT(FALSE);
705 }
706
707 /* Create PEB only for User-Mode Processes */
708 if ((Parent) && (NeedsPeb))
709 {
710 //
711 // Set up the initial PEB
712 //
713 RtlZeroMemory(&InitialPeb, sizeof(INITIAL_PEB));
714 InitialPeb.Mutant = (HANDLE)-1;
715 InitialPeb.ImageUsesLargePages = 0; // FIXME: Not yet supported
716
717 //
718 // Create it only if we have an image section
719 //
720 if (SectionHandle)
721 {
722 //
723 // Create it
724 //
725 Status = MmCreatePeb(Process, &InitialPeb, &Process->Peb);
726 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
727 }
728 else
729 {
730 //
731 // We have to clone it
732 //
733 ASSERTMSG("No support for cloning yet\n", FALSE);
734 }
735
736 }
737
738 /* The process can now be activated */
739 KeAcquireGuardedMutex(&PspActiveProcessMutex);
740 InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks);
741 KeReleaseGuardedMutex(&PspActiveProcessMutex);
742
743 /* Create an access state */
744 Status = SeCreateAccessStateEx(CurrentThread,
745 ((Parent) &&
746 (Parent == PsInitialSystemProcess)) ?
747 Parent : CurrentProcess,
748 &LocalAccessState,
749 &AuxData,
750 DesiredAccess,
751 &PsProcessType->TypeInfo.GenericMapping);
752 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
753
754 /* Insert the Process into the Object Directory */
755 Status = ObInsertObject(Process,
756 AccessState,
757 DesiredAccess,
758 1,
759 NULL,
760 &hProcess);
761
762 /* Free the access state */
763 if (AccessState) SeDeleteAccessState(AccessState);
764
765 /* Cleanup on failure */
766 if (!NT_SUCCESS(Status)) goto Cleanup;
767
768 /* Compute Quantum and Priority */
769 ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);
770 Process->Pcb.BasePriority =
771 (SCHAR)PspComputeQuantumAndPriority(Process,
772 PsProcessPriorityBackground,
773 &Quantum);
774 Process->Pcb.QuantumReset = Quantum;
775
776 /* Check if we have a parent other then the initial system process */
777 Process->GrantedAccess = PROCESS_TERMINATE;
778 if ((Parent) && (Parent != PsInitialSystemProcess))
779 {
780 /* Get the process's SD */
781 Status = ObGetObjectSecurity(Process,
782 &SecurityDescriptor,
783 &SdAllocated);
784 if (!NT_SUCCESS(Status))
785 {
786 /* We failed, close the handle and clean up */
787 ObCloseHandle(hProcess, PreviousMode);
788 goto CleanupWithRef;
789 }
790
791 /* Create the subject context */
792 SubjectContext.ProcessAuditId = Process;
793 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
794 SubjectContext.ClientToken = NULL;
795
796 /* Do the access check */
797 Result = SeAccessCheck(SecurityDescriptor,
798 &SubjectContext,
799 FALSE,
800 MAXIMUM_ALLOWED,
801 0,
802 NULL,
803 &PsProcessType->TypeInfo.GenericMapping,
804 PreviousMode,
805 &Process->GrantedAccess,
806 &AccessStatus);
807
808 /* Dereference the token and let go the SD */
809 ObFastDereferenceObject(&Process->Token,
810 SubjectContext.PrimaryToken);
811 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
812
813 /* Remove access if it failed */
814 if (!Result) Process->GrantedAccess = 0;
815
816 /* Give the process some basic access */
817 Process->GrantedAccess |= (PROCESS_VM_OPERATION |
818 PROCESS_VM_READ |
819 PROCESS_VM_WRITE |
820 PROCESS_QUERY_INFORMATION |
821 PROCESS_TERMINATE |
822 PROCESS_CREATE_THREAD |
823 PROCESS_DUP_HANDLE |
824 PROCESS_CREATE_PROCESS |
825 PROCESS_SET_INFORMATION |
826 STANDARD_RIGHTS_ALL |
827 PROCESS_SET_QUOTA);
828 }
829 else
830 {
831 /* Set full granted access */
832 Process->GrantedAccess = PROCESS_ALL_ACCESS;
833 }
834
835 /* Set the Creation Time */
836 KeQuerySystemTime(&Process->CreateTime);
837
838 /* Protect against bad user-mode pointer */
839 _SEH2_TRY
840 {
841 /* Save the process handle */
842 *ProcessHandle = hProcess;
843 }
844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
845 {
846 /* Get the exception code */
847 Status = _SEH2_GetExceptionCode();
848 }
849 _SEH2_END;
850
851 /* Run the Notification Routines */
852 PspRunCreateProcessNotifyRoutines(Process, TRUE);
853
854 /* If 12 processes have been created, enough of user-mode is ready */
855 if (++ProcessCount == 12) Ki386PerfEnd();
856
857 CleanupWithRef:
858 /*
859 * Dereference the process. For failures, kills the process and does
860 * cleanup present in PspDeleteProcess. For success, kills the extra
861 * reference added by ObInsertObject.
862 */
863 ObDereferenceObject(Process);
864
865 Cleanup:
866 /* Dereference the parent */
867 if (Parent) ObDereferenceObject(Parent);
868
869 /* Return status to caller */
870 return Status;
871 }
872
873 /* PUBLIC FUNCTIONS **********************************************************/
874
875 /*
876 * @implemented
877 */
878 NTSTATUS
879 NTAPI
880 PsCreateSystemProcess(OUT PHANDLE ProcessHandle,
881 IN ACCESS_MASK DesiredAccess,
882 IN POBJECT_ATTRIBUTES ObjectAttributes)
883 {
884 /* Call the internal API */
885 return PspCreateProcess(ProcessHandle,
886 DesiredAccess,
887 ObjectAttributes,
888 NULL,
889 0,
890 NULL,
891 NULL,
892 NULL,
893 FALSE);
894 }
895
896 /*
897 * @implemented
898 */
899 NTSTATUS
900 NTAPI
901 PsLookupProcessByProcessId(IN HANDLE ProcessId,
902 OUT PEPROCESS *Process)
903 {
904 PHANDLE_TABLE_ENTRY CidEntry;
905 PEPROCESS FoundProcess;
906 NTSTATUS Status = STATUS_INVALID_PARAMETER;
907 PAGED_CODE();
908 PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId);
909 KeEnterCriticalRegion();
910
911 /* Get the CID Handle Entry */
912 CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
913 if (CidEntry)
914 {
915 /* Get the Process */
916 FoundProcess = CidEntry->Object;
917
918 /* Make sure it's really a process */
919 if (FoundProcess->Pcb.Header.Type == ProcessObject)
920 {
921 /* Safe Reference and return it */
922 if (ObReferenceObjectSafe(FoundProcess))
923 {
924 *Process = FoundProcess;
925 Status = STATUS_SUCCESS;
926 }
927 }
928
929 /* Unlock the Entry */
930 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
931 }
932
933 /* Return to caller */
934 KeLeaveCriticalRegion();
935 return Status;
936 }
937
938 /*
939 * @implemented
940 */
941 NTSTATUS
942 NTAPI
943 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
944 OUT PEPROCESS *Process OPTIONAL,
945 OUT PETHREAD *Thread)
946 {
947 PHANDLE_TABLE_ENTRY CidEntry;
948 PETHREAD FoundThread;
949 NTSTATUS Status = STATUS_INVALID_CID;
950 PAGED_CODE();
951 PSTRACE(PS_PROCESS_DEBUG, "Cid: %p\n", Cid);
952 KeEnterCriticalRegion();
953
954 /* Get the CID Handle Entry */
955 CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread);
956 if (CidEntry)
957 {
958 /* Get the Process */
959 FoundThread = CidEntry->Object;
960
961 /* Make sure it's really a thread and this process' */
962 if ((FoundThread->Tcb.Header.Type == ThreadObject) &&
963 (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess))
964 {
965 /* Safe Reference and return it */
966 if (ObReferenceObjectSafe(FoundThread))
967 {
968 *Thread = FoundThread;
969 Status = STATUS_SUCCESS;
970
971 /* Check if we should return the Process too */
972 if (Process)
973 {
974 /* Return it and reference it */
975 *Process = FoundThread->ThreadsProcess;
976 ObReferenceObject(*Process);
977 }
978 }
979 }
980
981 /* Unlock the Entry */
982 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
983 }
984
985 /* Return to caller */
986 KeLeaveCriticalRegion();
987 return Status;
988 }
989
990 /*
991 * @implemented
992 */
993 LARGE_INTEGER
994 NTAPI
995 PsGetProcessExitTime(VOID)
996 {
997 return PsGetCurrentProcess()->ExitTime;
998 }
999
1000 /*
1001 * @implemented
1002 */
1003 LONGLONG
1004 NTAPI
1005 PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
1006 {
1007 return Process->CreateTime.QuadPart;
1008 }
1009
1010 /*
1011 * @implemented
1012 */
1013 PVOID
1014 NTAPI
1015 PsGetProcessDebugPort(PEPROCESS Process)
1016 {
1017 return Process->DebugPort;
1018 }
1019
1020 /*
1021 * @implemented
1022 */
1023 BOOLEAN
1024 NTAPI
1025 PsGetProcessExitProcessCalled(PEPROCESS Process)
1026 {
1027 return (BOOLEAN)Process->ProcessExiting;
1028 }
1029
1030 /*
1031 * @implemented
1032 */
1033 NTSTATUS
1034 NTAPI
1035 PsGetProcessExitStatus(PEPROCESS Process)
1036 {
1037 return Process->ExitStatus;
1038 }
1039
1040 /*
1041 * @implemented
1042 */
1043 HANDLE
1044 NTAPI
1045 PsGetProcessId(PEPROCESS Process)
1046 {
1047 return (HANDLE)Process->UniqueProcessId;
1048 }
1049
1050 /*
1051 * @implemented
1052 */
1053 LPSTR
1054 NTAPI
1055 PsGetProcessImageFileName(PEPROCESS Process)
1056 {
1057 return (LPSTR)Process->ImageFileName;
1058 }
1059
1060 /*
1061 * @implemented
1062 */
1063 HANDLE
1064 NTAPI
1065 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
1066 {
1067 return Process->InheritedFromUniqueProcessId;
1068 }
1069
1070 /*
1071 * @implemented
1072 */
1073 PEJOB
1074 NTAPI
1075 PsGetProcessJob(PEPROCESS Process)
1076 {
1077 return Process->Job;
1078 }
1079
1080 /*
1081 * @implemented
1082 */
1083 PPEB
1084 NTAPI
1085 PsGetProcessPeb(PEPROCESS Process)
1086 {
1087 return Process->Peb;
1088 }
1089
1090 /*
1091 * @implemented
1092 */
1093 ULONG
1094 NTAPI
1095 PsGetProcessPriorityClass(PEPROCESS Process)
1096 {
1097 return Process->PriorityClass;
1098 }
1099
1100 /*
1101 * @implemented
1102 */
1103 HANDLE
1104 NTAPI
1105 PsGetCurrentProcessId(VOID)
1106 {
1107 return (HANDLE)PsGetCurrentProcess()->UniqueProcessId;
1108 }
1109
1110 /*
1111 * @implemented
1112 */
1113 ULONG
1114 NTAPI
1115 PsGetCurrentProcessSessionId(VOID)
1116 {
1117 return MmGetSessionId(PsGetCurrentProcess());
1118 }
1119
1120 /*
1121 * @implemented
1122 */
1123 PVOID
1124 NTAPI
1125 PsGetProcessSectionBaseAddress(PEPROCESS Process)
1126 {
1127 return Process->SectionBaseAddress;
1128 }
1129
1130 /*
1131 * @implemented
1132 */
1133 PVOID
1134 NTAPI
1135 PsGetProcessSecurityPort(PEPROCESS Process)
1136 {
1137 return Process->SecurityPort;
1138 }
1139
1140 /*
1141 * @implemented
1142 */
1143 HANDLE
1144 NTAPI
1145 PsGetProcessSessionId(PEPROCESS Process)
1146 {
1147 return (HANDLE)Process->Session;
1148 }
1149
1150 /*
1151 * @implemented
1152 */
1153 PVOID
1154 NTAPI
1155 PsGetCurrentProcessWin32Process(VOID)
1156 {
1157 return PsGetCurrentProcess()->Win32Process;
1158 }
1159
1160 /*
1161 * @implemented
1162 */
1163 PVOID
1164 NTAPI
1165 PsGetProcessWin32Process(PEPROCESS Process)
1166 {
1167 return Process->Win32Process;
1168 }
1169
1170 /*
1171 * @implemented
1172 */
1173 PVOID
1174 NTAPI
1175 PsGetProcessWin32WindowStation(PEPROCESS Process)
1176 {
1177 return Process->Win32WindowStation;
1178 }
1179
1180 /*
1181 * @implemented
1182 */
1183 BOOLEAN
1184 NTAPI
1185 PsIsProcessBeingDebugged(PEPROCESS Process)
1186 {
1187 return Process->DebugPort != NULL;
1188 }
1189
1190 /*
1191 * @implemented
1192 */
1193 BOOLEAN
1194 NTAPI
1195 PsIsSystemProcess(IN PEPROCESS Process)
1196 {
1197 /* Return if this is the System Process */
1198 return Process == PsInitialSystemProcess;
1199 }
1200
1201 /*
1202 * @implemented
1203 */
1204 VOID
1205 NTAPI
1206 PsSetProcessPriorityClass(PEPROCESS Process,
1207 ULONG PriorityClass)
1208 {
1209 Process->PriorityClass = (UCHAR)PriorityClass;
1210 }
1211
1212 /*
1213 * @implemented
1214 */
1215 VOID
1216 NTAPI
1217 PsSetProcessSecurityPort(PEPROCESS Process,
1218 PVOID SecurityPort)
1219 {
1220 Process->SecurityPort = SecurityPort;
1221 }
1222
1223 /*
1224 * @implemented
1225 */
1226 VOID
1227 NTAPI
1228 PsSetProcessWin32Process(PEPROCESS Process,
1229 PVOID Win32Process)
1230 {
1231 Process->Win32Process = Win32Process;
1232 }
1233
1234 /*
1235 * @implemented
1236 */
1237 VOID
1238 NTAPI
1239 PsSetProcessWindowStation(PEPROCESS Process,
1240 PVOID WindowStation)
1241 {
1242 Process->Win32WindowStation = WindowStation;
1243 }
1244
1245 /*
1246 * @implemented
1247 */
1248 VOID
1249 NTAPI
1250 PsSetProcessPriorityByClass(IN PEPROCESS Process,
1251 IN PSPROCESSPRIORITYMODE Type)
1252 {
1253 UCHAR Quantum;
1254 ULONG Priority;
1255 PSTRACE(PS_PROCESS_DEBUG, "Process: %p Type: %lx\n", Process, Type);
1256
1257 /* Compute quantum and priority */
1258 Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
1259
1260 /* Set them */
1261 KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);
1262 }
1263
1264 /*
1265 * @implemented
1266 */
1267 NTSTATUS
1268 NTAPI
1269 NtCreateProcessEx(OUT PHANDLE ProcessHandle,
1270 IN ACCESS_MASK DesiredAccess,
1271 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1272 IN HANDLE ParentProcess,
1273 IN ULONG Flags,
1274 IN HANDLE SectionHandle OPTIONAL,
1275 IN HANDLE DebugPort OPTIONAL,
1276 IN HANDLE ExceptionPort OPTIONAL,
1277 IN BOOLEAN InJob)
1278 {
1279 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1280 NTSTATUS Status;
1281 PAGED_CODE();
1282 PSTRACE(PS_PROCESS_DEBUG,
1283 "ParentProcess: %p Flags: %lx\n", ParentProcess, Flags);
1284
1285 /* Check if we came from user mode */
1286 if (PreviousMode != KernelMode)
1287 {
1288 _SEH2_TRY
1289 {
1290 /* Probe process handle */
1291 ProbeForWriteHandle(ProcessHandle);
1292 }
1293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1294 {
1295 /* Return the exception code */
1296 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1297 }
1298 _SEH2_END;
1299 }
1300
1301 /* Make sure there's a parent process */
1302 if (!ParentProcess)
1303 {
1304 /* Can't create System Processes like this */
1305 Status = STATUS_INVALID_PARAMETER;
1306 }
1307 else
1308 {
1309 /* Create a user Process */
1310 Status = PspCreateProcess(ProcessHandle,
1311 DesiredAccess,
1312 ObjectAttributes,
1313 ParentProcess,
1314 Flags,
1315 SectionHandle,
1316 DebugPort,
1317 ExceptionPort,
1318 InJob);
1319 }
1320
1321 /* Return Status */
1322 return Status;
1323 }
1324
1325 /*
1326 * @implemented
1327 */
1328 NTSTATUS
1329 NTAPI
1330 NtCreateProcess(OUT PHANDLE ProcessHandle,
1331 IN ACCESS_MASK DesiredAccess,
1332 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1333 IN HANDLE ParentProcess,
1334 IN BOOLEAN InheritObjectTable,
1335 IN HANDLE SectionHandle OPTIONAL,
1336 IN HANDLE DebugPort OPTIONAL,
1337 IN HANDLE ExceptionPort OPTIONAL)
1338 {
1339 ULONG Flags = 0;
1340 PSTRACE(PS_PROCESS_DEBUG,
1341 "Parent: %p Attributes: %p\n", ParentProcess, ObjectAttributes);
1342
1343 /* Set new-style flags */
1344 if ((ULONG)SectionHandle & 1) Flags = PS_REQUEST_BREAKAWAY;
1345 if ((ULONG)DebugPort & 1) Flags |= PS_NO_DEBUG_INHERIT;
1346 if (InheritObjectTable) Flags |= PS_INHERIT_HANDLES;
1347
1348 /* Call the new API */
1349 return NtCreateProcessEx(ProcessHandle,
1350 DesiredAccess,
1351 ObjectAttributes,
1352 ParentProcess,
1353 Flags,
1354 SectionHandle,
1355 DebugPort,
1356 ExceptionPort,
1357 FALSE);
1358 }
1359
1360 /*
1361 * @implemented
1362 */
1363 NTSTATUS
1364 NTAPI
1365 NtOpenProcess(OUT PHANDLE ProcessHandle,
1366 IN ACCESS_MASK DesiredAccess,
1367 IN POBJECT_ATTRIBUTES ObjectAttributes,
1368 IN PCLIENT_ID ClientId)
1369 {
1370 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1371 CLIENT_ID SafeClientId;
1372 ULONG Attributes = 0;
1373 HANDLE hProcess;
1374 BOOLEAN HasObjectName = FALSE;
1375 PETHREAD Thread = NULL;
1376 PEPROCESS Process = NULL;
1377 NTSTATUS Status;
1378 ACCESS_STATE AccessState;
1379 AUX_ACCESS_DATA AuxData;
1380 PAGED_CODE();
1381 PSTRACE(PS_PROCESS_DEBUG,
1382 "ClientId: %p Attributes: %p\n", ClientId, ObjectAttributes);
1383
1384 /* Check if we were called from user mode */
1385 if (PreviousMode != KernelMode)
1386 {
1387 /* Enter SEH for probing */
1388 _SEH2_TRY
1389 {
1390 /* Probe the thread handle */
1391 ProbeForWriteHandle(ProcessHandle);
1392
1393 /* Check for a CID structure */
1394 if (ClientId)
1395 {
1396 /* Probe and capture it */
1397 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
1398 SafeClientId = *ClientId;
1399 ClientId = &SafeClientId;
1400 }
1401
1402 /*
1403 * Just probe the object attributes structure, don't capture it
1404 * completely. This is done later if necessary
1405 */
1406 ProbeForRead(ObjectAttributes,
1407 sizeof(OBJECT_ATTRIBUTES),
1408 sizeof(ULONG));
1409 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1410 Attributes = ObjectAttributes->Attributes;
1411 }
1412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1413 {
1414 /* Return the exception code */
1415 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1416 }
1417 _SEH2_END;
1418 }
1419 else
1420 {
1421 /* Otherwise just get the data directly */
1422 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1423 Attributes = ObjectAttributes->Attributes;
1424 }
1425
1426 /* Can't pass both, fail */
1427 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1428
1429 /* Create an access state */
1430 Status = SeCreateAccessState(&AccessState,
1431 &AuxData,
1432 DesiredAccess,
1433 &PsProcessType->TypeInfo.GenericMapping);
1434 if (!NT_SUCCESS(Status)) return Status;
1435
1436 /* Check if this is a debugger */
1437 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1438 {
1439 /* Did he want full access? */
1440 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1441 {
1442 /* Give it to him */
1443 AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
1444 }
1445 else
1446 {
1447 /* Otherwise just give every other access he could want */
1448 AccessState.PreviouslyGrantedAccess |=
1449 AccessState.RemainingDesiredAccess;
1450 }
1451
1452 /* The caller desires nothing else now */
1453 AccessState.RemainingDesiredAccess = 0;
1454 }
1455
1456 /* Open by name if one was given */
1457 if (HasObjectName)
1458 {
1459 /* Open it */
1460 Status = ObOpenObjectByName(ObjectAttributes,
1461 PsProcessType,
1462 PreviousMode,
1463 &AccessState,
1464 0,
1465 NULL,
1466 &hProcess);
1467
1468 /* Get rid of the access state */
1469 SeDeleteAccessState(&AccessState);
1470 }
1471 else if (ClientId)
1472 {
1473 /* Open by Thread ID */
1474 if (ClientId->UniqueThread)
1475 {
1476 /* Get the Process */
1477 Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread);
1478 }
1479 else
1480 {
1481 /* Get the Process */
1482 Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
1483 &Process);
1484 }
1485
1486 /* Check if we didn't find anything */
1487 if (!NT_SUCCESS(Status))
1488 {
1489 /* Get rid of the access state and return */
1490 SeDeleteAccessState(&AccessState);
1491 return Status;
1492 }
1493
1494 /* Open the Process Object */
1495 Status = ObOpenObjectByPointer(Process,
1496 Attributes,
1497 &AccessState,
1498 0,
1499 PsProcessType,
1500 PreviousMode,
1501 &hProcess);
1502
1503 /* Delete the access state */
1504 SeDeleteAccessState(&AccessState);
1505
1506 /* Dereference the thread if we used it */
1507 if (Thread) ObDereferenceObject(Thread);
1508
1509 /* Dereference the Process */
1510 ObDereferenceObject(Process);
1511 }
1512 else
1513 {
1514 /* neither an object name nor a client id was passed */
1515 return STATUS_INVALID_PARAMETER_MIX;
1516 }
1517
1518 /* Check for success */
1519 if (NT_SUCCESS(Status))
1520 {
1521 /* Use SEH for write back */
1522 _SEH2_TRY
1523 {
1524 /* Write back the handle */
1525 *ProcessHandle = hProcess;
1526 }
1527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1528 {
1529 /* Get the exception code */
1530 Status = _SEH2_GetExceptionCode();
1531 }
1532 _SEH2_END;
1533 }
1534
1535 /* Return status */
1536 return Status;
1537 }
1538 /* EOF */