2004-08-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / ps / process.c
1 /* $Id: process.c,v 1.139 2004/08/15 16:39:10 chorns Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/process.c
6 * PURPOSE: Process managment
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * REVISION HISTORY:
9 * 21/07/98: Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /* GLOBALS ******************************************************************/
20
21 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
22 HANDLE SystemProcessHandle = NULL;
23
24 POBJECT_TYPE EXPORTED PsProcessType = NULL;
25
26 LIST_ENTRY PsProcessListHead;
27 static KSPIN_LOCK PsProcessListLock;
28 static ULONG PiNextProcessUniqueId = 0;
29
30 static GENERIC_MAPPING PiProcessMapping = {PROCESS_READ,
31 PROCESS_WRITE,
32 PROCESS_EXECUTE,
33 PROCESS_ALL_ACCESS};
34
35 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8
36 #define MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT 8
37
38 static PCREATE_PROCESS_NOTIFY_ROUTINE
39 PiProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
40 static PLOAD_IMAGE_NOTIFY_ROUTINE
41 PiLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT];
42
43
44 typedef struct
45 {
46 WORK_QUEUE_ITEM WorkQueueItem;
47 KEVENT Event;
48 PEPROCESS Process;
49 BOOLEAN IsWorkerQueue;
50 } DEL_CONTEXT, *PDEL_CONTEXT;
51
52 /* FUNCTIONS *****************************************************************/
53
54 PEPROCESS
55 PsGetNextProcess(PEPROCESS OldProcess)
56 {
57 KIRQL oldIrql;
58 PEPROCESS NextProcess;
59 NTSTATUS Status;
60
61 if (OldProcess == NULL)
62 {
63 Status = ObReferenceObjectByPointer(PsInitialSystemProcess,
64 PROCESS_ALL_ACCESS,
65 PsProcessType,
66 KernelMode);
67 if (!NT_SUCCESS(Status))
68 {
69 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsInitialSystemProcess\n");
70 KEBUGCHECK(0);
71 }
72 return PsInitialSystemProcess;
73 }
74
75 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
76 NextProcess = OldProcess;
77 while (1)
78 {
79 if (NextProcess->ProcessListEntry.Blink == &PsProcessListHead)
80 {
81 NextProcess = CONTAINING_RECORD(PsProcessListHead.Blink,
82 EPROCESS,
83 ProcessListEntry);
84 }
85 else
86 {
87 NextProcess = CONTAINING_RECORD(NextProcess->ProcessListEntry.Blink,
88 EPROCESS,
89 ProcessListEntry);
90 }
91 Status = ObReferenceObjectByPointer(NextProcess,
92 PROCESS_ALL_ACCESS,
93 PsProcessType,
94 KernelMode);
95 if (NT_SUCCESS(Status))
96 {
97 break;
98 }
99 else if (Status == STATUS_PROCESS_IS_TERMINATING)
100 {
101 continue;
102 }
103 else if (!NT_SUCCESS(Status))
104 {
105 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
106 KEBUGCHECK(0);
107 }
108 }
109
110 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
111 ObDereferenceObject(OldProcess);
112
113 return(NextProcess);
114 }
115
116
117 NTSTATUS STDCALL
118 _NtOpenProcessToken(IN HANDLE ProcessHandle,
119 IN ACCESS_MASK DesiredAccess,
120 OUT PHANDLE TokenHandle)
121 {
122 PACCESS_TOKEN Token;
123 NTSTATUS Status;
124
125 Status = PsOpenTokenOfProcess(ProcessHandle,
126 &Token);
127 if (!NT_SUCCESS(Status))
128 {
129 return(Status);
130 }
131 Status = ObCreateHandle(PsGetCurrentProcess(),
132 Token,
133 DesiredAccess,
134 FALSE,
135 TokenHandle);
136 ObDereferenceObject(Token);
137 return(Status);
138 }
139
140
141 /*
142 * @implemented
143 */
144 NTSTATUS STDCALL
145 NtOpenProcessToken(IN HANDLE ProcessHandle,
146 IN ACCESS_MASK DesiredAccess,
147 OUT PHANDLE TokenHandle)
148 {
149 return _NtOpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle);
150 }
151
152 /*
153 * @unimplemented
154 */
155 NTSTATUS
156 STDCALL
157 NtOpenProcessTokenEx(
158 IN HANDLE ProcessHandle,
159 IN ACCESS_MASK DesiredAccess,
160 IN ULONG HandleAttributes,
161 OUT PHANDLE TokenHandle
162 )
163 {
164 UNIMPLEMENTED;
165 return STATUS_NOT_IMPLEMENTED;
166 }
167
168
169
170 /*
171 * @implemented
172 */
173 PACCESS_TOKEN STDCALL
174 PsReferencePrimaryToken(PEPROCESS Process)
175 {
176 ObReferenceObjectByPointer(Process->Token,
177 TOKEN_ALL_ACCESS,
178 SepTokenObjectType,
179 UserMode);
180 return(Process->Token);
181 }
182
183
184 NTSTATUS
185 PsOpenTokenOfProcess(HANDLE ProcessHandle,
186 PACCESS_TOKEN* Token)
187 {
188 PEPROCESS Process;
189 NTSTATUS Status;
190
191 Status = ObReferenceObjectByHandle(ProcessHandle,
192 PROCESS_QUERY_INFORMATION,
193 PsProcessType,
194 UserMode,
195 (PVOID*)&Process,
196 NULL);
197 if (!NT_SUCCESS(Status))
198 {
199 return(Status);
200 }
201 *Token = PsReferencePrimaryToken(Process);
202 ObDereferenceObject(Process);
203 return(STATUS_SUCCESS);
204 }
205
206
207 VOID
208 PiKillMostProcesses(VOID)
209 {
210 KIRQL oldIrql;
211 PLIST_ENTRY current_entry;
212 PEPROCESS current;
213
214 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
215
216 current_entry = PsProcessListHead.Flink;
217 while (current_entry != &PsProcessListHead)
218 {
219 current = CONTAINING_RECORD(current_entry, EPROCESS,
220 ProcessListEntry);
221 current_entry = current_entry->Flink;
222
223 if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId &&
224 current->UniqueProcessId != (ULONG)PsGetCurrentProcessId())
225 {
226 PiTerminateProcessThreads(current, STATUS_SUCCESS);
227 }
228 }
229
230 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
231 }
232
233
234 VOID INIT_FUNCTION
235 PsInitProcessManagment(VOID)
236 {
237 PKPROCESS KProcess;
238 KIRQL oldIrql;
239 NTSTATUS Status;
240
241 /*
242 * Register the process object type
243 */
244
245 PsProcessType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
246
247 PsProcessType->Tag = TAG('P', 'R', 'O', 'C');
248 PsProcessType->TotalObjects = 0;
249 PsProcessType->TotalHandles = 0;
250 PsProcessType->MaxObjects = ULONG_MAX;
251 PsProcessType->MaxHandles = ULONG_MAX;
252 PsProcessType->PagedPoolCharge = 0;
253 PsProcessType->NonpagedPoolCharge = sizeof(EPROCESS);
254 PsProcessType->Mapping = &PiProcessMapping;
255 PsProcessType->Dump = NULL;
256 PsProcessType->Open = NULL;
257 PsProcessType->Close = NULL;
258 PsProcessType->Delete = PiDeleteProcess;
259 PsProcessType->Parse = NULL;
260 PsProcessType->Security = NULL;
261 PsProcessType->QueryName = NULL;
262 PsProcessType->OkayToClose = NULL;
263 PsProcessType->Create = NULL;
264 PsProcessType->DuplicationNotify = NULL;
265
266 RtlRosInitUnicodeStringFromLiteral(&PsProcessType->TypeName, L"Process");
267
268 ObpCreateTypeObject(PsProcessType);
269
270 InitializeListHead(&PsProcessListHead);
271 KeInitializeSpinLock(&PsProcessListLock);
272
273 RtlZeroMemory(PiProcessNotifyRoutine, sizeof(PiProcessNotifyRoutine));
274 RtlZeroMemory(PiLoadImageNotifyRoutine, sizeof(PiLoadImageNotifyRoutine));
275
276 /*
277 * Initialize the system process
278 */
279 Status = ObCreateObject(KernelMode,
280 PsProcessType,
281 NULL,
282 KernelMode,
283 NULL,
284 sizeof(EPROCESS),
285 0,
286 0,
287 (PVOID*)&PsInitialSystemProcess);
288 if (!NT_SUCCESS(Status))
289 {
290 return;
291 }
292
293 /* System threads may run on any processor. */
294 PsInitialSystemProcess->Pcb.Affinity = 0xFFFFFFFF;
295 PsInitialSystemProcess->Pcb.IopmOffset = 0xffff;
296 PsInitialSystemProcess->Pcb.LdtDescriptor[0] = 0;
297 PsInitialSystemProcess->Pcb.LdtDescriptor[1] = 0;
298 PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIO_NORMAL;
299 KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader,
300 InternalProcessType,
301 sizeof(EPROCESS),
302 FALSE);
303 KProcess = &PsInitialSystemProcess->Pcb;
304
305 MmInitializeAddressSpace(PsInitialSystemProcess,
306 &PsInitialSystemProcess->AddressSpace);
307 ObCreateHandleTable(NULL,FALSE,PsInitialSystemProcess);
308
309 #if defined(__GNUC__)
310 KProcess->DirectoryTableBase =
311 (LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
312 #else
313 {
314 LARGE_INTEGER dummy;
315 dummy.QuadPart = (LONGLONG)(ULONG)MmGetPageDirectory();
316 KProcess->DirectoryTableBase = dummy;
317 }
318 #endif
319
320 PsInitialSystemProcess->UniqueProcessId =
321 InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
322 PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
323 PsInitialSystemProcess->Win32Desktop = (HANDLE)0;
324
325 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
326 InsertHeadList(&PsProcessListHead,
327 &PsInitialSystemProcess->ProcessListEntry);
328 InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
329 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
330
331 strcpy(PsInitialSystemProcess->ImageFileName, "SYSTEM");
332
333 SepCreateSystemProcessToken(PsInitialSystemProcess);
334
335 ObCreateHandle(PsInitialSystemProcess,
336 PsInitialSystemProcess,
337 PROCESS_ALL_ACCESS,
338 FALSE,
339 &SystemProcessHandle);
340 }
341
342 VOID STDCALL
343 PiDeleteProcessWorker(PVOID pContext)
344 {
345 KIRQL oldIrql;
346 PDEL_CONTEXT Context;
347 PEPROCESS CurrentProcess;
348 PEPROCESS Process;
349
350 Context = (PDEL_CONTEXT)pContext;
351 Process = Context->Process;
352 CurrentProcess = PsGetCurrentProcess();
353
354 DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process);
355
356 if (CurrentProcess != Process)
357 {
358 KeAttachProcess(Process);
359 }
360
361 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
362 RemoveEntryList(&Process->ProcessListEntry);
363 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
364
365 /* KDB hook */
366 KDB_DELETEPROCESS_HOOK(Process);
367
368 ObDereferenceObject(Process->Token);
369 ObDeleteHandleTable(Process);
370
371 if (CurrentProcess != Process)
372 {
373 KeDetachProcess();
374 }
375
376 MmReleaseMmInfo(Process);
377 if (Context->IsWorkerQueue)
378 {
379 KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
380 }
381 }
382
383 VOID STDCALL
384 PiDeleteProcess(PVOID ObjectBody)
385 {
386 DEL_CONTEXT Context;
387
388 Context.Process = (PEPROCESS)ObjectBody;
389
390 if (PsGetCurrentProcess() == Context.Process || PsGetCurrentThread()->OldProcess == NULL)
391 {
392 Context.IsWorkerQueue = FALSE;
393 PiDeleteProcessWorker(&Context);
394 }
395 else
396 {
397 Context.IsWorkerQueue = TRUE;
398 KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
399 ExInitializeWorkItem (&Context.WorkQueueItem, PiDeleteProcessWorker, &Context);
400 ExQueueWorkItem(&Context.WorkQueueItem, HyperCriticalWorkQueue);
401 if (KeReadStateEvent(&Context.Event) == 0)
402 {
403 KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
404 }
405 }
406 }
407
408 static NTSTATUS
409 PsCreatePeb(HANDLE ProcessHandle,
410 PEPROCESS Process,
411 PVOID ImageBase)
412 {
413 ULONG PebSize;
414 PPEB Peb;
415 LARGE_INTEGER SectionOffset;
416 ULONG ViewSize;
417 PVOID TableBase;
418 NTSTATUS Status;
419
420 /* Allocate the Process Environment Block (PEB) */
421 Peb = (PPEB)PEB_BASE;
422 PebSize = PAGE_SIZE;
423 Status = NtAllocateVirtualMemory(ProcessHandle,
424 (PVOID*)&Peb,
425 0,
426 &PebSize,
427 MEM_RESERVE | MEM_COMMIT,
428 PAGE_READWRITE);
429 if (!NT_SUCCESS(Status))
430 {
431 DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
432 return(Status);
433 }
434 DPRINT("Peb %p PebSize %lu\n", Peb, PebSize);
435
436 ViewSize = 0;
437 #if defined(__GNUC__)
438 SectionOffset.QuadPart = 0LL;
439 #else
440 SectionOffset.QuadPart = 0;
441 #endif
442 TableBase = NULL;
443 Status = MmMapViewOfSection(NlsSectionObject,
444 Process,
445 &TableBase,
446 0,
447 0,
448 &SectionOffset,
449 &ViewSize,
450 ViewShare,
451 MEM_TOP_DOWN,
452 PAGE_READONLY);
453 if (!NT_SUCCESS(Status))
454 {
455 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
456 return(Status);
457 }
458 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
459
460 KeAttachProcess(Process);
461
462 /* Initialize the PEB */
463 RtlZeroMemory(Peb, sizeof(PEB));
464 Peb->ImageBaseAddress = ImageBase;
465
466 Peb->OSMajorVersion = 4;
467 Peb->OSMinorVersion = 0;
468 Peb->OSBuildNumber = 0;
469 Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
470 Peb->SPMajorVersion = 6;
471
472 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
473 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
474 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
475
476 Process->Peb = Peb;
477 KeDetachProcess();
478
479 DPRINT("PsCreatePeb: Peb created at %p\n", Peb);
480
481 return(STATUS_SUCCESS);
482 }
483
484
485 PKPROCESS
486 KeGetCurrentProcess(VOID)
487 /*
488 * FUNCTION: Returns a pointer to the current process
489 */
490 {
491 return(&(PsGetCurrentProcess()->Pcb));
492 }
493
494 /*
495 * Warning: Even though it returns HANDLE, it's not a real HANDLE but really a
496 * ULONG ProcessId! (Skywing)
497 */
498 /*
499 * @implemented
500 */
501 HANDLE STDCALL
502 PsGetCurrentProcessId(VOID)
503 {
504 return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
505 }
506
507 /*
508 * @unimplemented
509 */
510 ULONG
511 STDCALL
512 PsGetCurrentProcessSessionId (
513 VOID
514 )
515 {
516 return PsGetCurrentProcess()->SessionId;
517 }
518
519 /*
520 * FUNCTION: Returns a pointer to the current process
521 *
522 * @implemented
523 */
524 PEPROCESS STDCALL
525 IoGetCurrentProcess(VOID)
526 {
527 if (PsGetCurrentThread() == NULL ||
528 PsGetCurrentThread()->ThreadsProcess == NULL)
529 {
530 return(PsInitialSystemProcess);
531 }
532 else
533 {
534 return(PsGetCurrentThread()->ThreadsProcess);
535 }
536 }
537
538 /*
539 * @implemented
540 */
541 NTSTATUS STDCALL
542 PsCreateSystemProcess(PHANDLE ProcessHandle,
543 ACCESS_MASK DesiredAccess,
544 POBJECT_ATTRIBUTES ObjectAttributes)
545 {
546 return NtCreateProcess(ProcessHandle,
547 DesiredAccess,
548 ObjectAttributes,
549 SystemProcessHandle,
550 FALSE,
551 NULL,
552 NULL,
553 NULL);
554 }
555
556 NTSTATUS STDCALL
557 NtCreateProcess(OUT PHANDLE ProcessHandle,
558 IN ACCESS_MASK DesiredAccess,
559 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
560 IN HANDLE ParentProcessHandle,
561 IN BOOLEAN InheritObjectTable,
562 IN HANDLE SectionHandle OPTIONAL,
563 IN HANDLE DebugPortHandle OPTIONAL,
564 IN HANDLE ExceptionPortHandle OPTIONAL)
565 /*
566 * FUNCTION: Creates a process.
567 * ARGUMENTS:
568 * ProcessHandle (OUT) = Caller supplied storage for the resulting
569 * handle
570 * DesiredAccess = Specifies the allowed or desired access to the
571 * process can be a combination of
572 * STANDARD_RIGHTS_REQUIRED| ..
573 * ObjectAttribute = Initialized attributes for the object, contains
574 * the rootdirectory and the filename
575 * ParentProcess = Handle to the parent process.
576 * InheritObjectTable = Specifies to inherit the objects of the parent
577 * process if true.
578 * SectionHandle = Handle to a section object to back the image file
579 * DebugPort = Handle to a DebugPort if NULL the system default debug
580 * port will be used.
581 * ExceptionPort = Handle to a exception port.
582 * REMARKS:
583 * This function maps to the win32 CreateProcess.
584 * RETURNS: Status
585 */
586 {
587 PEPROCESS Process;
588 PEPROCESS ParentProcess;
589 PKPROCESS KProcess;
590 NTSTATUS Status;
591 KIRQL oldIrql;
592 PVOID LdrStartupAddr;
593 PVOID ImageBase;
594 PEPORT DebugPort;
595 PEPORT ExceptionPort;
596 PVOID BaseAddress;
597 PMEMORY_AREA MemoryArea;
598 PHYSICAL_ADDRESS BoundaryAddressMultiple;
599
600 DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
601
602 BoundaryAddressMultiple.QuadPart = 0;
603
604 Status = ObReferenceObjectByHandle(ParentProcessHandle,
605 PROCESS_CREATE_PROCESS,
606 PsProcessType,
607 ExGetPreviousMode(),
608 (PVOID*)&ParentProcess,
609 NULL);
610 if (!NT_SUCCESS(Status))
611 {
612 DPRINT("NtCreateProcess() = %x\n",Status);
613 return(Status);
614 }
615
616 Status = ObCreateObject(ExGetPreviousMode(),
617 PsProcessType,
618 ObjectAttributes,
619 ExGetPreviousMode(),
620 NULL,
621 sizeof(EPROCESS),
622 0,
623 0,
624 (PVOID*)&Process);
625 if (!NT_SUCCESS(Status))
626 {
627 ObDereferenceObject(ParentProcess);
628 DPRINT("ObCreateObject() = %x\n",Status);
629 return(Status);
630 }
631
632 Status = ObInsertObject ((PVOID)Process,
633 NULL,
634 DesiredAccess,
635 0,
636 NULL,
637 ProcessHandle);
638 if (!NT_SUCCESS(Status))
639 {
640 ObDereferenceObject (Process);
641 ObDereferenceObject (ParentProcess);
642 DPRINT("ObInsertObject() = %x\n",Status);
643 return Status;
644 }
645
646 KeInitializeDispatcherHeader(&Process->Pcb.DispatcherHeader,
647 InternalProcessType,
648 sizeof(EPROCESS),
649 FALSE);
650 KProcess = &Process->Pcb;
651 /* Inherit parent process's affinity. */
652 KProcess->Affinity = ParentProcess->Pcb.Affinity;
653 KProcess->BasePriority = PROCESS_PRIO_NORMAL;
654 KProcess->IopmOffset = 0xffff;
655 KProcess->LdtDescriptor[0] = 0;
656 KProcess->LdtDescriptor[1] = 0;
657 MmInitializeAddressSpace(Process,
658 &Process->AddressSpace);
659 Process->UniqueProcessId = InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
660 Process->InheritedFromUniqueProcessId =
661 (HANDLE)ParentProcess->UniqueProcessId;
662 ObCreateHandleTable(ParentProcess,
663 InheritObjectTable,
664 Process);
665 MmCopyMmInfo(ParentProcess, Process);
666 if (ParentProcess->Win32WindowStation != (HANDLE)0)
667 {
668 /* Always duplicate the process window station. */
669 Process->Win32WindowStation = 0;
670 Status = ObDuplicateObject(ParentProcess,
671 Process,
672 ParentProcess->Win32WindowStation,
673 &Process->Win32WindowStation,
674 0,
675 FALSE,
676 DUPLICATE_SAME_ACCESS);
677 if (!NT_SUCCESS(Status))
678 {
679 KEBUGCHECK(0);
680 }
681 }
682 else
683 {
684 Process->Win32WindowStation = (HANDLE)0;
685 }
686 if (ParentProcess->Win32Desktop != (HANDLE)0)
687 {
688 /* Always duplicate the process window station. */
689 Process->Win32Desktop = 0;
690 Status = ObDuplicateObject(ParentProcess,
691 Process,
692 ParentProcess->Win32Desktop,
693 &Process->Win32Desktop,
694 0,
695 FALSE,
696 DUPLICATE_SAME_ACCESS);
697 if (!NT_SUCCESS(Status))
698 {
699 KEBUGCHECK(0);
700 }
701 }
702 else
703 {
704 Process->Win32Desktop = (HANDLE)0;
705 }
706
707 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
708 InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
709 InitializeListHead(&Process->ThreadListHead);
710 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
711
712 Process->Pcb.State = PROCESS_STATE_ACTIVE;
713
714 /*
715 * Add the debug port
716 */
717 if (DebugPortHandle != NULL)
718 {
719 Status = ObReferenceObjectByHandle(DebugPortHandle,
720 PORT_ALL_ACCESS,
721 ExPortType,
722 UserMode,
723 (PVOID*)&DebugPort,
724 NULL);
725 if (!NT_SUCCESS(Status))
726 {
727 ObDereferenceObject(Process);
728 ObDereferenceObject(ParentProcess);
729 ZwClose(*ProcessHandle);
730 *ProcessHandle = NULL;
731 return(Status);
732 }
733 Process->DebugPort = DebugPort;
734 }
735
736 /*
737 * Add the exception port
738 */
739 if (ExceptionPortHandle != NULL)
740 {
741 Status = ObReferenceObjectByHandle(ExceptionPortHandle,
742 PORT_ALL_ACCESS,
743 ExPortType,
744 UserMode,
745 (PVOID*)&ExceptionPort,
746 NULL);
747 if (!NT_SUCCESS(Status))
748 {
749 ObDereferenceObject(Process);
750 ObDereferenceObject(ParentProcess);
751 ZwClose(*ProcessHandle);
752 *ProcessHandle = NULL;
753 return(Status);
754 }
755 Process->ExceptionPort = ExceptionPort;
756 }
757
758 /*
759 * Now we have created the process proper
760 */
761
762 MmLockAddressSpace(&Process->AddressSpace);
763
764 /* Protect the highest 64KB of the process address space */
765 BaseAddress = MmUserProbeAddress;
766 Status = MmCreateMemoryArea(Process,
767 &Process->AddressSpace,
768 MEMORY_AREA_NO_ACCESS,
769 &BaseAddress,
770 0x10000,
771 PAGE_NOACCESS,
772 &MemoryArea,
773 FALSE,
774 FALSE,
775 BoundaryAddressMultiple);
776 if (!NT_SUCCESS(Status))
777 {
778 MmUnlockAddressSpace(&Process->AddressSpace);
779 DPRINT1("Failed to protect the highest 64KB of the process address space\n");
780 KEBUGCHECK(0);
781 }
782
783 /* Protect the lowest 64KB of the process address space */
784 #if 0
785 BaseAddress = (PVOID)0x00000000;
786 Status = MmCreateMemoryArea(Process,
787 &Process->AddressSpace,
788 MEMORY_AREA_NO_ACCESS,
789 &BaseAddress,
790 0x10000,
791 PAGE_NOACCESS,
792 &MemoryArea,
793 FALSE,
794 FALSE,
795 BoundaryAddressMultiple);
796 if (!NT_SUCCESS(Status))
797 {
798 MmUnlockAddressSpace(&Process->AddressSpace);
799 DPRINT1("Failed to protect the lowest 64KB of the process address space\n");
800 KEBUGCHECK(0);
801 }
802 #endif
803
804 /* Protect the 60KB above the shared user page */
805 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
806 Status = MmCreateMemoryArea(Process,
807 &Process->AddressSpace,
808 MEMORY_AREA_NO_ACCESS,
809 &BaseAddress,
810 0x10000 - PAGE_SIZE,
811 PAGE_NOACCESS,
812 &MemoryArea,
813 FALSE,
814 FALSE,
815 BoundaryAddressMultiple);
816 if (!NT_SUCCESS(Status))
817 {
818 MmUnlockAddressSpace(&Process->AddressSpace);
819 DPRINT1("Failed to protect the memory above the shared user page\n");
820 KEBUGCHECK(0);
821 }
822
823 /* Create the shared data page */
824 BaseAddress = (PVOID)USER_SHARED_DATA;
825 Status = MmCreateMemoryArea(Process,
826 &Process->AddressSpace,
827 MEMORY_AREA_SHARED_DATA,
828 &BaseAddress,
829 PAGE_SIZE,
830 PAGE_READONLY,
831 &MemoryArea,
832 FALSE,
833 FALSE,
834 BoundaryAddressMultiple);
835 MmUnlockAddressSpace(&Process->AddressSpace);
836 if (!NT_SUCCESS(Status))
837 {
838 DPRINT1("Failed to create shared data page\n");
839 KEBUGCHECK(0);
840 }
841
842 /*
843 * Map ntdll
844 */
845 Status = LdrpMapSystemDll(*ProcessHandle,
846 &LdrStartupAddr);
847 if (!NT_SUCCESS(Status))
848 {
849 DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status);
850 ObDereferenceObject(Process);
851 ObDereferenceObject(ParentProcess);
852 return(Status);
853 }
854
855 /*
856 * Map the process image
857 */
858 if (SectionHandle != NULL)
859 {
860 DPRINT("Mapping process image\n");
861 Status = LdrpMapImage(*ProcessHandle,
862 SectionHandle,
863 &ImageBase);
864 if (!NT_SUCCESS(Status))
865 {
866 DbgPrint("LdrpMapImage failed (Status %x)\n", Status);
867 ObDereferenceObject(Process);
868 ObDereferenceObject(ParentProcess);
869 return(Status);
870 }
871 }
872 else
873 {
874 ImageBase = NULL;
875 }
876
877 /*
878 * Duplicate the token
879 */
880 Status = SepInitializeNewProcess(Process, ParentProcess);
881 if (!NT_SUCCESS(Status))
882 {
883 DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status);
884 ObDereferenceObject(Process);
885 ObDereferenceObject(ParentProcess);
886 return(Status);
887 }
888
889 /*
890 *
891 */
892 DPRINT("Creating PEB\n");
893 Status = PsCreatePeb(*ProcessHandle,
894 Process,
895 ImageBase);
896 if (!NT_SUCCESS(Status))
897 {
898 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
899 ObDereferenceObject(Process);
900 ObDereferenceObject(ParentProcess);
901 ZwClose(*ProcessHandle);
902 *ProcessHandle = NULL;
903 return(Status);
904 }
905
906 /*
907 * Maybe send a message to the creator process's debugger
908 */
909 #if 0
910 if (ParentProcess->DebugPort != NULL)
911 {
912 LPC_DBG_MESSAGE Message;
913 HANDLE FileHandle;
914
915 ObCreateHandle(NULL, // Debugger Process
916 NULL, // SectionHandle
917 FILE_ALL_ACCESS,
918 FALSE,
919 &FileHandle);
920
921 Message.Header.MessageSize = sizeof(LPC_DBG_MESSAGE);
922 Message.Header.DataSize = sizeof(LPC_DBG_MESSAGE) -
923 sizeof(LPC_MESSAGE);
924 Message.Type = DBG_EVENT_CREATE_PROCESS;
925 Message.Data.CreateProcess.FileHandle = FileHandle;
926 Message.Data.CreateProcess.Base = ImageBase;
927 Message.Data.CreateProcess.EntryPoint = NULL; //
928
929 Status = LpcSendDebugMessagePort(ParentProcess->DebugPort,
930 &Message);
931 }
932 #endif
933
934 PspRunCreateProcessNotifyRoutines(Process, TRUE);
935
936 ObDereferenceObject(Process);
937 ObDereferenceObject(ParentProcess);
938 return(STATUS_SUCCESS);
939 }
940
941
942 /*
943 * @unimplemented
944 */
945 NTSTATUS STDCALL
946 NtOpenProcess(OUT PHANDLE ProcessHandle,
947 IN ACCESS_MASK DesiredAccess,
948 IN POBJECT_ATTRIBUTES ObjectAttributes,
949 IN PCLIENT_ID ClientId)
950 {
951 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
952 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
953 ProcessHandle, DesiredAccess, ObjectAttributes, ClientId,
954 ClientId->UniqueProcess, ClientId->UniqueThread);
955
956
957 /*
958 * Not sure of the exact semantics
959 */
960 if (ObjectAttributes != NULL && ObjectAttributes->ObjectName != NULL &&
961 ObjectAttributes->ObjectName->Buffer != NULL)
962 {
963 NTSTATUS Status;
964 PEPROCESS Process;
965
966 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
967 ObjectAttributes->Attributes,
968 NULL,
969 DesiredAccess,
970 PsProcessType,
971 UserMode,
972 NULL,
973 (PVOID*)&Process);
974 if (Status != STATUS_SUCCESS)
975 {
976 return(Status);
977 }
978
979 Status = ObCreateHandle(PsGetCurrentProcess(),
980 Process,
981 DesiredAccess,
982 FALSE,
983 ProcessHandle);
984 ObDereferenceObject(Process);
985
986 return(Status);
987 }
988 else
989 {
990 KIRQL oldIrql;
991 PLIST_ENTRY current_entry;
992 PEPROCESS current;
993 NTSTATUS Status;
994
995 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
996 current_entry = PsProcessListHead.Flink;
997 while (current_entry != &PsProcessListHead)
998 {
999 current = CONTAINING_RECORD(current_entry, EPROCESS,
1000 ProcessListEntry);
1001 if (current->UniqueProcessId == (ULONG)ClientId->UniqueProcess)
1002 {
1003 if (current->Pcb.State == PROCESS_STATE_TERMINATED)
1004 {
1005 Status = STATUS_PROCESS_IS_TERMINATING;
1006 }
1007 else
1008 {
1009 Status = ObReferenceObjectByPointer(current,
1010 DesiredAccess,
1011 PsProcessType,
1012 UserMode);
1013 }
1014 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1015 if (NT_SUCCESS(Status))
1016 {
1017 Status = ObCreateHandle(PsGetCurrentProcess(),
1018 current,
1019 DesiredAccess,
1020 FALSE,
1021 ProcessHandle);
1022 ObDereferenceObject(current);
1023 DPRINT("*ProcessHandle %x\n", ProcessHandle);
1024 DPRINT("NtOpenProcess() = %x\n", Status);
1025 }
1026 return(Status);
1027 }
1028 current_entry = current_entry->Flink;
1029 }
1030 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1031 DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
1032 return(STATUS_UNSUCCESSFUL);
1033 }
1034 return(STATUS_UNSUCCESSFUL);
1035 }
1036
1037
1038 /*
1039 * @unimplemented
1040 */
1041 NTSTATUS STDCALL
1042 NtQueryInformationProcess(IN HANDLE ProcessHandle,
1043 IN CINT ProcessInformationClass,
1044 OUT PVOID ProcessInformation,
1045 IN ULONG ProcessInformationLength,
1046 OUT PULONG ReturnLength OPTIONAL)
1047 {
1048 PEPROCESS Process;
1049 NTSTATUS Status;
1050
1051 /*
1052 * TODO: Here we should probably check that ProcessInformationLength
1053 * bytes indeed are writable at address ProcessInformation.
1054 */
1055
1056 Status = ObReferenceObjectByHandle(ProcessHandle,
1057 PROCESS_SET_INFORMATION,
1058 PsProcessType,
1059 UserMode,
1060 (PVOID*)&Process,
1061 NULL);
1062 if (Status != STATUS_SUCCESS)
1063 {
1064 return(Status);
1065 }
1066
1067 switch (ProcessInformationClass)
1068 {
1069 case ProcessBasicInformation:
1070 if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION))
1071 {
1072 Status = STATUS_INFO_LENGTH_MISMATCH;
1073 }
1074 else
1075 {
1076 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
1077 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
1078 ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
1079 ProcessBasicInformationP->PebBaseAddress = Process->Peb;
1080 ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
1081 ProcessBasicInformationP->UniqueProcessId =
1082 Process->UniqueProcessId;
1083 ProcessBasicInformationP->InheritedFromUniqueProcessId =
1084 (ULONG)Process->InheritedFromUniqueProcessId;
1085 ProcessBasicInformationP->BasePriority =
1086 Process->Pcb.BasePriority;
1087
1088 if (ReturnLength)
1089 {
1090 *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
1091 }
1092 }
1093 break;
1094
1095 case ProcessQuotaLimits:
1096 case ProcessIoCounters:
1097 Status = STATUS_NOT_IMPLEMENTED;
1098 break;
1099
1100 case ProcessTimes:
1101 if (ProcessInformationLength != sizeof(KERNEL_USER_TIMES))
1102 {
1103 Status = STATUS_INFO_LENGTH_MISMATCH;
1104 }
1105 else
1106 {
1107 PKERNEL_USER_TIMES ProcessTimeP =
1108 (PKERNEL_USER_TIMES)ProcessInformation;
1109
1110 ProcessTimeP->CreateTime = (TIME) Process->CreateTime;
1111 ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
1112 ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
1113 ProcessTimeP->ExitTime = (TIME) Process->ExitTime;
1114
1115 if (ReturnLength)
1116 {
1117 *ReturnLength = sizeof(KERNEL_USER_TIMES);
1118 }
1119 }
1120 break;
1121
1122 case ProcessDebugPort:
1123 case ProcessLdtInformation:
1124 case ProcessWorkingSetWatch:
1125 case ProcessWx86Information:
1126 Status = STATUS_NOT_IMPLEMENTED;
1127 break;
1128
1129 case ProcessHandleCount:
1130 if (ProcessInformationLength != sizeof(ULONG))
1131 {
1132 Status = STATUS_INFO_LENGTH_MISMATCH;
1133 }
1134 else
1135 {
1136 PULONG HandleCount = (PULONG)ProcessInformation;
1137 *HandleCount = ObpGetHandleCountByHandleTable(&Process->HandleTable);
1138 if (ReturnLength)
1139 {
1140 *ReturnLength = sizeof(ULONG);
1141 }
1142 }
1143 break;
1144
1145 case ProcessSessionInformation:
1146 case ProcessWow64Information:
1147 Status = STATUS_NOT_IMPLEMENTED;
1148 break;
1149
1150 case ProcessVmCounters:
1151 if (ProcessInformationLength != sizeof(VM_COUNTERS))
1152 {
1153 Status = STATUS_INFO_LENGTH_MISMATCH;
1154 }
1155 else
1156 {
1157 PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
1158 pOut->PeakVirtualSize = Process->PeakVirtualSize;
1159 /*
1160 * Here we should probably use VirtualSize.LowPart, but due to
1161 * incompatibilities in current headers (no unnamed union),
1162 * I opted for cast.
1163 */
1164 pOut->VirtualSize = (ULONG)Process->VirtualSize.QuadPart;
1165 pOut->PageFaultCount = Process->Vm.PageFaultCount;
1166 pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
1167 pOut->WorkingSetSize = Process->Vm.WorkingSetSize;
1168 pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeakPoolUsage[0]; // TODO: Verify!
1169 pOut->QuotaPagedPoolUsage = Process->QuotaPoolUsage[0]; // TODO: Verify!
1170 pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify!
1171 pOut->QuotaNonPagedPoolUsage = Process->QuotaPoolUsage[1]; // TODO: Verify!
1172 pOut->PagefileUsage = Process->PagefileUsage;
1173 pOut->PeakPagefileUsage = Process->PeakPagefileUsage;
1174
1175 if (ReturnLength)
1176 {
1177 *ReturnLength = sizeof(VM_COUNTERS);
1178 }
1179 }
1180 break;
1181
1182 case ProcessDefaultHardErrorMode:
1183 if (ProcessInformationLength != sizeof(ULONG))
1184 {
1185 Status = STATUS_INFO_LENGTH_MISMATCH;
1186 }
1187 else
1188 {
1189 PULONG HardErrMode = (PULONG)ProcessInformation;
1190 *HardErrMode = Process->DefaultHardErrorProcessing;
1191
1192 if (ReturnLength)
1193 {
1194 *ReturnLength = sizeof(ULONG);
1195 }
1196 }
1197 break;
1198
1199 case ProcessPriorityBoost:
1200 if (ProcessInformationLength != sizeof(ULONG))
1201 {
1202 Status = STATUS_INFO_LENGTH_MISMATCH;
1203 }
1204 else
1205 {
1206 PULONG BoostEnabled = (PULONG)ProcessInformation;
1207 *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
1208
1209 if (ReturnLength)
1210 {
1211 *ReturnLength = sizeof(ULONG);
1212 }
1213 }
1214 break;
1215
1216 case ProcessDeviceMap:
1217 Status = STATUS_NOT_IMPLEMENTED;
1218 break;
1219
1220 case ProcessPriorityClass:
1221 if (ProcessInformationLength != sizeof(USHORT))
1222 {
1223 Status = STATUS_INFO_LENGTH_MISMATCH;
1224 }
1225 else
1226 {
1227 PUSHORT Priority = (PUSHORT)ProcessInformation;
1228 *Priority = Process->PriorityClass;
1229
1230 if (ReturnLength)
1231 {
1232 *ReturnLength = sizeof(USHORT);
1233 }
1234 }
1235 break;
1236
1237 /*
1238 * Note: The following 10 information classes are verified to not be
1239 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
1240 */
1241 case ProcessBasePriority:
1242 case ProcessRaisePriority:
1243 case ProcessExceptionPort:
1244 case ProcessAccessToken:
1245 case ProcessLdtSize:
1246 case ProcessIoPortHandlers:
1247 case ProcessUserModeIOPL:
1248 case ProcessEnableAlignmentFaultFixup:
1249 case ProcessAffinityMask:
1250 case ProcessForegroundInformation:
1251 default:
1252 Status = STATUS_INVALID_INFO_CLASS;
1253 }
1254 ObDereferenceObject(Process);
1255 return(Status);
1256 }
1257
1258
1259 NTSTATUS
1260 PspAssignPrimaryToken(PEPROCESS Process,
1261 HANDLE TokenHandle)
1262 {
1263 PACCESS_TOKEN Token;
1264 PACCESS_TOKEN OldToken;
1265 NTSTATUS Status;
1266
1267 Status = ObReferenceObjectByHandle(TokenHandle,
1268 0,
1269 SepTokenObjectType,
1270 UserMode,
1271 (PVOID*)&Token,
1272 NULL);
1273 if (!NT_SUCCESS(Status))
1274 {
1275 return(Status);
1276 }
1277 Status = SeExchangePrimaryToken(Process, Token, &OldToken);
1278 if (NT_SUCCESS(Status))
1279 {
1280 ObDereferenceObject(OldToken);
1281 }
1282 ObDereferenceObject(Token);
1283 return(Status);
1284 }
1285
1286 /*
1287 * @unimplemented
1288 */
1289 NTSTATUS STDCALL
1290 NtSetInformationProcess(IN HANDLE ProcessHandle,
1291 IN CINT ProcessInformationClass,
1292 IN PVOID ProcessInformation,
1293 IN ULONG ProcessInformationLength)
1294 {
1295 PEPROCESS Process;
1296 NTSTATUS Status;
1297 PHANDLE ProcessAccessTokenP;
1298
1299 Status = ObReferenceObjectByHandle(ProcessHandle,
1300 PROCESS_SET_INFORMATION,
1301 PsProcessType,
1302 UserMode,
1303 (PVOID*)&Process,
1304 NULL);
1305 if (!NT_SUCCESS(Status))
1306 {
1307 return(Status);
1308 }
1309
1310 switch (ProcessInformationClass)
1311 {
1312 case ProcessQuotaLimits:
1313 case ProcessBasePriority:
1314 case ProcessRaisePriority:
1315 case ProcessDebugPort:
1316 case ProcessExceptionPort:
1317 Status = STATUS_NOT_IMPLEMENTED;
1318 break;
1319
1320 case ProcessAccessToken:
1321 ProcessAccessTokenP = (PHANDLE)ProcessInformation;
1322 Status = PspAssignPrimaryToken(Process, *ProcessAccessTokenP);
1323 break;
1324
1325 case ProcessImageFileName:
1326 memcpy(Process->ImageFileName, ProcessInformation, 8);
1327 Status = STATUS_SUCCESS;
1328 break;
1329
1330 case ProcessLdtInformation:
1331 case ProcessLdtSize:
1332 case ProcessDefaultHardErrorMode:
1333 case ProcessIoPortHandlers:
1334 case ProcessWorkingSetWatch:
1335 case ProcessUserModeIOPL:
1336 case ProcessEnableAlignmentFaultFixup:
1337 case ProcessPriorityClass:
1338 case ProcessAffinityMask:
1339 Status = STATUS_NOT_IMPLEMENTED;
1340 break;
1341
1342 case ProcessBasicInformation:
1343 case ProcessIoCounters:
1344 case ProcessTimes:
1345 case ProcessPooledUsageAndLimits:
1346 case ProcessWx86Information:
1347 case ProcessHandleCount:
1348 case ProcessWow64Information:
1349 default:
1350 Status = STATUS_INVALID_INFO_CLASS;
1351
1352 case ProcessDesktop:
1353 Process->Win32Desktop = *(PHANDLE)ProcessInformation;
1354 Status = STATUS_SUCCESS;
1355 break;
1356 }
1357 ObDereferenceObject(Process);
1358 return(Status);
1359 }
1360
1361
1362 /**********************************************************************
1363 * NAME INTERNAL
1364 * PiQuerySystemProcessInformation
1365 *
1366 * DESCRIPTION
1367 * Compute the size of a process+thread snapshot as
1368 * expected by NtQuerySystemInformation.
1369 *
1370 * RETURN VALUE
1371 * 0 on error; otherwise the size, in bytes of the buffer
1372 * required to write a full snapshot.
1373 *
1374 * NOTE
1375 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
1376 */
1377 NTSTATUS
1378 PiQuerySystemProcessInformation(PVOID Buffer,
1379 ULONG Size,
1380 PULONG ReqSize)
1381 {
1382 return STATUS_NOT_IMPLEMENTED;
1383
1384 #if 0
1385 KIRQL OldIrql;
1386 PLIST_ENTRY CurrentEntryP;
1387 PEPROCESS CurrentP;
1388 PLIST_ENTRY CurrentEntryT;
1389 PETHREAD CurrentT;
1390
1391 ULONG RequiredSize = 0L;
1392 BOOLEAN SizeOnly = FALSE;
1393
1394 ULONG SpiSize = 0L;
1395
1396 PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
1397 PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
1398 PSYSTEM_THREAD_INFO pInfoT = NULL;
1399
1400
1401 /* Lock the process list. */
1402 KeAcquireSpinLock(&PsProcessListLock,
1403 &OldIrql);
1404
1405 /*
1406 * Scan the process list. Since the
1407 * list is circular, the guard is false
1408 * after the last process.
1409 */
1410 for ( CurrentEntryP = PsProcessListHead.Flink;
1411 (CurrentEntryP != & PsProcessListHead);
1412 CurrentEntryP = CurrentEntryP->Flink
1413 )
1414 {
1415 /*
1416 * Compute how much space is
1417 * occupied in the snapshot
1418 * by adding this process info.
1419 * (at least one thread).
1420 */
1421 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
1422 RequiredSize += SpiSizeCurrent;
1423 /*
1424 * Do not write process data in the
1425 * buffer if it is too small.
1426 */
1427 if (TRUE == SizeOnly) continue;
1428 /*
1429 * Check if the buffer can contain
1430 * the full snapshot.
1431 */
1432 if (Size < RequiredSize)
1433 {
1434 SizeOnly = TRUE;
1435 continue;
1436 }
1437 /*
1438 * Get a reference to the
1439 * process descriptor we are
1440 * handling.
1441 */
1442 CurrentP = CONTAINING_RECORD(
1443 CurrentEntryP,
1444 EPROCESS,
1445 ProcessListEntry
1446 );
1447 /*
1448 * Write process data in the buffer.
1449 */
1450 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1451 /* PROCESS */
1452 pInfoP->ThreadCount = 0L;
1453 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1454 RtlInitUnicodeString (
1455 & pInfoP->Name,
1456 CurrentP->ImageFileName
1457 );
1458 /* THREAD */
1459 for ( pInfoT = & CurrentP->ThreadSysInfo [0],
1460 CurrentEntryT = CurrentP->ThreadListHead.Flink;
1461
1462 (CurrentEntryT != & CurrentP->ThreadListHead);
1463
1464 pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1465 CurrentEntryT = CurrentEntryT->Flink
1466 )
1467 {
1468 /*
1469 * Recalculate the size of the
1470 * information block.
1471 */
1472 if (0 < pInfoP->ThreadCount)
1473 {
1474 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1475 }
1476 /*
1477 * Do not write thread data in the
1478 * buffer if it is too small.
1479 */
1480 if (TRUE == SizeOnly) continue;
1481 /*
1482 * Check if the buffer can contain
1483 * the full snapshot.
1484 */
1485 if (Size < RequiredSize)
1486 {
1487 SizeOnly = TRUE;
1488 continue;
1489 }
1490 /*
1491 * Get a reference to the
1492 * thread descriptor we are
1493 * handling.
1494 */
1495 CurrentT = CONTAINING_RECORD(
1496 CurrentEntryT,
1497 KTHREAD,
1498 Tcb.ThreadListEntry
1499 );
1500 /*
1501 * Write thread data.
1502 */
1503 RtlZeroMemory (
1504 pInfoT,
1505 sizeof (SYSTEM_THREAD_INFORMATION)
1506 );
1507 pInfoT->KernelTime = CurrentT-> ; /* TIME */
1508 pInfoT->UserTime = CurrentT-> ; /* TIME */
1509 pInfoT->CreateTime = CurrentT-> ; /* TIME */
1510 pInfoT->TickCount = CurrentT-> ; /* ULONG */
1511 pInfoT->StartEIP = CurrentT-> ; /* ULONG */
1512 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1513 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1514 pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */
1515 pInfoT->BasePriority = CurrentT-> ; /* ULONG */
1516 pInfoT->nSwitches = CurrentT-> ; /* ULONG */
1517 pInfoT->State = CurrentT-> ; /* DWORD */
1518 pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */
1519 /*
1520 * Count the number of threads
1521 * this process has.
1522 */
1523 ++ pInfoP->ThreadCount;
1524 }
1525 /*
1526 * Save the size of information
1527 * stored in the buffer for the
1528 * current process.
1529 */
1530 pInfoP->RelativeOffset = SpiSize;
1531 /*
1532 * Save a reference to the last
1533 * valid information block.
1534 */
1535 pInfoPLast = pInfoP;
1536 /*
1537 * Compute the offset of the
1538 * SYSTEM_PROCESS_INFORMATION
1539 * descriptor in the snapshot
1540 * buffer for the next process.
1541 */
1542 (ULONG) pInfoP += SpiSize;
1543 }
1544 /*
1545 * Unlock the process list.
1546 */
1547 KeReleaseSpinLock (
1548 & PsProcessListLock,
1549 OldIrql
1550 );
1551 /*
1552 * Return the proper error status code,
1553 * if the buffer was too small.
1554 */
1555 if (TRUE == SizeOnly)
1556 {
1557 if (NULL != RequiredSize)
1558 {
1559 *pRequiredSize = RequiredSize;
1560 }
1561 return STATUS_INFO_LENGTH_MISMATCH;
1562 }
1563 /*
1564 * Mark the end of the snapshot.
1565 */
1566 pInfoP->RelativeOffset = 0L;
1567 /* OK */
1568 return STATUS_SUCCESS;
1569 #endif
1570 }
1571
1572 /*
1573 * @implemented
1574 */
1575 LARGE_INTEGER STDCALL
1576 PsGetProcessExitTime(VOID)
1577 {
1578 LARGE_INTEGER Li;
1579 Li.QuadPart = PsGetCurrentProcess()->ExitTime.QuadPart;
1580 return Li;
1581 }
1582
1583 /*
1584 * @implemented
1585 */
1586 LONGLONG
1587 STDCALL
1588 PsGetProcessCreateTimeQuadPart(
1589 PEPROCESS Process
1590 )
1591 {
1592 return Process->CreateTime.QuadPart;
1593 }
1594
1595 /*
1596 * @implemented
1597 */
1598 PVOID
1599 STDCALL
1600 PsGetProcessDebugPort(
1601 PEPROCESS Process
1602 )
1603 {
1604 return Process->DebugPort;
1605 }
1606
1607 /*
1608 * @implemented
1609 */
1610 BOOLEAN
1611 STDCALL
1612 PsGetProcessExitProcessCalled(
1613 PEPROCESS Process
1614 )
1615 {
1616 return Process->ExitProcessCalled;
1617 }
1618
1619 /*
1620 * @implemented
1621 */
1622 NTSTATUS
1623 STDCALL
1624 PsGetProcessExitStatus(
1625 PEPROCESS Process
1626 )
1627 {
1628 return Process->ExitStatus;
1629 }
1630
1631 /*
1632 * @implemented
1633 */
1634 HANDLE
1635 STDCALL
1636 PsGetProcessId(
1637 PEPROCESS Process
1638 )
1639 {
1640 return (HANDLE)Process->UniqueProcessId;
1641 }
1642
1643 /*
1644 * @implemented
1645 */
1646 LPSTR
1647 STDCALL
1648 PsGetProcessImageFileName(
1649 PEPROCESS Process
1650 )
1651 {
1652 return (LPSTR)Process->ImageFileName;
1653 }
1654
1655 /*
1656 * @implemented
1657 */
1658 HANDLE
1659 STDCALL
1660 PsGetProcessInheritedFromUniqueProcessId(
1661 PEPROCESS Process
1662 )
1663 {
1664 return Process->InheritedFromUniqueProcessId;
1665 }
1666
1667 /*
1668 * @unimplemented
1669 */
1670 PVOID /*PEJOB*/
1671 STDCALL
1672 PsGetProcessJob(
1673 PEPROCESS Process
1674 )
1675 {
1676 UNIMPLEMENTED;
1677 return 0;
1678 }
1679
1680 /*
1681 * @implemented
1682 */
1683 PPEB
1684 STDCALL
1685 PsGetProcessPeb(
1686 PEPROCESS Process
1687 )
1688 {
1689 return Process->Peb;
1690 }
1691
1692 /*
1693 * @implemented
1694 */
1695 ULONG
1696 STDCALL
1697 PsGetProcessPriorityClass(
1698 PEPROCESS Process
1699 )
1700 {
1701 return Process->PriorityClass;
1702 }
1703
1704 /*
1705 * @implemented
1706 */
1707 PVOID
1708 STDCALL
1709 PsGetProcessSectionBaseAddress(
1710 PEPROCESS Process
1711 )
1712 {
1713 return Process->SectionBaseAddress;
1714 }
1715
1716 /*
1717 * @implemented
1718 */
1719 PVOID
1720 STDCALL
1721 PsGetProcessSecurityPort(
1722 PEPROCESS Process
1723 )
1724 {
1725 return Process->SecurityPort;
1726 }
1727
1728 /*
1729 * @implemented
1730 */
1731 HANDLE
1732 STDCALL
1733 PsGetProcessSessionId(
1734 PEPROCESS Process
1735 )
1736 {
1737 return (HANDLE)Process->SessionId;
1738 }
1739
1740 /*
1741 * @implemented
1742 */
1743 PVOID
1744 STDCALL
1745 PsGetProcessWin32Process(
1746 PEPROCESS Process
1747 )
1748 {
1749 return Process->Win32Process;
1750 }
1751
1752 /*
1753 * @implemented
1754 */
1755 PVOID
1756 STDCALL
1757 PsGetProcessWin32WindowStation(
1758 PEPROCESS Process
1759 )
1760 {
1761 return Process->Win32WindowStation;
1762 }
1763
1764 /*
1765 * @implemented
1766 */
1767 BOOLEAN
1768 STDCALL
1769 PsIsProcessBeingDebugged(
1770 PEPROCESS Process
1771 )
1772 {
1773 return FALSE/*Process->IsProcessBeingDebugged*/;
1774 }
1775
1776
1777 /*
1778 * @implemented
1779 */
1780 NTSTATUS STDCALL
1781 PsLookupProcessByProcessId(IN PVOID ProcessId,
1782 OUT PEPROCESS *Process)
1783 {
1784 KIRQL oldIrql;
1785 PLIST_ENTRY current_entry;
1786 PEPROCESS current;
1787
1788 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1789
1790 current_entry = PsProcessListHead.Flink;
1791 while (current_entry != &PsProcessListHead)
1792 {
1793 current = CONTAINING_RECORD(current_entry,
1794 EPROCESS,
1795 ProcessListEntry);
1796 if (current->UniqueProcessId == (ULONG)ProcessId)
1797 {
1798 *Process = current;
1799 ObReferenceObject(current);
1800 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1801 return(STATUS_SUCCESS);
1802 }
1803 current_entry = current_entry->Flink;
1804 }
1805
1806 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1807
1808 return(STATUS_INVALID_PARAMETER);
1809 }
1810
1811 VOID
1812 STDCALL
1813 PspRunCreateProcessNotifyRoutines
1814 (
1815 PEPROCESS CurrentProcess,
1816 BOOLEAN Create
1817 )
1818 {
1819 ULONG i;
1820 HANDLE ProcessId = (HANDLE)CurrentProcess->UniqueProcessId;
1821 HANDLE ParentId = CurrentProcess->InheritedFromUniqueProcessId;
1822
1823 for(i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++ i)
1824 if(PiProcessNotifyRoutine[i])
1825 PiProcessNotifyRoutine[i](ParentId, ProcessId, Create);
1826 }
1827
1828 /*
1829 * @implemented
1830 */
1831 NTSTATUS STDCALL
1832 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
1833 IN BOOLEAN Remove)
1834 {
1835 ULONG i;
1836
1837 if (Remove)
1838 {
1839 for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
1840 {
1841 if ((PVOID)PiProcessNotifyRoutine[i] == (PVOID)NotifyRoutine)
1842 {
1843 PiProcessNotifyRoutine[i] = NULL;
1844 break;
1845 }
1846 }
1847
1848 return(STATUS_SUCCESS);
1849 }
1850
1851 /*insert*/
1852 for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
1853 {
1854 if (PiProcessNotifyRoutine[i] == NULL)
1855 {
1856 PiProcessNotifyRoutine[i] = NotifyRoutine;
1857 break;
1858 }
1859 }
1860
1861 if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
1862 {
1863 return STATUS_INSUFFICIENT_RESOURCES;
1864 }
1865
1866 return STATUS_SUCCESS;
1867 }
1868
1869 VOID STDCALL
1870 PspRunLoadImageNotifyRoutines(
1871 PUNICODE_STRING FullImageName,
1872 HANDLE ProcessId,
1873 PIMAGE_INFO ImageInfo)
1874 {
1875 ULONG i;
1876
1877 for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++ i)
1878 if (PiLoadImageNotifyRoutine[i])
1879 PiLoadImageNotifyRoutine[i](FullImageName, ProcessId, ImageInfo);
1880 }
1881
1882 /*
1883 * @unimplemented
1884 */
1885 NTSTATUS
1886 STDCALL
1887 PsRemoveLoadImageNotifyRoutine(
1888 IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
1889 )
1890 {
1891 UNIMPLEMENTED;
1892 return STATUS_NOT_IMPLEMENTED;
1893 }
1894
1895 /*
1896 * @implemented
1897 */
1898 NTSTATUS STDCALL
1899 PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
1900 {
1901 ULONG i;
1902
1903 for (i = 0; i < MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT; i++)
1904 {
1905 if (PiLoadImageNotifyRoutine[i] == NULL)
1906 {
1907 PiLoadImageNotifyRoutine[i] = NotifyRoutine;
1908 break;
1909 }
1910 }
1911
1912 if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
1913 {
1914 return STATUS_INSUFFICIENT_RESOURCES;
1915 }
1916
1917 return STATUS_SUCCESS;
1918 }
1919
1920 /*
1921 * @implemented
1922 */
1923 VOID
1924 STDCALL
1925 PsSetProcessPriorityClass(
1926 PEPROCESS Process,
1927 ULONG PriorityClass
1928 )
1929 {
1930 Process->PriorityClass = PriorityClass;
1931 }
1932
1933 /*
1934 * @implemented
1935 */
1936 VOID
1937 STDCALL
1938 PsSetProcessSecurityPort(
1939 PEPROCESS Process,
1940 PVOID SecurityPort
1941 )
1942 {
1943 Process->SecurityPort = SecurityPort;
1944 }
1945
1946 /*
1947 * @implemented
1948 */
1949 VOID
1950 STDCALL
1951 PsSetProcessWin32Process(
1952 PEPROCESS Process,
1953 PVOID Win32Process
1954 )
1955 {
1956 Process->Win32Process = Win32Process;
1957 }
1958
1959 /*
1960 * @implemented
1961 */
1962 VOID
1963 STDCALL
1964 PsSetProcessWin32WindowStation(
1965 PEPROCESS Process,
1966 PVOID WindowStation
1967 )
1968 {
1969 Process->Win32WindowStation = WindowStation;
1970 }
1971
1972 /* Pool Quotas */
1973 /*
1974 * @implemented
1975 */
1976 VOID
1977 STDCALL
1978 PsChargePoolQuota(
1979 IN PEPROCESS Process,
1980 IN POOL_TYPE PoolType,
1981 IN ULONG_PTR Amount
1982 )
1983 {
1984 NTSTATUS Status;
1985
1986 /* Charge the usage */
1987 Status = PsChargeProcessPoolQuota(Process, PoolType, Amount);
1988
1989 /* Raise Exception */
1990 if (!NT_SUCCESS(Status)) {
1991 ExRaiseStatus(Status);
1992 }
1993 }
1994
1995 /*
1996 * @implemented
1997 */
1998 NTSTATUS
1999 STDCALL
2000 PsChargeProcessNonPagedPoolQuota (
2001 IN PEPROCESS Process,
2002 IN ULONG_PTR Amount
2003 )
2004 {
2005 /* Call the general function */
2006 return PsChargeProcessPoolQuota(Process, NonPagedPool, Amount);
2007 }
2008
2009 /*
2010 * @implemented
2011 */
2012 NTSTATUS
2013 STDCALL
2014 PsChargeProcessPagedPoolQuota (
2015 IN PEPROCESS Process,
2016 IN ULONG_PTR Amount
2017 )
2018 {
2019 /* Call the general function */
2020 return PsChargeProcessPoolQuota(Process, PagedPool, Amount);
2021 }
2022
2023 /*
2024 * @implemented
2025 */
2026 NTSTATUS
2027 STDCALL
2028 PsChargeProcessPoolQuota(
2029 IN PEPROCESS Process,
2030 IN POOL_TYPE PoolType,
2031 IN ULONG_PTR Amount
2032 )
2033 {
2034 PEPROCESS_QUOTA_BLOCK QuotaBlock;
2035 KIRQL OldValue;
2036 ULONG NewUsageSize;
2037 ULONG NewMaxQuota;
2038
2039 /* Get current Quota Block */
2040 QuotaBlock = Process->QuotaBlock;
2041
2042 /* Quota Operations are not to be done on the SYSTEM Process */
2043 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
2044
2045 /* Acquire Spinlock */
2046 KeAcquireSpinLock(&QuotaBlock->QuotaLock, &OldValue);
2047
2048 /* New Size in use */
2049 NewUsageSize = QuotaBlock->QuotaPoolUsage[PoolType] + Amount;
2050
2051 /* Does this size respect the quota? */
2052 if (NewUsageSize > QuotaBlock->QuotaPoolLimit[PoolType]) {
2053
2054 /* It doesn't, so keep raising the Quota */
2055 while (MiRaisePoolQuota(PoolType, QuotaBlock->QuotaPoolLimit[PoolType], &NewMaxQuota)) {
2056 /* Save new Maximum Quota */
2057 QuotaBlock->QuotaPoolLimit[PoolType] = NewMaxQuota;
2058
2059 /* See if the new Maximum Quota fulfills our need */
2060 if (NewUsageSize <= NewMaxQuota) goto QuotaChanged;
2061 }
2062
2063 KeReleaseSpinLock(&QuotaBlock->QuotaLock, OldValue);
2064 return STATUS_QUOTA_EXCEEDED;
2065 }
2066
2067 QuotaChanged:
2068 /* Save new Usage */
2069 QuotaBlock->QuotaPoolUsage[PoolType] = NewUsageSize;
2070
2071 /* Is this a new peak? */
2072 if (NewUsageSize > QuotaBlock->QuotaPeakPoolUsage[PoolType]) {
2073 QuotaBlock->QuotaPeakPoolUsage[PoolType] = NewUsageSize;
2074 }
2075
2076 /* Release spinlock */
2077 KeReleaseSpinLock(&QuotaBlock->QuotaLock, OldValue);
2078
2079 /* All went well */
2080 return STATUS_SUCCESS;
2081 }
2082
2083 /*
2084 * @unimplemented
2085 */
2086 VOID
2087 STDCALL
2088 PsReturnPoolQuota(
2089 IN PEPROCESS Process,
2090 IN POOL_TYPE PoolType,
2091 IN ULONG_PTR Amount
2092 )
2093 {
2094 UNIMPLEMENTED;
2095 }
2096
2097 /*
2098 * @unimplemented
2099 */
2100 VOID
2101 STDCALL
2102 PsReturnProcessNonPagedPoolQuota(
2103 IN PEPROCESS Process,
2104 IN ULONG_PTR Amount
2105 )
2106 {
2107 UNIMPLEMENTED;
2108 }
2109
2110 /*
2111 * @unimplemented
2112 */
2113 VOID
2114 STDCALL
2115 PsReturnProcessPagedPoolQuota(
2116 IN PEPROCESS Process,
2117 IN ULONG_PTR Amount
2118 )
2119 {
2120 UNIMPLEMENTED;
2121 }
2122 /* EOF */