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