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)
12 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS ******************************************************************/
20 PEPROCESS EXPORTED PsInitialSystemProcess
= NULL
;
22 POBJECT_TYPE EXPORTED PsProcessType
= NULL
;
24 LIST_ENTRY PsProcessListHead
;
25 static KSPIN_LOCK PsProcessListLock
;
26 static ULONG PiNextProcessUniqueId
= 0; /* TODO */
27 static LARGE_INTEGER ShortPsLockDelay
, PsLockTimeout
;
29 static GENERIC_MAPPING PiProcessMapping
= {STANDARD_RIGHTS_READ
| PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
30 STANDARD_RIGHTS_WRITE
| PROCESS_CREATE_PROCESS
| PROCESS_CREATE_THREAD
|
31 PROCESS_VM_OPERATION
| PROCESS_VM_WRITE
| PROCESS_DUP_HANDLE
|
32 PROCESS_TERMINATE
| PROCESS_SET_QUOTA
| PROCESS_SET_INFORMATION
| PROCESS_SET_PORT
,
33 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
36 static const INFORMATION_CLASS_INFO PsProcessInfoClass
[] =
38 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessBasicInformation */
39 ICI_SQ_SAME( sizeof(QUOTA_LIMITS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessQuotaLimits */
40 ICI_SQ_SAME( sizeof(IO_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessIoCounters */
41 ICI_SQ_SAME( sizeof(VM_COUNTERS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessVmCounters */
42 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessTimes */
43 ICI_SQ_SAME( sizeof(KPRIORITY
), sizeof(USHORT
), ICIF_SET
), /* ProcessBasePriority */
44 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_SET
), /* ProcessRaisePriority */
45 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessDebugPort */
46 ICI_SQ_SAME( sizeof(HANDLE
), sizeof(ULONG
), ICIF_SET
), /* ProcessExceptionPort */
47 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN
), sizeof(USHORT
), ICIF_SET
), /* ProcessAccessToken */
48 ICI_SQ_SAME( 0 /* FIXME */, sizeof(USHORT
), ICIF_QUERY
| ICIF_SET
), /* ProcessLdtInformation */
49 ICI_SQ_SAME( 0 /* FIXME */, sizeof(USHORT
), ICIF_SET
), /* ProcessLdtSize */
50 ICI_SQ_SAME( sizeof(ULONG
), sizeof(USHORT
), ICIF_QUERY
| ICIF_SET
), /* ProcessDefaultHardErrorMode */
51 ICI_SQ_SAME( 0 /* FIXME */, sizeof(USHORT
), ICIF_SET
), /* ProcessIoPortHandlers */
52 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessPooledUsageAndLimits */
53 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessWorkingSetWatch */
54 ICI_SQ_SAME( 0 /* FIXME */, sizeof(USHORT
), ICIF_SET
), /* ProcessUserModeIOPL */
55 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(USHORT
), ICIF_SET
), /* ProcessEnableAlignmentFaultFixup */
56 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS
), sizeof(USHORT
), ICIF_SET
), /* ProcessPriorityClass */
57 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWx86Information */
58 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessHandleCount */
59 ICI_SQ_SAME( sizeof(KAFFINITY
), sizeof(USHORT
), ICIF_SET
), /* ProcessAffinityMask */
60 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
), /* ProcessPriorityBoost */
62 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Query
), /* ProcessDeviceMap */
63 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION
)0x0)->Set
),
66 ICIF_QUERY
| ICIF_SET
),
68 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION
), sizeof(USHORT
), ICIF_QUERY
| ICIF_SET
), /* ProcessSessionInformation */
69 ICI_SQ_SAME( sizeof(BOOLEAN
), sizeof(USHORT
), ICIF_SET
), /* ProcessForegroundInformation */
70 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
), /* ProcessWow64Information */
71 ICI_SQ_SAME( sizeof(UNICODE_STRING
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SIZE_VARIABLE
), /* ProcessImageFileName */
74 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8
75 #define MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT 8
77 static PCREATE_PROCESS_NOTIFY_ROUTINE
78 PiProcessNotifyRoutine
[MAX_PROCESS_NOTIFY_ROUTINE_COUNT
];
79 static PLOAD_IMAGE_NOTIFY_ROUTINE
80 PiLoadImageNotifyRoutine
[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT
];
85 WORK_QUEUE_ITEM WorkQueueItem
;
88 BOOLEAN IsWorkerQueue
;
89 } DEL_CONTEXT
, *PDEL_CONTEXT
;
91 /* FUNCTIONS *****************************************************************/
95 PsExitSpecialApc(PKAPC Apc
,
96 PKNORMAL_ROUTINE
*NormalRoutine
,
98 PVOID
*SystemArgument1
,
99 PVOID
*SystemArgument2
)
104 PsGetNextProcess(PEPROCESS OldProcess
)
107 PEPROCESS NextProcess
;
110 if (OldProcess
== NULL
)
112 Status
= ObReferenceObjectByPointer(PsInitialSystemProcess
,
116 if (!NT_SUCCESS(Status
))
118 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsInitialSystemProcess\n");
121 return PsInitialSystemProcess
;
124 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
125 NextProcess
= OldProcess
;
128 if (NextProcess
->ProcessListEntry
.Blink
== &PsProcessListHead
)
130 NextProcess
= CONTAINING_RECORD(PsProcessListHead
.Blink
,
136 NextProcess
= CONTAINING_RECORD(NextProcess
->ProcessListEntry
.Blink
,
140 Status
= ObReferenceObjectByPointer(NextProcess
,
144 if (NT_SUCCESS(Status
))
148 else if (Status
== STATUS_PROCESS_IS_TERMINATING
)
152 else if (!NT_SUCCESS(Status
))
154 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
159 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
160 ObDereferenceObject(OldProcess
);
170 NtOpenProcessToken(IN HANDLE ProcessHandle
,
171 IN ACCESS_MASK DesiredAccess
,
172 OUT PHANDLE TokenHandle
)
174 return NtOpenProcessTokenEx(ProcessHandle
,
186 NtOpenProcessTokenEx(
187 IN HANDLE ProcessHandle
,
188 IN ACCESS_MASK DesiredAccess
,
189 IN ULONG HandleAttributes
,
190 OUT PHANDLE TokenHandle
197 Status
= PsOpenTokenOfProcess(ProcessHandle
,
199 if (!NT_SUCCESS(Status
))
203 Status
= ObCreateHandle(PsGetCurrentProcess(),
208 ObDereferenceObject(Token
);
210 if(NT_SUCCESS(Status
))
212 Status
= MmCopyToCaller(TokenHandle
, &hToken
, sizeof(HANDLE
));
221 PACCESS_TOKEN STDCALL
222 PsReferencePrimaryToken(PEPROCESS Process
)
224 ObReferenceObjectByPointer(Process
->Token
,
228 return(Process
->Token
);
233 PsOpenTokenOfProcess(HANDLE ProcessHandle
,
234 PACCESS_TOKEN
* Token
)
239 Status
= ObReferenceObjectByHandle(ProcessHandle
,
240 PROCESS_QUERY_INFORMATION
,
245 if (!NT_SUCCESS(Status
))
249 *Token
= PsReferencePrimaryToken(Process
);
250 ObDereferenceObject(Process
);
251 return(STATUS_SUCCESS
);
256 PiKillMostProcesses(VOID
)
259 PLIST_ENTRY current_entry
;
262 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
264 current_entry
= PsProcessListHead
.Flink
;
265 while (current_entry
!= &PsProcessListHead
)
267 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
269 current_entry
= current_entry
->Flink
;
271 if (current
->UniqueProcessId
!= PsInitialSystemProcess
->UniqueProcessId
&&
272 current
->UniqueProcessId
!= (ULONG
)PsGetCurrentProcessId())
274 PiTerminateProcessThreads(current
, STATUS_SUCCESS
);
278 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
283 PsInitProcessManagment(VOID
)
289 ShortPsLockDelay
.QuadPart
= -100LL;
290 PsLockTimeout
.QuadPart
= -10000000LL; /* one second */
292 * Register the process object type
295 PsProcessType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
297 PsProcessType
->Tag
= TAG('P', 'R', 'O', 'C');
298 PsProcessType
->TotalObjects
= 0;
299 PsProcessType
->TotalHandles
= 0;
300 PsProcessType
->PeakObjects
= 0;
301 PsProcessType
->PeakHandles
= 0;
302 PsProcessType
->PagedPoolCharge
= 0;
303 PsProcessType
->NonpagedPoolCharge
= sizeof(EPROCESS
);
304 PsProcessType
->Mapping
= &PiProcessMapping
;
305 PsProcessType
->Dump
= NULL
;
306 PsProcessType
->Open
= NULL
;
307 PsProcessType
->Close
= NULL
;
308 PsProcessType
->Delete
= PiDeleteProcess
;
309 PsProcessType
->Parse
= NULL
;
310 PsProcessType
->Security
= NULL
;
311 PsProcessType
->QueryName
= NULL
;
312 PsProcessType
->OkayToClose
= NULL
;
313 PsProcessType
->Create
= NULL
;
314 PsProcessType
->DuplicationNotify
= NULL
;
316 RtlRosInitUnicodeStringFromLiteral(&PsProcessType
->TypeName
, L
"Process");
318 ObpCreateTypeObject(PsProcessType
);
320 InitializeListHead(&PsProcessListHead
);
321 KeInitializeSpinLock(&PsProcessListLock
);
323 RtlZeroMemory(PiProcessNotifyRoutine
, sizeof(PiProcessNotifyRoutine
));
324 RtlZeroMemory(PiLoadImageNotifyRoutine
, sizeof(PiLoadImageNotifyRoutine
));
327 * Initialize the system process
329 Status
= ObCreateObject(KernelMode
,
337 (PVOID
*)&PsInitialSystemProcess
);
338 if (!NT_SUCCESS(Status
))
343 /* System threads may run on any processor. */
344 PsInitialSystemProcess
->Pcb
.Affinity
= 0xFFFFFFFF;
345 PsInitialSystemProcess
->Pcb
.IopmOffset
= 0xffff;
346 PsInitialSystemProcess
->Pcb
.LdtDescriptor
[0] = 0;
347 PsInitialSystemProcess
->Pcb
.LdtDescriptor
[1] = 0;
348 PsInitialSystemProcess
->Pcb
.BasePriority
= PROCESS_PRIO_NORMAL
;
349 PsInitialSystemProcess
->Pcb
.ThreadQuantum
= 6;
350 InitializeListHead(&PsInitialSystemProcess
->Pcb
.ThreadListHead
);
351 KeInitializeDispatcherHeader(&PsInitialSystemProcess
->Pcb
.DispatcherHeader
,
355 KProcess
= &PsInitialSystemProcess
->Pcb
;
357 MmInitializeAddressSpace(PsInitialSystemProcess
,
358 &PsInitialSystemProcess
->AddressSpace
);
359 ObCreateHandleTable(NULL
,FALSE
,PsInitialSystemProcess
);
361 KeInitializeEvent(&PsInitialSystemProcess
->LockEvent
, SynchronizationEvent
, FALSE
);
362 PsInitialSystemProcess
->LockCount
= 0;
363 PsInitialSystemProcess
->LockOwner
= NULL
;
365 #if defined(__GNUC__)
366 KProcess
->DirectoryTableBase
=
367 (LARGE_INTEGER
)(LONGLONG
)(ULONG
)MmGetPageDirectory();
371 dummy
.QuadPart
= (LONGLONG
)(ULONG
)MmGetPageDirectory();
372 KProcess
->DirectoryTableBase
= dummy
;
376 PsInitialSystemProcess
->UniqueProcessId
=
377 InterlockedIncrementUL(&PiNextProcessUniqueId
); /* TODO */
378 PsInitialSystemProcess
->Win32WindowStation
= (HANDLE
)0;
380 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
381 InsertHeadList(&PsProcessListHead
,
382 &PsInitialSystemProcess
->ProcessListEntry
);
383 InitializeListHead(&PsInitialSystemProcess
->ThreadListHead
);
384 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
386 strcpy(PsInitialSystemProcess
->ImageFileName
, "System");
388 SepCreateSystemProcessToken(PsInitialSystemProcess
);
392 PiDeleteProcessWorker(PVOID pContext
)
395 PDEL_CONTEXT Context
;
396 PEPROCESS CurrentProcess
;
399 Context
= (PDEL_CONTEXT
)pContext
;
400 Process
= Context
->Process
;
401 CurrentProcess
= PsGetCurrentProcess();
403 DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process
);
405 if (CurrentProcess
!= Process
)
407 KeAttachProcess(&Process
->Pcb
);
410 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
411 RemoveEntryList(&Process
->ProcessListEntry
);
412 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
415 KDB_DELETEPROCESS_HOOK(Process
);
417 ObDereferenceObject(Process
->Token
);
418 ObDeleteHandleTable(Process
);
420 if (CurrentProcess
!= Process
)
425 MmReleaseMmInfo(Process
);
426 if (Context
->IsWorkerQueue
)
428 KeSetEvent(&Context
->Event
, IO_NO_INCREMENT
, FALSE
);
433 PiDeleteProcess(PVOID ObjectBody
)
437 Context
.Process
= (PEPROCESS
)ObjectBody
;
439 if (PsGetCurrentProcess() == Context
.Process
||
440 PsGetCurrentThread()->ThreadsProcess
== Context
.Process
)
445 if (PsGetCurrentThread()->ThreadsProcess
== PsGetCurrentProcess())
447 Context
.IsWorkerQueue
= FALSE
;
448 PiDeleteProcessWorker(&Context
);
452 Context
.IsWorkerQueue
= TRUE
;
453 KeInitializeEvent(&Context
.Event
, NotificationEvent
, FALSE
);
454 ExInitializeWorkItem (&Context
.WorkQueueItem
, PiDeleteProcessWorker
, &Context
);
455 ExQueueWorkItem(&Context
.WorkQueueItem
, HyperCriticalWorkQueue
);
456 if (KeReadStateEvent(&Context
.Event
) == 0)
458 KeWaitForSingleObject(&Context
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
462 if(((PEPROCESS
)ObjectBody
)->Win32Process
!= NULL
)
464 /* delete the W32PROCESS structure if there's one associated */
465 ExFreePool (((PEPROCESS
)ObjectBody
)->Win32Process
);
470 PsCreatePeb(HANDLE ProcessHandle
,
477 LARGE_INTEGER SectionOffset
;
482 /* Allocate the Process Environment Block (PEB) */
483 Process
->TebBlock
= (PVOID
) MM_ROUND_DOWN(PEB_BASE
, MM_VIRTMEM_GRANULARITY
);
484 AllocSize
= MM_VIRTMEM_GRANULARITY
;
485 Status
= NtAllocateVirtualMemory(ProcessHandle
,
491 if (!NT_SUCCESS(Status
))
493 DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status
);
496 ASSERT((ULONG_PTR
) Process
->TebBlock
<= PEB_BASE
&&
497 PEB_BASE
+ PAGE_SIZE
<= (ULONG_PTR
) Process
->TebBlock
+ AllocSize
);
498 Peb
= (PPEB
)PEB_BASE
;
500 Status
= NtAllocateVirtualMemory(ProcessHandle
,
506 if (!NT_SUCCESS(Status
))
508 DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status
);
511 DPRINT("Peb %p PebSize %lu\n", Peb
, PebSize
);
512 ASSERT((PPEB
) PEB_BASE
== Peb
&& PAGE_SIZE
<= PebSize
);
513 Process
->TebLastAllocated
= (PVOID
) Peb
;
516 SectionOffset
.QuadPart
= (ULONGLONG
)0;
518 Status
= MmMapViewOfSection(NlsSectionObject
,
528 if (!NT_SUCCESS(Status
))
530 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
533 DPRINT("TableBase %p ViewSize %lx\n", TableBase
, ViewSize
);
535 KeAttachProcess(&Process
->Pcb
);
537 /* Initialize the PEB */
538 RtlZeroMemory(Peb
, sizeof(PEB
));
539 Peb
->ImageBaseAddress
= ImageBase
;
541 Peb
->OSMajorVersion
= 4;
542 Peb
->OSMinorVersion
= 0;
543 Peb
->OSBuildNumber
= 1381;
544 Peb
->OSPlatformId
= 2; //VER_PLATFORM_WIN32_NT;
545 Peb
->SPMajorVersion
= 6;
547 Peb
->AnsiCodePageData
= (char*)TableBase
+ NlsAnsiTableOffset
;
548 Peb
->OemCodePageData
= (char*)TableBase
+ NlsOemTableOffset
;
549 Peb
->UnicodeCaseTableData
= (char*)TableBase
+ NlsUnicodeTableOffset
;
554 DPRINT("PsCreatePeb: Peb created at %p\n", Peb
);
556 return(STATUS_SUCCESS
);
561 KeGetCurrentProcess(VOID
)
563 * FUNCTION: Returns a pointer to the current process
566 return(&(PsGetCurrentProcess()->Pcb
));
570 * Warning: Even though it returns HANDLE, it's not a real HANDLE but really a
571 * ULONG ProcessId! (Skywing)
577 PsGetCurrentProcessId(VOID
)
579 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
587 PsGetCurrentProcessSessionId (
591 return PsGetCurrentProcess()->SessionId
;
595 * FUNCTION: Returns a pointer to the current process
600 IoGetCurrentProcess(VOID
)
602 if (PsGetCurrentThread() == NULL
||
603 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
605 return(PsInitialSystemProcess
);
609 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
617 PsCreateSystemProcess(PHANDLE ProcessHandle
,
618 ACCESS_MASK DesiredAccess
,
619 POBJECT_ATTRIBUTES ObjectAttributes
)
621 HANDLE SystemProcessHandle
;
624 /* FIXME - what about security? should there be any privilege checks or something
627 Status
= ObCreateHandle(PsGetCurrentProcess(),
628 PsInitialSystemProcess
,
629 PROCESS_CREATE_PROCESS
| PROCESS_CREATE_THREAD
| PROCESS_QUERY_INFORMATION
,
631 &SystemProcessHandle
);
632 if(!NT_SUCCESS(Status
))
634 DPRINT1("Failed to create a handle for the system process!\n");
638 Status
= NtCreateProcess(ProcessHandle
,
647 NtClose(SystemProcessHandle
);
653 NtCreateProcess(OUT PHANDLE ProcessHandle
,
654 IN ACCESS_MASK DesiredAccess
,
655 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
656 IN HANDLE ParentProcess
,
657 IN BOOLEAN InheritObjectTable
,
658 IN HANDLE SectionHandle OPTIONAL
,
659 IN HANDLE DebugPort OPTIONAL
,
660 IN HANDLE ExceptionPort OPTIONAL
)
662 * FUNCTION: Creates a process.
664 * ProcessHandle (OUT) = Caller supplied storage for the resulting
666 * DesiredAccess = Specifies the allowed or desired access to the
667 * process can be a combination of
668 * STANDARD_RIGHTS_REQUIRED| ..
669 * ObjectAttribute = Initialized attributes for the object, contains
670 * the rootdirectory and the filename
671 * ParentProcess = Handle to the parent process.
672 * InheritObjectTable = Specifies to inherit the objects of the parent
674 * SectionHandle = Handle to a section object to back the image file
675 * DebugPort = Handle to a DebugPort if NULL the system default debug
677 * ExceptionPort = Handle to a exception port.
679 * This function maps to the win32 CreateProcess.
684 PEPROCESS pParentProcess
;
688 PVOID LdrStartupAddr
;
691 PEPORT pExceptionPort
;
693 PMEMORY_AREA MemoryArea
;
694 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
696 DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes
);
698 BoundaryAddressMultiple
.QuadPart
= 0;
700 Status
= ObReferenceObjectByHandle(ParentProcess
,
701 PROCESS_CREATE_PROCESS
,
704 (PVOID
*)&pParentProcess
,
706 if (!NT_SUCCESS(Status
))
708 DPRINT("NtCreateProcess() = %x\n",Status
);
712 Status
= ObCreateObject(ExGetPreviousMode(),
721 if (!NT_SUCCESS(Status
))
723 ObDereferenceObject(pParentProcess
);
724 DPRINT("ObCreateObject() = %x\n",Status
);
728 Status
= ObInsertObject ((PVOID
)Process
,
734 if (!NT_SUCCESS(Status
))
736 ObDereferenceObject (Process
);
737 ObDereferenceObject (pParentProcess
);
738 DPRINT("ObInsertObject() = %x\n",Status
);
742 KeInitializeDispatcherHeader(&Process
->Pcb
.DispatcherHeader
,
746 KProcess
= &Process
->Pcb
;
747 /* Inherit parent process's affinity. */
748 KProcess
->Affinity
= pParentProcess
->Pcb
.Affinity
;
749 KProcess
->BasePriority
= PROCESS_PRIO_NORMAL
;
750 KProcess
->IopmOffset
= 0xffff;
751 KProcess
->LdtDescriptor
[0] = 0;
752 KProcess
->LdtDescriptor
[1] = 0;
753 InitializeListHead(&KProcess
->ThreadListHead
);
754 KProcess
->ThreadQuantum
= 6;
755 KProcess
->AutoAlignment
= 0;
756 MmInitializeAddressSpace(Process
,
757 &Process
->AddressSpace
);
758 Process
->UniqueProcessId
= InterlockedIncrementUL(&PiNextProcessUniqueId
); /* TODO */
759 Process
->InheritedFromUniqueProcessId
=
760 (HANDLE
)pParentProcess
->UniqueProcessId
;
761 ObCreateHandleTable(pParentProcess
,
764 MmCopyMmInfo(ParentProcess
, Process
);
766 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
767 Process
->LockCount
= 0;
768 Process
->LockOwner
= NULL
;
770 Process
->Win32WindowStation
= (HANDLE
)0;
772 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
773 InsertHeadList(&PsProcessListHead
, &Process
->ProcessListEntry
);
774 InitializeListHead(&Process
->ThreadListHead
);
775 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
777 ExInitializeFastMutex(&Process
->TebLock
);
778 Process
->Pcb
.State
= PROCESS_STATE_ACTIVE
;
783 if (DebugPort
!= NULL
)
785 Status
= ObReferenceObjectByHandle(DebugPort
,
791 if (!NT_SUCCESS(Status
))
793 ObDereferenceObject(Process
);
794 ObDereferenceObject(pParentProcess
);
795 ZwClose(*ProcessHandle
);
796 *ProcessHandle
= NULL
;
799 Process
->DebugPort
= pDebugPort
;
803 * Add the exception port
805 if (ExceptionPort
!= NULL
)
807 Status
= ObReferenceObjectByHandle(ExceptionPort
,
811 (PVOID
*)&pExceptionPort
,
813 if (!NT_SUCCESS(Status
))
815 ObDereferenceObject(Process
);
816 ObDereferenceObject(pParentProcess
);
817 ZwClose(*ProcessHandle
);
818 *ProcessHandle
= NULL
;
821 Process
->ExceptionPort
= pExceptionPort
;
825 * Now we have created the process proper
828 MmLockAddressSpace(&Process
->AddressSpace
);
830 /* Protect the highest 64KB of the process address space */
831 BaseAddress
= (PVOID
)MmUserProbeAddress
;
832 Status
= MmCreateMemoryArea(Process
,
833 &Process
->AddressSpace
,
834 MEMORY_AREA_NO_ACCESS
,
841 BoundaryAddressMultiple
);
842 if (!NT_SUCCESS(Status
))
844 MmUnlockAddressSpace(&Process
->AddressSpace
);
845 DPRINT1("Failed to protect the highest 64KB of the process address space\n");
849 /* Protect the lowest 64KB of the process address space */
851 BaseAddress
= (PVOID
)0x00000000;
852 Status
= MmCreateMemoryArea(Process
,
853 &Process
->AddressSpace
,
854 MEMORY_AREA_NO_ACCESS
,
861 BoundaryAddressMultiple
);
862 if (!NT_SUCCESS(Status
))
864 MmUnlockAddressSpace(&Process
->AddressSpace
);
865 DPRINT1("Failed to protect the lowest 64KB of the process address space\n");
870 /* Protect the 60KB above the shared user page */
871 BaseAddress
= (char*)USER_SHARED_DATA
+ PAGE_SIZE
;
872 Status
= MmCreateMemoryArea(Process
,
873 &Process
->AddressSpace
,
874 MEMORY_AREA_NO_ACCESS
,
881 BoundaryAddressMultiple
);
882 if (!NT_SUCCESS(Status
))
884 MmUnlockAddressSpace(&Process
->AddressSpace
);
885 DPRINT1("Failed to protect the memory above the shared user page\n");
889 /* Create the shared data page */
890 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
891 Status
= MmCreateMemoryArea(Process
,
892 &Process
->AddressSpace
,
893 MEMORY_AREA_SHARED_DATA
,
900 BoundaryAddressMultiple
);
901 MmUnlockAddressSpace(&Process
->AddressSpace
);
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("Failed to create shared data page\n");
908 if (SectionHandle
!= NULL
)
910 PSECTION_OBJECT SectionObject
;
911 UNICODE_STRING FileName
;
917 * Determine the image file name and save it to the EPROCESS structure
919 Status
= ObReferenceObjectByHandle(SectionHandle
,
923 (PVOID
*)&SectionObject
,
925 if (!NT_SUCCESS(Status
))
927 DbgPrint("Failed to reference section object\n", Status
);
928 ObDereferenceObject(Process
);
929 ObDereferenceObject(pParentProcess
);
933 FileName
= SectionObject
->FileObject
->FileName
;
934 szSrc
= (PWCHAR
)(FileName
.Buffer
+ (FileName
.Length
/ sizeof(WCHAR
)) - 1);
935 while(szSrc
>= FileName
.Buffer
)
949 /* copy the image file name to the process and truncate it to 15 characters
951 szDest
= Process
->ImageFileName
;
952 lnFName
= min(lnFName
, sizeof(Process
->ImageFileName
) - 1);
955 *(szDest
++) = (UCHAR
)*(szSrc
++);
960 ObDereferenceObject(SectionObject
);
964 Process
->ImageFileName
[0] = '\0';
970 Status
= LdrpMapSystemDll(*ProcessHandle
,
972 if (!NT_SUCCESS(Status
))
974 DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status
);
975 ObDereferenceObject(Process
);
976 ObDereferenceObject(pParentProcess
);
981 * Map the process image
983 if (SectionHandle
!= NULL
)
985 DPRINT("Mapping process image\n");
986 Status
= LdrpMapImage(*ProcessHandle
,
989 if (!NT_SUCCESS(Status
))
991 DbgPrint("LdrpMapImage failed (Status %x)\n", Status
);
992 ObDereferenceObject(Process
);
993 ObDereferenceObject(pParentProcess
);
1003 * Duplicate the token
1005 Status
= SepInitializeNewProcess(Process
, pParentProcess
);
1006 if (!NT_SUCCESS(Status
))
1008 DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status
);
1009 ObDereferenceObject(Process
);
1010 ObDereferenceObject(pParentProcess
);
1017 DPRINT("Creating PEB\n");
1018 Status
= PsCreatePeb(*ProcessHandle
,
1021 if (!NT_SUCCESS(Status
))
1023 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
1024 ObDereferenceObject(Process
);
1025 ObDereferenceObject(pParentProcess
);
1026 ZwClose(*ProcessHandle
);
1027 *ProcessHandle
= NULL
;
1032 * Maybe send a message to the creator process's debugger
1035 if (pParentProcess
->DebugPort
!= NULL
)
1037 LPC_DBG_MESSAGE Message
;
1040 ObCreateHandle(NULL
, // Debugger Process
1041 NULL
, // SectionHandle
1046 Message
.Header
.MessageSize
= sizeof(LPC_DBG_MESSAGE
);
1047 Message
.Header
.DataSize
= sizeof(LPC_DBG_MESSAGE
) -
1048 sizeof(LPC_MESSAGE
);
1049 Message
.Type
= DBG_EVENT_CREATE_PROCESS
;
1050 Message
.Data
.CreateProcess
.FileHandle
= FileHandle
;
1051 Message
.Data
.CreateProcess
.Base
= ImageBase
;
1052 Message
.Data
.CreateProcess
.EntryPoint
= NULL
; //
1054 Status
= LpcSendDebugMessagePort(pParentProcess
->DebugPort
,
1059 PspRunCreateProcessNotifyRoutines(Process
, TRUE
);
1061 ObDereferenceObject(Process
);
1062 ObDereferenceObject(pParentProcess
);
1063 return(STATUS_SUCCESS
);
1071 NtOpenProcess(OUT PHANDLE ProcessHandle
,
1072 IN ACCESS_MASK DesiredAccess
,
1073 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1074 IN PCLIENT_ID ClientId
)
1076 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
1077 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
1078 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
1079 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
1083 * Not sure of the exact semantics
1085 if (ObjectAttributes
!= NULL
&& ObjectAttributes
->ObjectName
!= NULL
&&
1086 ObjectAttributes
->ObjectName
->Buffer
!= NULL
)
1091 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
1092 ObjectAttributes
->Attributes
,
1099 if (Status
!= STATUS_SUCCESS
)
1104 Status
= ObCreateHandle(PsGetCurrentProcess(),
1109 ObDereferenceObject(Process
);
1116 PLIST_ENTRY current_entry
;
1120 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
1121 current_entry
= PsProcessListHead
.Flink
;
1122 while (current_entry
!= &PsProcessListHead
)
1124 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
1126 if (current
->UniqueProcessId
== (ULONG
)ClientId
->UniqueProcess
)
1128 if (current
->Pcb
.State
== PROCESS_STATE_TERMINATED
)
1130 Status
= STATUS_PROCESS_IS_TERMINATING
;
1134 Status
= ObReferenceObjectByPointer(current
,
1139 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
1140 if (NT_SUCCESS(Status
))
1142 Status
= ObCreateHandle(PsGetCurrentProcess(),
1147 ObDereferenceObject(current
);
1148 DPRINT("*ProcessHandle %x\n", ProcessHandle
);
1149 DPRINT("NtOpenProcess() = %x\n", Status
);
1153 current_entry
= current_entry
->Flink
;
1155 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
1156 DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
1157 return(STATUS_UNSUCCESSFUL
);
1159 return(STATUS_UNSUCCESSFUL
);
1167 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
1168 IN PROCESSINFOCLASS ProcessInformationClass
,
1169 OUT PVOID ProcessInformation
,
1170 IN ULONG ProcessInformationLength
,
1171 OUT PULONG ReturnLength OPTIONAL
)
1174 KPROCESSOR_MODE PreviousMode
;
1175 NTSTATUS Status
= STATUS_SUCCESS
;
1177 PreviousMode
= ExGetPreviousMode();
1179 DefaultQueryInfoBufferCheck(ProcessInformationClass
,
1182 ProcessInformationLength
,
1186 if(!NT_SUCCESS(Status
))
1188 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status
);
1193 * TODO: Here we should probably check that ProcessInformationLength
1194 * bytes indeed are writable at address ProcessInformation.
1197 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1198 PROCESS_QUERY_INFORMATION
,
1203 if (!NT_SUCCESS(Status
))
1208 switch (ProcessInformationClass
)
1210 case ProcessBasicInformation
:
1212 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
=
1213 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
1217 ProcessBasicInformationP
->ExitStatus
= Process
->ExitStatus
;
1218 ProcessBasicInformationP
->PebBaseAddress
= Process
->Peb
;
1219 ProcessBasicInformationP
->AffinityMask
= Process
->Pcb
.Affinity
;
1220 ProcessBasicInformationP
->UniqueProcessId
=
1221 Process
->UniqueProcessId
;
1222 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
1223 (ULONG
)Process
->InheritedFromUniqueProcessId
;
1224 ProcessBasicInformationP
->BasePriority
=
1225 Process
->Pcb
.BasePriority
;
1229 *ReturnLength
= sizeof(PROCESS_BASIC_INFORMATION
);
1234 Status
= _SEH_GetExceptionCode();
1240 case ProcessQuotaLimits
:
1241 case ProcessIoCounters
:
1242 Status
= STATUS_NOT_IMPLEMENTED
;
1247 PKERNEL_USER_TIMES ProcessTimeP
= (PKERNEL_USER_TIMES
)ProcessInformation
;
1250 ProcessTimeP
->CreateTime
= Process
->CreateTime
;
1251 ProcessTimeP
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
* 100000LL;
1252 ProcessTimeP
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
* 100000LL;
1253 ProcessTimeP
->ExitTime
= Process
->ExitTime
;
1257 *ReturnLength
= sizeof(KERNEL_USER_TIMES
);
1262 Status
= _SEH_GetExceptionCode();
1268 case ProcessDebugPort
:
1272 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
!= NULL
? (HANDLE
)-1 : NULL
);
1275 *ReturnLength
= sizeof(HANDLE
);
1280 Status
= _SEH_GetExceptionCode();
1286 case ProcessLdtInformation
:
1287 case ProcessWorkingSetWatch
:
1288 case ProcessWx86Information
:
1289 Status
= STATUS_NOT_IMPLEMENTED
;
1292 case ProcessHandleCount
:
1294 ULONG HandleCount
= ObpGetHandleCountByHandleTable(&Process
->HandleTable
);
1298 *(PULONG
)ProcessInformation
= HandleCount
;
1301 *ReturnLength
= sizeof(ULONG
);
1306 Status
= _SEH_GetExceptionCode();
1312 case ProcessSessionInformation
:
1314 PPROCESS_SESSION_INFORMATION SessionInfo
= (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
1318 SessionInfo
->SessionId
= Process
->SessionId
;
1321 *ReturnLength
= sizeof(PROCESS_SESSION_INFORMATION
);
1326 Status
= _SEH_GetExceptionCode();
1332 case ProcessWow64Information
:
1333 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
1334 Status
= STATUS_NOT_IMPLEMENTED
;
1337 case ProcessVmCounters
:
1339 PVM_COUNTERS pOut
= (PVM_COUNTERS
)ProcessInformation
;
1343 pOut
->PeakVirtualSize
= Process
->PeakVirtualSize
;
1345 * Here we should probably use VirtualSize.LowPart, but due to
1346 * incompatibilities in current headers (no unnamed union),
1349 pOut
->VirtualSize
= (ULONG
)Process
->VirtualSize
.QuadPart
;
1350 pOut
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
1351 pOut
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
1352 pOut
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
1353 pOut
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeakPoolUsage
[0]; // TODO: Verify!
1354 pOut
->QuotaPagedPoolUsage
= Process
->QuotaPoolUsage
[0]; // TODO: Verify!
1355 pOut
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeakPoolUsage
[1]; // TODO: Verify!
1356 pOut
->QuotaNonPagedPoolUsage
= Process
->QuotaPoolUsage
[1]; // TODO: Verify!
1357 pOut
->PagefileUsage
= Process
->PagefileUsage
;
1358 pOut
->PeakPagefileUsage
= Process
->PeakPagefileUsage
;
1362 *ReturnLength
= sizeof(VM_COUNTERS
);
1367 Status
= _SEH_GetExceptionCode();
1373 case ProcessDefaultHardErrorMode
:
1375 PULONG HardErrMode
= (PULONG
)ProcessInformation
;
1378 *HardErrMode
= Process
->DefaultHardErrorProcessing
;
1381 *ReturnLength
= sizeof(ULONG
);
1386 Status
= _SEH_GetExceptionCode();
1392 case ProcessPriorityBoost
:
1394 PULONG BoostEnabled
= (PULONG
)ProcessInformation
;
1398 *BoostEnabled
= Process
->Pcb
.DisableBoost
? FALSE
: TRUE
;
1402 *ReturnLength
= sizeof(ULONG
);
1407 Status
= _SEH_GetExceptionCode();
1413 case ProcessDeviceMap
:
1415 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
1417 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
1421 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
1424 *ReturnLength
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
1429 Status
= _SEH_GetExceptionCode();
1435 case ProcessPriorityClass
:
1437 PUSHORT Priority
= (PUSHORT
)ProcessInformation
;
1441 *Priority
= Process
->PriorityClass
;
1445 *ReturnLength
= sizeof(USHORT
);
1450 Status
= _SEH_GetExceptionCode();
1456 case ProcessImageFileName
:
1459 * We DO NOT return the file name stored in the EPROCESS structure.
1460 * Propably if we can't find a PEB or ProcessParameters structure for the
1463 if(Process
->Peb
!= NULL
)
1465 PRTL_USER_PROCESS_PARAMETERS ProcParams
= NULL
;
1466 UNICODE_STRING LocalDest
;
1467 ULONG ImagePathLen
= 0;
1468 PUNICODE_STRING DstPath
= (PUNICODE_STRING
)ProcessInformation
;
1470 /* we need to attach to the process to make sure we're in the right context! */
1471 KeAttachProcess(&Process
->Pcb
);
1475 ProcParams
= Process
->Peb
->ProcessParameters
;
1476 ImagePathLen
= ProcParams
->ImagePathName
.Length
;
1480 Status
= _SEH_GetExceptionCode();
1484 if(NT_SUCCESS(Status
))
1486 if(ProcessInformationLength
< sizeof(UNICODE_STRING
) + ImagePathLen
+ sizeof(WCHAR
))
1488 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1492 PWSTR StrSource
= NULL
;
1494 /* create a DstPath structure on the stack */
1497 LocalDest
.Length
= ImagePathLen
;
1498 LocalDest
.MaximumLength
= ImagePathLen
+ sizeof(WCHAR
);
1499 LocalDest
.Buffer
= (PWSTR
)(DstPath
+ 1);
1501 /* save a copy of the pointer to the source buffer */
1502 StrSource
= ProcParams
->ImagePathName
.Buffer
;
1506 Status
= _SEH_GetExceptionCode();
1510 if(NT_SUCCESS(Status
))
1512 /* now, let's allocate some anonymous memory to copy the string to.
1513 we can't just copy it to the buffer the caller pointed as it might
1514 be user memory in another context */
1515 PWSTR PathCopy
= ExAllocatePool(PagedPool
, LocalDest
.Length
+ sizeof(WCHAR
));
1516 if(PathCopy
!= NULL
)
1518 /* make a copy of the buffer to the temporary buffer */
1521 RtlCopyMemory(PathCopy
, StrSource
, LocalDest
.Length
);
1522 PathCopy
[LocalDest
.Length
/ sizeof(WCHAR
)] = L
'\0';
1526 Status
= _SEH_GetExceptionCode();
1530 /* detach from the process */
1533 /* only copy the string back to the caller if we were able to
1534 copy it into the temporary buffer! */
1535 if(NT_SUCCESS(Status
))
1537 /* now let's copy the buffer back to the caller */
1540 *DstPath
= LocalDest
;
1541 RtlCopyMemory(LocalDest
.Buffer
, PathCopy
, LocalDest
.Length
+ sizeof(WCHAR
));
1544 *ReturnLength
= sizeof(UNICODE_STRING
) + LocalDest
.Length
+ sizeof(WCHAR
);
1549 Status
= _SEH_GetExceptionCode();
1554 /* we're done with the copy operation, free the temporary kernel buffer */
1555 ExFreePool(PathCopy
);
1557 /* we need to bail because we're already detached from the process */
1562 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1568 /* don't forget to detach from the process!!! */
1573 /* FIXME - what to do here? */
1574 Status
= STATUS_UNSUCCESSFUL
;
1580 * Note: The following 10 information classes are verified to not be
1581 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
1583 case ProcessBasePriority
:
1584 case ProcessRaisePriority
:
1585 case ProcessExceptionPort
:
1586 case ProcessAccessToken
:
1587 case ProcessLdtSize
:
1588 case ProcessIoPortHandlers
:
1589 case ProcessUserModeIOPL
:
1590 case ProcessEnableAlignmentFaultFixup
:
1591 case ProcessAffinityMask
:
1592 case ProcessForegroundInformation
:
1594 Status
= STATUS_INVALID_INFO_CLASS
;
1597 ObDereferenceObject(Process
);
1603 PspAssignPrimaryToken(PEPROCESS Process
,
1606 PACCESS_TOKEN Token
;
1607 PACCESS_TOKEN OldToken
;
1610 Status
= ObReferenceObjectByHandle(TokenHandle
,
1616 if (!NT_SUCCESS(Status
))
1620 Status
= SeExchangePrimaryToken(Process
, Token
, &OldToken
);
1621 if (NT_SUCCESS(Status
))
1623 ObDereferenceObject(OldToken
);
1625 ObDereferenceObject(Token
);
1633 NtSetInformationProcess(IN HANDLE ProcessHandle
,
1634 IN PROCESSINFOCLASS ProcessInformationClass
,
1635 IN PVOID ProcessInformation
,
1636 IN ULONG ProcessInformationLength
)
1639 KPROCESSOR_MODE PreviousMode
;
1641 NTSTATUS Status
= STATUS_SUCCESS
;
1643 PreviousMode
= ExGetPreviousMode();
1645 DefaultSetInfoBufferCheck(ProcessInformationClass
,
1648 ProcessInformationLength
,
1651 if(!NT_SUCCESS(Status
))
1653 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass
, ProcessInformation
, ProcessInformationLength
);
1654 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status
);
1658 switch(ProcessInformationClass
)
1660 case ProcessSessionInformation
:
1661 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_SESSIONID
;
1663 case ProcessExceptionPort
:
1664 case ProcessDebugPort
:
1665 Access
= PROCESS_SET_INFORMATION
| PROCESS_SET_PORT
;
1669 Access
= PROCESS_SET_INFORMATION
;
1673 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1679 if (!NT_SUCCESS(Status
))
1684 switch (ProcessInformationClass
)
1686 case ProcessQuotaLimits
:
1687 case ProcessBasePriority
:
1688 case ProcessRaisePriority
:
1689 Status
= STATUS_NOT_IMPLEMENTED
;
1692 case ProcessDebugPort
:
1694 if(ProcessInformationLength
!= sizeof(HANDLE
))
1696 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1700 HANDLE PortHandle
= NULL
;
1702 /* make a safe copy of the buffer on the stack */
1705 PortHandle
= *(PHANDLE
)ProcessInformation
;
1706 Status
= (PortHandle
!= NULL
? STATUS_SUCCESS
: STATUS_INVALID_PARAMETER
);
1710 Status
= _SEH_GetExceptionCode();
1714 if(NT_SUCCESS(Status
))
1718 /* in case we had success reading from the buffer, verify the provided
1721 Status
= ObReferenceObjectByHandle(PortHandle
,
1727 if(NT_SUCCESS(Status
))
1729 /* lock the process to be thread-safe! */
1731 Status
= PsLockProcess(Process
, FALSE
);
1732 if(NT_SUCCESS(Status
))
1735 * according to "NT Native API" documentation, setting the debug
1736 * port is only permitted once!
1738 if(Process
->DebugPort
== NULL
)
1740 /* keep the reference to the handle! */
1741 Process
->DebugPort
= DebugPort
;
1745 /* we're now debugging the process, so set the flag in the PEB
1746 structure. However, to access it we need to attach to the
1747 process so we're sure we're in the right context! */
1749 KeAttachProcess(&Process
->Pcb
);
1752 Process
->Peb
->BeingDebugged
= TRUE
;
1756 DPRINT1("Trying to set the Peb->BeingDebugged field of process 0x%x failed, exception: 0x%x\n", Process
, _SEH_GetExceptionCode());
1761 Status
= STATUS_SUCCESS
;
1765 ObDereferenceObject(DebugPort
);
1766 Status
= STATUS_PORT_ALREADY_SET
;
1768 PsUnlockProcess(Process
);
1772 ObDereferenceObject(DebugPort
);
1780 case ProcessExceptionPort
:
1782 if(ProcessInformationLength
!= sizeof(HANDLE
))
1784 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1788 HANDLE PortHandle
= NULL
;
1790 /* make a safe copy of the buffer on the stack */
1793 PortHandle
= *(PHANDLE
)ProcessInformation
;
1794 Status
= STATUS_SUCCESS
;
1798 Status
= _SEH_GetExceptionCode();
1802 if(NT_SUCCESS(Status
))
1804 PEPORT ExceptionPort
;
1806 /* in case we had success reading from the buffer, verify the provided
1809 Status
= ObReferenceObjectByHandle(PortHandle
,
1813 (PVOID
)&ExceptionPort
,
1815 if(NT_SUCCESS(Status
))
1817 /* lock the process to be thread-safe! */
1819 Status
= PsLockProcess(Process
, FALSE
);
1820 if(NT_SUCCESS(Status
))
1823 * according to "NT Native API" documentation, setting the exception
1824 * port is only permitted once!
1826 if(Process
->ExceptionPort
== NULL
)
1828 /* keep the reference to the handle! */
1829 Process
->ExceptionPort
= ExceptionPort
;
1830 Status
= STATUS_SUCCESS
;
1834 ObDereferenceObject(ExceptionPort
);
1835 Status
= STATUS_PORT_ALREADY_SET
;
1837 PsUnlockProcess(Process
);
1841 ObDereferenceObject(ExceptionPort
);
1849 case ProcessAccessToken
:
1851 if(ProcessInformationLength
!= sizeof(PROCESS_ACCESS_TOKEN
))
1853 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1857 HANDLE TokenHandle
= NULL
;
1859 /* make a safe copy of the buffer on the stack */
1862 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->Token
;
1863 Status
= STATUS_SUCCESS
;
1867 Status
= _SEH_GetExceptionCode();
1871 if(NT_SUCCESS(Status
))
1873 /* in case we had success reading from the buffer, perform the actual task */
1874 Status
= PspAssignPrimaryToken(Process
, TokenHandle
);
1880 case ProcessDefaultHardErrorMode
:
1882 if(ProcessInformationLength
!= sizeof(UINT
))
1884 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1890 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
1891 *(PLONG
)ProcessInformation
);
1892 Status
= STATUS_SUCCESS
;
1896 Status
= _SEH_GetExceptionCode();
1903 case ProcessSessionInformation
:
1905 if(ProcessInformationLength
!= sizeof(UINT
))
1907 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1911 PROCESS_SESSION_INFORMATION SessionInfo
;
1912 Status
= STATUS_SUCCESS
;
1916 /* copy the structure to the stack */
1917 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
1921 Status
= _SEH_GetExceptionCode();
1925 if(NT_SUCCESS(Status
))
1927 /* we successfully copied the structure to the stack, continue processing */
1930 * setting the session id requires the SeTcbPrivilege!
1932 if(!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1935 /* can't set the session id, bail! */
1936 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1940 /* FIXME - update the session id for the process token */
1942 Status
= PsLockProcess(Process
, FALSE
);
1943 if(NT_SUCCESS(Status
))
1945 Process
->SessionId
= SessionInfo
.SessionId
;
1947 /* Update the session id in the PEB structure */
1948 if(Process
->Peb
!= NULL
)
1950 /* we need to attach to the process to make sure we're in the right
1951 context to access the PEB structure */
1952 KeAttachProcess(&Process
->Pcb
);
1956 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
1958 Status
= STATUS_SUCCESS
;
1962 Status
= _SEH_GetExceptionCode();
1969 PsUnlockProcess(Process
);
1976 case ProcessLdtInformation
:
1977 case ProcessLdtSize
:
1978 case ProcessIoPortHandlers
:
1979 case ProcessWorkingSetWatch
:
1980 case ProcessUserModeIOPL
:
1981 case ProcessEnableAlignmentFaultFixup
:
1982 case ProcessPriorityClass
:
1983 case ProcessAffinityMask
:
1984 Status
= STATUS_NOT_IMPLEMENTED
;
1987 case ProcessBasicInformation
:
1988 case ProcessIoCounters
:
1990 case ProcessPooledUsageAndLimits
:
1991 case ProcessWx86Information
:
1992 case ProcessHandleCount
:
1993 case ProcessWow64Information
:
1995 Status
= STATUS_INVALID_INFO_CLASS
;
1997 ObDereferenceObject(Process
);
2002 /**********************************************************************
2004 * PiQuerySystemProcessInformation
2007 * Compute the size of a process+thread snapshot as
2008 * expected by NtQuerySystemInformation.
2011 * 0 on error; otherwise the size, in bytes of the buffer
2012 * required to write a full snapshot.
2015 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
2018 PiQuerySystemProcessInformation(PVOID Buffer
,
2022 return STATUS_NOT_IMPLEMENTED
;
2026 PLIST_ENTRY CurrentEntryP
;
2028 PLIST_ENTRY CurrentEntryT
;
2031 ULONG RequiredSize
= 0L;
2032 BOOLEAN SizeOnly
= FALSE
;
2036 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
2037 PSYSTEM_PROCESS_INFORMATION pInfoPLast
= NULL
;
2038 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
2041 /* Lock the process list. */
2042 KeAcquireSpinLock(&PsProcessListLock
,
2046 * Scan the process list. Since the
2047 * list is circular, the guard is false
2048 * after the last process.
2050 for ( CurrentEntryP
= PsProcessListHead
.Flink
;
2051 (CurrentEntryP
!= & PsProcessListHead
);
2052 CurrentEntryP
= CurrentEntryP
->Flink
2056 * Compute how much space is
2057 * occupied in the snapshot
2058 * by adding this process info.
2059 * (at least one thread).
2061 SpiSizeCurrent
= sizeof (SYSTEM_PROCESS_INFORMATION
);
2062 RequiredSize
+= SpiSizeCurrent
;
2064 * Do not write process data in the
2065 * buffer if it is too small.
2067 if (TRUE
== SizeOnly
) continue;
2069 * Check if the buffer can contain
2070 * the full snapshot.
2072 if (Size
< RequiredSize
)
2078 * Get a reference to the
2079 * process descriptor we are
2082 CurrentP
= CONTAINING_RECORD(
2088 * Write process data in the buffer.
2090 RtlZeroMemory (pInfoP
, sizeof (SYSTEM_PROCESS_INFORMATION
));
2092 pInfoP
->ThreadCount
= 0L;
2093 pInfoP
->ProcessId
= CurrentP
->UniqueProcessId
;
2094 RtlInitUnicodeString (
2096 CurrentP
->ImageFileName
2099 for ( pInfoT
= & CurrentP
->ThreadSysInfo
[0],
2100 CurrentEntryT
= CurrentP
->ThreadListHead
.Flink
;
2102 (CurrentEntryT
!= & CurrentP
->ThreadListHead
);
2104 pInfoT
= & CurrentP
->ThreadSysInfo
[pInfoP
->ThreadCount
],
2105 CurrentEntryT
= CurrentEntryT
->Flink
2109 * Recalculate the size of the
2110 * information block.
2112 if (0 < pInfoP
->ThreadCount
)
2114 RequiredSize
+= sizeof (SYSTEM_THREAD_INFORMATION
);
2117 * Do not write thread data in the
2118 * buffer if it is too small.
2120 if (TRUE
== SizeOnly
) continue;
2122 * Check if the buffer can contain
2123 * the full snapshot.
2125 if (Size
< RequiredSize
)
2131 * Get a reference to the
2132 * thread descriptor we are
2135 CurrentT
= CONTAINING_RECORD(
2141 * Write thread data.
2145 sizeof (SYSTEM_THREAD_INFORMATION
)
2147 pInfoT
->KernelTime
= CurrentT
-> ; /* TIME */
2148 pInfoT
->UserTime
= CurrentT
-> ; /* TIME */
2149 pInfoT
->CreateTime
= CurrentT
-> ; /* TIME */
2150 pInfoT
->TickCount
= CurrentT
-> ; /* ULONG */
2151 pInfoT
->StartEIP
= CurrentT
-> ; /* ULONG */
2152 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
2153 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
2154 pInfoT
->DynamicPriority
= CurrentT
-> ; /* ULONG */
2155 pInfoT
->BasePriority
= CurrentT
-> ; /* ULONG */
2156 pInfoT
->nSwitches
= CurrentT
-> ; /* ULONG */
2157 pInfoT
->State
= CurrentT
-> ; /* DWORD */
2158 pInfoT
->WaitReason
= CurrentT
-> ; /* KWAIT_REASON */
2160 * Count the number of threads
2163 ++ pInfoP
->ThreadCount
;
2166 * Save the size of information
2167 * stored in the buffer for the
2170 pInfoP
->RelativeOffset
= SpiSize
;
2172 * Save a reference to the last
2173 * valid information block.
2175 pInfoPLast
= pInfoP
;
2177 * Compute the offset of the
2178 * SYSTEM_PROCESS_INFORMATION
2179 * descriptor in the snapshot
2180 * buffer for the next process.
2182 (ULONG
) pInfoP
+= SpiSize
;
2185 * Unlock the process list.
2188 & PsProcessListLock
,
2192 * Return the proper error status code,
2193 * if the buffer was too small.
2195 if (TRUE
== SizeOnly
)
2197 if (NULL
!= RequiredSize
)
2199 *pRequiredSize
= RequiredSize
;
2201 return STATUS_INFO_LENGTH_MISMATCH
;
2204 * Mark the end of the snapshot.
2206 pInfoP
->RelativeOffset
= 0L;
2208 return STATUS_SUCCESS
;
2215 LARGE_INTEGER STDCALL
2216 PsGetProcessExitTime(VOID
)
2219 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
2228 PsGetProcessCreateTimeQuadPart(
2232 return Process
->CreateTime
.QuadPart
;
2240 PsGetProcessDebugPort(
2244 return Process
->DebugPort
;
2252 PsGetProcessExitProcessCalled(
2256 return Process
->ExitProcessCalled
;
2264 PsGetProcessExitStatus(
2268 return Process
->ExitStatus
;
2280 return (HANDLE
)Process
->UniqueProcessId
;
2288 PsGetProcessImageFileName(
2292 return (LPSTR
)Process
->ImageFileName
;
2300 PsGetProcessInheritedFromUniqueProcessId(
2304 return Process
->InheritedFromUniqueProcessId
;
2316 return Process
->Job
;
2328 return Process
->Peb
;
2336 PsGetProcessPriorityClass(
2340 return Process
->PriorityClass
;
2348 PsGetProcessSectionBaseAddress(
2352 return Process
->SectionBaseAddress
;
2360 PsGetProcessSecurityPort(
2364 return Process
->SecurityPort
;
2372 PsGetProcessSessionId(
2376 return (HANDLE
)Process
->SessionId
;
2384 PsGetProcessWin32Process(
2388 return Process
->Win32Process
;
2396 PsGetProcessWin32WindowStation(
2400 return Process
->Win32WindowStation
;
2408 PsIsProcessBeingDebugged(
2412 return FALSE
/*Process->IsProcessBeingDebugged*/;
2420 PsLookupProcessByProcessId(IN PVOID ProcessId
,
2421 OUT PEPROCESS
*Process
)
2424 PLIST_ENTRY current_entry
;
2427 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
2429 current_entry
= PsProcessListHead
.Flink
;
2430 while (current_entry
!= &PsProcessListHead
)
2432 current
= CONTAINING_RECORD(current_entry
,
2435 if (current
->UniqueProcessId
== (ULONG
)ProcessId
)
2438 ObReferenceObject(current
);
2439 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
2440 return(STATUS_SUCCESS
);
2442 current_entry
= current_entry
->Flink
;
2445 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
2447 return(STATUS_INVALID_PARAMETER
);
2452 PspRunCreateProcessNotifyRoutines
2454 PEPROCESS CurrentProcess
,
2459 HANDLE ProcessId
= (HANDLE
)CurrentProcess
->UniqueProcessId
;
2460 HANDLE ParentId
= CurrentProcess
->InheritedFromUniqueProcessId
;
2462 for(i
= 0; i
< MAX_PROCESS_NOTIFY_ROUTINE_COUNT
; ++ i
)
2463 if(PiProcessNotifyRoutine
[i
])
2464 PiProcessNotifyRoutine
[i
](ParentId
, ProcessId
, Create
);
2471 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine
,
2478 for(i
=0;i
<MAX_PROCESS_NOTIFY_ROUTINE_COUNT
;i
++)
2480 if ((PVOID
)PiProcessNotifyRoutine
[i
] == (PVOID
)NotifyRoutine
)
2482 PiProcessNotifyRoutine
[i
] = NULL
;
2487 return(STATUS_SUCCESS
);
2491 for(i
=0;i
<MAX_PROCESS_NOTIFY_ROUTINE_COUNT
;i
++)
2493 if (PiProcessNotifyRoutine
[i
] == NULL
)
2495 PiProcessNotifyRoutine
[i
] = NotifyRoutine
;
2500 if (i
== MAX_PROCESS_NOTIFY_ROUTINE_COUNT
)
2502 return STATUS_INSUFFICIENT_RESOURCES
;
2505 return STATUS_SUCCESS
;
2509 PspRunLoadImageNotifyRoutines(
2510 PUNICODE_STRING FullImageName
,
2512 PIMAGE_INFO ImageInfo
)
2516 for (i
= 0; i
< MAX_PROCESS_NOTIFY_ROUTINE_COUNT
; ++ i
)
2517 if (PiLoadImageNotifyRoutine
[i
])
2518 PiLoadImageNotifyRoutine
[i
](FullImageName
, ProcessId
, ImageInfo
);
2526 PsRemoveLoadImageNotifyRoutine(
2527 IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
2531 return STATUS_NOT_IMPLEMENTED
;
2538 PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
)
2542 for (i
= 0; i
< MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT
; i
++)
2544 if (PiLoadImageNotifyRoutine
[i
] == NULL
)
2546 PiLoadImageNotifyRoutine
[i
] = NotifyRoutine
;
2551 if (i
== MAX_PROCESS_NOTIFY_ROUTINE_COUNT
)
2553 return STATUS_INSUFFICIENT_RESOURCES
;
2556 return STATUS_SUCCESS
;
2564 PsSetProcessPriorityClass(
2569 Process
->PriorityClass
= PriorityClass
;
2577 PsSetProcessSecurityPort(
2582 Process
->SecurityPort
= SecurityPort
;
2590 PsSetProcessWin32Process(
2595 Process
->Win32Process
= Win32Process
;
2603 PsSetProcessWin32WindowStation(
2608 Process
->Win32WindowStation
= WindowStation
;
2618 IN PEPROCESS Process
,
2619 IN POOL_TYPE PoolType
,
2625 /* Charge the usage */
2626 Status
= PsChargeProcessPoolQuota(Process
, PoolType
, Amount
);
2628 /* Raise Exception */
2629 if (!NT_SUCCESS(Status
)) {
2630 ExRaiseStatus(Status
);
2639 PsChargeProcessNonPagedPoolQuota (
2640 IN PEPROCESS Process
,
2644 /* Call the general function */
2645 return PsChargeProcessPoolQuota(Process
, NonPagedPool
, Amount
);
2653 PsChargeProcessPagedPoolQuota (
2654 IN PEPROCESS Process
,
2658 /* Call the general function */
2659 return PsChargeProcessPoolQuota(Process
, PagedPool
, Amount
);
2667 PsChargeProcessPoolQuota(
2668 IN PEPROCESS Process
,
2669 IN POOL_TYPE PoolType
,
2673 PEPROCESS_QUOTA_BLOCK QuotaBlock
;
2677 /* Get current Quota Block */
2678 QuotaBlock
= Process
->QuotaBlock
;
2680 /* Quota Operations are not to be done on the SYSTEM Process */
2681 if (Process
== PsInitialSystemProcess
) return STATUS_SUCCESS
;
2683 /* New Size in use */
2684 NewUsageSize
= QuotaBlock
->QuotaEntry
[PoolType
].Usage
+ Amount
;
2686 /* Does this size respect the quota? */
2687 if (NewUsageSize
> QuotaBlock
->QuotaEntry
[PoolType
].Limit
) {
2689 /* It doesn't, so keep raising the Quota */
2690 while (MiRaisePoolQuota(PoolType
, QuotaBlock
->QuotaEntry
[PoolType
].Limit
, &NewMaxQuota
)) {
2691 /* Save new Maximum Quota */
2692 QuotaBlock
->QuotaEntry
[PoolType
].Limit
= NewMaxQuota
;
2694 /* See if the new Maximum Quota fulfills our need */
2695 if (NewUsageSize
<= NewMaxQuota
) goto QuotaChanged
;
2698 return STATUS_QUOTA_EXCEEDED
;
2702 /* Save new Usage */
2703 QuotaBlock
->QuotaEntry
[PoolType
].Usage
= NewUsageSize
;
2705 /* Is this a new peak? */
2706 if (NewUsageSize
> QuotaBlock
->QuotaEntry
[PoolType
].Peak
) {
2707 QuotaBlock
->QuotaEntry
[PoolType
].Peak
= NewUsageSize
;
2711 return STATUS_SUCCESS
;
2720 IN PEPROCESS Process
,
2721 IN POOL_TYPE PoolType
,
2733 PsReturnProcessNonPagedPoolQuota(
2734 IN PEPROCESS Process
,
2746 PsReturnProcessPagedPoolQuota(
2747 IN PEPROCESS Process
,
2755 PsLockProcess(PEPROCESS Process
, BOOL Timeout
)
2758 PKTHREAD PrevLockOwner
;
2759 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
2760 PLARGE_INTEGER Delay
= (Timeout
? &PsLockTimeout
: NULL
);
2761 PKTHREAD CallingThread
= KeGetCurrentThread();
2763 KeEnterCriticalRegion();
2767 if(Process
->Pcb
.State
== PROCESS_STATE_TERMINATED
)
2769 KeLeaveCriticalRegion();
2770 return STATUS_PROCESS_IS_TERMINATING
;
2773 PrevLockOwner
= (PKTHREAD
)InterlockedCompareExchangePointer(
2774 &Process
->LockOwner
, CallingThread
, NULL
);
2775 if(PrevLockOwner
== NULL
|| PrevLockOwner
== CallingThread
)
2777 /* we got the lock or already locked it */
2778 if(InterlockedIncrementUL(&Process
->LockCount
) == 1)
2780 KeClearEvent(&Process
->LockEvent
);
2783 return STATUS_SUCCESS
;
2789 Status
= KeWaitForSingleObject(&Process
->LockEvent
,
2794 if(!NT_SUCCESS(Status
))
2797 if(Status
== STATUS_TIMEOUT
)
2799 DPRINT1("PsLockProcess(0x%x) timed out!\n", Process
);
2802 KeLeaveCriticalRegion();
2809 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
2818 PsUnlockProcess(PEPROCESS Process
)
2820 ASSERT(Process
->LockOwner
== KeGetCurrentThread());
2822 if(InterlockedDecrementUL(&Process
->LockCount
) == 0)
2824 InterlockedExchangePointer(&Process
->LockOwner
, NULL
);
2825 KeSetEvent(&Process
->LockEvent
, IO_NO_INCREMENT
, FALSE
);
2828 KeLeaveCriticalRegion();