The real, definitive, Visual C++ support branch. Accept no substitutes
[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 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 = 2;
205 i = PsPrioritySeparation;
206 }
207 else
208 {
209 /* Set the background memory priority and no separation */
210 MemoryPriority = 0;
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 /* Ineherit 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_TIMEOUT;
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 _SEH_TRY
814 {
815 /* Save the process handle */
816 *ProcessHandle = hProcess;
817 }
818 _SEH_HANDLE
819 {
820 /* Get the exception code */
821 Status = _SEH_GetExceptionCode();
822 }
823 _SEH_END;
824
825 CleanupWithRef:
826 /*
827 * Dereference the process. For failures, kills the process and does
828 * cleanup present in PspDeleteProcess. For success, kills the extra
829 * reference added by ObInsertObject.
830 */
831 ObDereferenceObject(Process);
832
833 Cleanup:
834 /* Dereference the parent */
835 if (Parent) ObDereferenceObject(Parent);
836
837 /* Return status to caller */
838 return Status;
839 }
840
841 /* PUBLIC FUNCTIONS **********************************************************/
842
843 /*
844 * @implemented
845 */
846 NTSTATUS
847 NTAPI
848 PsCreateSystemProcess(OUT PHANDLE ProcessHandle,
849 IN ACCESS_MASK DesiredAccess,
850 IN POBJECT_ATTRIBUTES ObjectAttributes)
851 {
852 /* Call the internal API */
853 return PspCreateProcess(ProcessHandle,
854 DesiredAccess,
855 ObjectAttributes,
856 NULL,
857 0,
858 NULL,
859 NULL,
860 NULL,
861 FALSE);
862 }
863
864 /*
865 * @implemented
866 */
867 NTSTATUS
868 NTAPI
869 PsLookupProcessByProcessId(IN HANDLE ProcessId,
870 OUT PEPROCESS *Process)
871 {
872 PHANDLE_TABLE_ENTRY CidEntry;
873 PEPROCESS FoundProcess;
874 NTSTATUS Status = STATUS_INVALID_PARAMETER;
875 PAGED_CODE();
876 PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId);
877 KeEnterCriticalRegion();
878
879 /* Get the CID Handle Entry */
880 CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
881 if (CidEntry)
882 {
883 /* Get the Process */
884 FoundProcess = CidEntry->Object;
885
886 /* Make sure it's really a process */
887 if (FoundProcess->Pcb.Header.Type == ProcessObject)
888 {
889 /* Safe Reference and return it */
890 if (ObReferenceObjectSafe(FoundProcess))
891 {
892 *Process = FoundProcess;
893 Status = STATUS_SUCCESS;
894 }
895 }
896
897 /* Unlock the Entry */
898 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
899 }
900
901 /* Return to caller */
902 KeLeaveCriticalRegion();
903 return Status;
904 }
905
906 /*
907 * @implemented
908 */
909 NTSTATUS
910 NTAPI
911 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
912 OUT PEPROCESS *Process OPTIONAL,
913 OUT PETHREAD *Thread)
914 {
915 PHANDLE_TABLE_ENTRY CidEntry;
916 PETHREAD FoundThread;
917 NTSTATUS Status = STATUS_INVALID_CID;
918 PAGED_CODE();
919 PSTRACE(PS_PROCESS_DEBUG, "Cid: %p\n", Cid);
920 KeEnterCriticalRegion();
921
922 /* Get the CID Handle Entry */
923 CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread);
924 if (CidEntry)
925 {
926 /* Get the Process */
927 FoundThread = CidEntry->Object;
928
929 /* Make sure it's really a thread and this process' */
930 if ((FoundThread->Tcb.DispatcherHeader.Type == ThreadObject) &&
931 (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess))
932 {
933 /* Safe Reference and return it */
934 if (ObReferenceObjectSafe(FoundThread))
935 {
936 *Thread = FoundThread;
937 Status = STATUS_SUCCESS;
938
939 /* Check if we should return the Process too */
940 if (Process)
941 {
942 /* Return it and reference it */
943 *Process = FoundThread->ThreadsProcess;
944 ObReferenceObject(*Process);
945 }
946 }
947 }
948
949 /* Unlock the Entry */
950 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
951 }
952
953 /* Return to caller */
954 KeLeaveCriticalRegion();
955 return Status;
956 }
957
958 /*
959 * @implemented
960 */
961 LARGE_INTEGER
962 NTAPI
963 PsGetProcessExitTime(VOID)
964 {
965 return PsGetCurrentProcess()->ExitTime;
966 }
967
968 /*
969 * @implemented
970 */
971 LONGLONG
972 NTAPI
973 PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
974 {
975 return Process->CreateTime.QuadPart;
976 }
977
978 /*
979 * @implemented
980 */
981 PVOID
982 NTAPI
983 PsGetProcessDebugPort(PEPROCESS Process)
984 {
985 return Process->DebugPort;
986 }
987
988 /*
989 * @implemented
990 */
991 BOOLEAN
992 NTAPI
993 PsGetProcessExitProcessCalled(PEPROCESS Process)
994 {
995 return (BOOLEAN)Process->ProcessExiting;
996 }
997
998 /*
999 * @implemented
1000 */
1001 NTSTATUS
1002 NTAPI
1003 PsGetProcessExitStatus(PEPROCESS Process)
1004 {
1005 return Process->ExitStatus;
1006 }
1007
1008 /*
1009 * @implemented
1010 */
1011 HANDLE
1012 NTAPI
1013 PsGetProcessId(PEPROCESS Process)
1014 {
1015 return (HANDLE)Process->UniqueProcessId;
1016 }
1017
1018 /*
1019 * @implemented
1020 */
1021 LPSTR
1022 NTAPI
1023 PsGetProcessImageFileName(PEPROCESS Process)
1024 {
1025 return (LPSTR)Process->ImageFileName;
1026 }
1027
1028 /*
1029 * @implemented
1030 */
1031 HANDLE
1032 NTAPI
1033 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
1034 {
1035 return Process->InheritedFromUniqueProcessId;
1036 }
1037
1038 /*
1039 * @implemented
1040 */
1041 PEJOB
1042 NTAPI
1043 PsGetProcessJob(PEPROCESS Process)
1044 {
1045 return Process->Job;
1046 }
1047
1048 /*
1049 * @implemented
1050 */
1051 PPEB
1052 NTAPI
1053 PsGetProcessPeb(PEPROCESS Process)
1054 {
1055 return Process->Peb;
1056 }
1057
1058 /*
1059 * @implemented
1060 */
1061 ULONG
1062 NTAPI
1063 PsGetProcessPriorityClass(PEPROCESS Process)
1064 {
1065 return Process->PriorityClass;
1066 }
1067
1068 /*
1069 * @implemented
1070 */
1071 HANDLE
1072 NTAPI
1073 PsGetCurrentProcessId(VOID)
1074 {
1075 return (HANDLE)PsGetCurrentProcess()->UniqueProcessId;
1076 }
1077
1078 /*
1079 * @implemented
1080 */
1081 ULONG
1082 NTAPI
1083 PsGetCurrentProcessSessionId(VOID)
1084 {
1085 return PsGetCurrentProcess()->Session;
1086 }
1087
1088 /*
1089 * @implemented
1090 */
1091 PVOID
1092 NTAPI
1093 PsGetProcessSectionBaseAddress(PEPROCESS Process)
1094 {
1095 return Process->SectionBaseAddress;
1096 }
1097
1098 /*
1099 * @implemented
1100 */
1101 PVOID
1102 NTAPI
1103 PsGetProcessSecurityPort(PEPROCESS Process)
1104 {
1105 return Process->SecurityPort;
1106 }
1107
1108 /*
1109 * @implemented
1110 */
1111 HANDLE
1112 NTAPI
1113 PsGetProcessSessionId(PEPROCESS Process)
1114 {
1115 return (HANDLE)Process->Session;
1116 }
1117
1118 /*
1119 * @implemented
1120 */
1121 PVOID
1122 NTAPI
1123 PsGetCurrentProcessWin32Process(VOID)
1124 {
1125 return PsGetCurrentProcess()->Win32Process;
1126 }
1127
1128 /*
1129 * @implemented
1130 */
1131 PVOID
1132 NTAPI
1133 PsGetProcessWin32Process(PEPROCESS Process)
1134 {
1135 return Process->Win32Process;
1136 }
1137
1138 /*
1139 * @implemented
1140 */
1141 PVOID
1142 NTAPI
1143 PsGetProcessWin32WindowStation(PEPROCESS Process)
1144 {
1145 return Process->Win32WindowStation;
1146 }
1147
1148 /*
1149 * @implemented
1150 */
1151 BOOLEAN
1152 NTAPI
1153 PsIsProcessBeingDebugged(PEPROCESS Process)
1154 {
1155 return Process->DebugPort != NULL;
1156 }
1157
1158 /*
1159 * @implemented
1160 */
1161 BOOLEAN
1162 NTAPI
1163 PsIsSystemProcess(IN PEPROCESS Process)
1164 {
1165 /* Return if this is the System Process */
1166 return Process == PsInitialSystemProcess;
1167 }
1168
1169 /*
1170 * @implemented
1171 */
1172 VOID
1173 NTAPI
1174 PsSetProcessPriorityClass(PEPROCESS Process,
1175 ULONG PriorityClass)
1176 {
1177 Process->PriorityClass = (UCHAR)PriorityClass;
1178 }
1179
1180 /*
1181 * @implemented
1182 */
1183 VOID
1184 NTAPI
1185 PsSetProcessSecurityPort(PEPROCESS Process,
1186 PVOID SecurityPort)
1187 {
1188 Process->SecurityPort = SecurityPort;
1189 }
1190
1191 /*
1192 * @implemented
1193 */
1194 VOID
1195 NTAPI
1196 PsSetProcessWin32Process(PEPROCESS Process,
1197 PVOID Win32Process)
1198 {
1199 Process->Win32Process = Win32Process;
1200 }
1201
1202 /*
1203 * @implemented
1204 */
1205 VOID
1206 NTAPI
1207 PsSetProcessWindowStation(PEPROCESS Process,
1208 PVOID WindowStation)
1209 {
1210 Process->Win32WindowStation = WindowStation;
1211 }
1212
1213 /*
1214 * @implemented
1215 */
1216 VOID
1217 NTAPI
1218 PsSetProcessPriorityByClass(IN PEPROCESS Process,
1219 IN PSPROCESSPRIORITYMODE Type)
1220 {
1221 UCHAR Quantum;
1222 ULONG Priority;
1223 PSTRACE(PS_PROCESS_DEBUG, "Process: %p Type: %lx\n", Process, Type);
1224
1225 /* Compute quantum and priority */
1226 Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
1227
1228 /* Set them */
1229 KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);
1230 }
1231
1232 /*
1233 * @implemented
1234 */
1235 NTSTATUS
1236 NTAPI
1237 NtCreateProcessEx(OUT PHANDLE ProcessHandle,
1238 IN ACCESS_MASK DesiredAccess,
1239 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1240 IN HANDLE ParentProcess,
1241 IN ULONG Flags,
1242 IN HANDLE SectionHandle OPTIONAL,
1243 IN HANDLE DebugPort OPTIONAL,
1244 IN HANDLE ExceptionPort OPTIONAL,
1245 IN BOOLEAN InJob)
1246 {
1247 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1248 NTSTATUS Status = STATUS_SUCCESS;
1249 PAGED_CODE();
1250 PSTRACE(PS_PROCESS_DEBUG,
1251 "ParentProcess: %p Flags: %lx\n", ParentProcess, Flags);
1252
1253 /* Check if we came from user mode */
1254 if(PreviousMode != KernelMode)
1255 {
1256 _SEH_TRY
1257 {
1258 /* Probe process handle */
1259 ProbeForWriteHandle(ProcessHandle);
1260 }
1261 _SEH_HANDLE
1262 {
1263 /* Get exception code */
1264 Status = _SEH_GetExceptionCode();
1265 }
1266 _SEH_END;
1267 if (!NT_SUCCESS(Status)) return Status;
1268 }
1269
1270 /* Make sure there's a parent process */
1271 if (!ParentProcess)
1272 {
1273 /* Can't create System Processes like this */
1274 Status = STATUS_INVALID_PARAMETER;
1275 }
1276 else
1277 {
1278 /* Create a user Process */
1279 Status = PspCreateProcess(ProcessHandle,
1280 DesiredAccess,
1281 ObjectAttributes,
1282 ParentProcess,
1283 Flags,
1284 SectionHandle,
1285 DebugPort,
1286 ExceptionPort,
1287 InJob);
1288 }
1289
1290 /* Return Status */
1291 return Status;
1292 }
1293
1294 /*
1295 * @implemented
1296 */
1297 NTSTATUS
1298 NTAPI
1299 NtCreateProcess(OUT PHANDLE ProcessHandle,
1300 IN ACCESS_MASK DesiredAccess,
1301 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1302 IN HANDLE ParentProcess,
1303 IN BOOLEAN InheritObjectTable,
1304 IN HANDLE SectionHandle OPTIONAL,
1305 IN HANDLE DebugPort OPTIONAL,
1306 IN HANDLE ExceptionPort OPTIONAL)
1307 {
1308 ULONG Flags = 0;
1309 PSTRACE(PS_PROCESS_DEBUG,
1310 "Parent: %p Attributes: %p\n", ParentProcess, ObjectAttributes);
1311
1312 /* Set new-style flags */
1313 if ((ULONG)SectionHandle & 1) Flags = PS_REQUEST_BREAKAWAY;
1314 if ((ULONG)DebugPort & 1) Flags |= PS_NO_DEBUG_INHERIT;
1315 if (InheritObjectTable) Flags |= PS_INHERIT_HANDLES;
1316
1317 /* Call the new API */
1318 return NtCreateProcessEx(ProcessHandle,
1319 DesiredAccess,
1320 ObjectAttributes,
1321 ParentProcess,
1322 Flags,
1323 SectionHandle,
1324 DebugPort,
1325 ExceptionPort,
1326 FALSE);
1327 }
1328
1329 /*
1330 * @implemented
1331 */
1332 NTSTATUS
1333 NTAPI
1334 NtOpenProcess(OUT PHANDLE ProcessHandle,
1335 IN ACCESS_MASK DesiredAccess,
1336 IN POBJECT_ATTRIBUTES ObjectAttributes,
1337 IN PCLIENT_ID ClientId)
1338 {
1339 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1340 CLIENT_ID SafeClientId;
1341 ULONG Attributes = 0;
1342 HANDLE hProcess;
1343 BOOLEAN HasObjectName = FALSE;
1344 PETHREAD Thread = NULL;
1345 PEPROCESS Process = NULL;
1346 NTSTATUS Status = STATUS_SUCCESS;
1347 ACCESS_STATE AccessState;
1348 AUX_ACCESS_DATA AuxData;
1349 PAGED_CODE();
1350 PSTRACE(PS_PROCESS_DEBUG,
1351 "ClientId: %p Attributes: %p\n", ClientId, ObjectAttributes);
1352
1353 /* Check if we were called from user mode */
1354 if (PreviousMode != KernelMode)
1355 {
1356 /* Enter SEH for probing */
1357 _SEH_TRY
1358 {
1359 /* Probe the thread handle */
1360 ProbeForWriteHandle(ProcessHandle);
1361
1362 /* Check for a CID structure */
1363 if (ClientId)
1364 {
1365 /* Probe and capture it */
1366 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
1367 SafeClientId = *ClientId;
1368 ClientId = &SafeClientId;
1369 }
1370
1371 /*
1372 * Just probe the object attributes structure, don't capture it
1373 * completely. This is done later if necessary
1374 */
1375 ProbeForRead(ObjectAttributes,
1376 sizeof(OBJECT_ATTRIBUTES),
1377 sizeof(ULONG));
1378 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1379 Attributes = ObjectAttributes->Attributes;
1380 }
1381 _SEH_HANDLE
1382 {
1383 /* Get the exception code */
1384 Status = _SEH_GetExceptionCode();
1385 }
1386 _SEH_END;
1387 if (!NT_SUCCESS(Status)) return Status;
1388 }
1389 else
1390 {
1391 /* Otherwise just get the data directly */
1392 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1393 Attributes = ObjectAttributes->Attributes;
1394 }
1395
1396 /* Can't pass both, fail */
1397 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1398
1399 /* Create an access state */
1400 Status = SeCreateAccessState(&AccessState,
1401 &AuxData,
1402 DesiredAccess,
1403 &PsProcessType->TypeInfo.GenericMapping);
1404 if (!NT_SUCCESS(Status)) return Status;
1405
1406 /* Check if this is a debugger */
1407 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1408 {
1409 /* Did he want full access? */
1410 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1411 {
1412 /* Give it to him */
1413 AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
1414 }
1415 else
1416 {
1417 /* Otherwise just give every other access he could want */
1418 AccessState.PreviouslyGrantedAccess |=
1419 AccessState.RemainingDesiredAccess;
1420 }
1421
1422 /* The caller desires nothing else now */
1423 AccessState.RemainingDesiredAccess = 0;
1424 }
1425
1426 /* Open by name if one was given */
1427 if (HasObjectName)
1428 {
1429 /* Open it */
1430 Status = ObOpenObjectByName(ObjectAttributes,
1431 PsProcessType,
1432 PreviousMode,
1433 &AccessState,
1434 0,
1435 NULL,
1436 &hProcess);
1437
1438 /* Get rid of the access state */
1439 SeDeleteAccessState(&AccessState);
1440 }
1441 else if (ClientId)
1442 {
1443 /* Open by Thread ID */
1444 if (ClientId->UniqueThread)
1445 {
1446 /* Get the Process */
1447 Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread);
1448 }
1449 else
1450 {
1451 /* Get the Process */
1452 Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
1453 &Process);
1454 }
1455
1456 /* Check if we didn't find anything */
1457 if (!NT_SUCCESS(Status))
1458 {
1459 /* Get rid of the access state and return */
1460 SeDeleteAccessState(&AccessState);
1461 return Status;
1462 }
1463
1464 /* Open the Process Object */
1465 Status = ObOpenObjectByPointer(Process,
1466 Attributes,
1467 &AccessState,
1468 0,
1469 PsProcessType,
1470 PreviousMode,
1471 &hProcess);
1472
1473 /* Delete the access state */
1474 SeDeleteAccessState(&AccessState);
1475
1476 /* Dereference the thread if we used it */
1477 if (Thread) ObDereferenceObject(Thread);
1478
1479 /* Dereference the Process */
1480 ObDereferenceObject(Process);
1481 }
1482 else
1483 {
1484 /* neither an object name nor a client id was passed */
1485 return STATUS_INVALID_PARAMETER_MIX;
1486 }
1487
1488 /* Check for success */
1489 if (NT_SUCCESS(Status))
1490 {
1491 /* Use SEH for write back */
1492 _SEH_TRY
1493 {
1494 /* Write back the handle */
1495 *ProcessHandle = hProcess;
1496 }
1497 _SEH_HANDLE
1498 {
1499 /* Get the exception code */
1500 Status = _SEH_GetExceptionCode();
1501 }
1502 _SEH_END;
1503 }
1504
1505 /* Return status */
1506 return Status;
1507 }
1508 /* EOF */