1 /* $Id: process.c,v 1.43 2000/06/03 21:36:32 ekohl Exp $
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 ******************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/mm.h>
17 #include <internal/ke.h>
18 #include <internal/ps.h>
20 #include <internal/string.h>
21 #include <internal/id.h>
22 #include <internal/teb.h>
23 #include <internal/ldr.h>
24 #include <internal/port.h>
26 #include <internal/dbg.h>
29 #include <internal/debug.h>
31 /* GLOBALS ******************************************************************/
33 PEPROCESS EXPORTED PsInitialSystemProcess
= NULL
;
34 HANDLE SystemProcessHandle
= NULL
;
36 POBJECT_TYPE EXPORTED PsProcessType
= NULL
;
38 static LIST_ENTRY PsProcessListHead
;
39 static KSPIN_LOCK PsProcessListLock
;
40 static ULONG PiNextProcessUniqueId
= 0;
42 /* FUNCTIONS *****************************************************************/
44 NTSTATUS STDCALL
NtOpenProcessToken(IN HANDLE ProcessHandle
,
45 IN ACCESS_MASK DesiredAccess
,
46 OUT PHANDLE TokenHandle
)
51 Status
= PsOpenTokenOfProcess(ProcessHandle
,
53 if (!NT_SUCCESS(Status
))
57 Status
= ObCreateHandle(PsGetCurrentProcess(),
62 ObDereferenceObject(Token
);
66 PACCESS_TOKEN STDCALL
PsReferencePrimaryToken(PEPROCESS Process
)
68 ObReferenceObjectByPointer(Process
->Token
,
72 return(Process
->Token
);
75 NTSTATUS
PsOpenTokenOfProcess(HANDLE ProcessHandle
,
81 Status
= ObReferenceObjectByHandle(ProcessHandle
,
82 PROCESS_QUERY_INFORMATION
,
87 if (!NT_SUCCESS(Status
))
91 *Token
= PsReferencePrimaryToken(Process
);
92 ObDereferenceObject(Process
);
93 return(STATUS_SUCCESS
);
96 VOID
PiKillMostProcesses(VOID
)
99 PLIST_ENTRY current_entry
;
102 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
104 current_entry
= PsProcessListHead
.Flink
;
105 while (current_entry
!= &PsProcessListHead
)
107 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
108 Pcb
.ProcessListEntry
);
109 current_entry
= current_entry
->Flink
;
111 if (current
->UniqueProcessId
!= PsInitialSystemProcess
->UniqueProcessId
&&
112 current
->UniqueProcessId
!= (ULONG
)PsGetCurrentProcessId())
114 PiTerminateProcess(current
, STATUS_SUCCESS
);
118 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
121 VOID
PsInitProcessManagment(VOID
)
123 ANSI_STRING AnsiString
;
128 * Register the process object type
131 PsProcessType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
133 PsProcessType
->TotalObjects
= 0;
134 PsProcessType
->TotalHandles
= 0;
135 PsProcessType
->MaxObjects
= ULONG_MAX
;
136 PsProcessType
->MaxHandles
= ULONG_MAX
;
137 PsProcessType
->PagedPoolCharge
= 0;
138 PsProcessType
->NonpagedPoolCharge
= sizeof(EPROCESS
);
139 PsProcessType
->Dump
= NULL
;
140 PsProcessType
->Open
= NULL
;
141 PsProcessType
->Close
= NULL
;
142 PsProcessType
->Delete
= PiDeleteProcess
;
143 PsProcessType
->Parse
= NULL
;
144 PsProcessType
->Security
= NULL
;
145 PsProcessType
->QueryName
= NULL
;
146 PsProcessType
->OkayToClose
= NULL
;
147 PsProcessType
->Create
= NULL
;
149 RtlInitAnsiString(&AnsiString
,"Process");
150 RtlAnsiStringToUnicodeString(&PsProcessType
->TypeName
,&AnsiString
,TRUE
);
152 InitializeListHead(&PsProcessListHead
);
153 KeInitializeSpinLock(&PsProcessListLock
);
156 * Initialize the system process
158 PsInitialSystemProcess
= ObCreateObject(NULL
,
162 PsInitialSystemProcess
->Pcb
.BasePriority
= PROCESS_PRIO_NORMAL
;
163 KeInitializeDispatcherHeader(&PsInitialSystemProcess
->Pcb
.DispatcherHeader
,
167 KProcess
= &PsInitialSystemProcess
->Pcb
;
169 MmInitializeAddressSpace(PsInitialSystemProcess
,
170 &PsInitialSystemProcess
->Pcb
.AddressSpace
);
171 ObCreateHandleTable(NULL
,FALSE
,PsInitialSystemProcess
);
172 KProcess
->PageTableDirectory
= get_page_directory();
173 PsInitialSystemProcess
->UniqueProcessId
=
174 InterlockedIncrement(&PiNextProcessUniqueId
);
176 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
177 InsertHeadList(&PsProcessListHead
, &KProcess
->ProcessListEntry
);
178 InitializeListHead( &KProcess
->ThreadListHead
);
179 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
181 strcpy(PsInitialSystemProcess
->ImageFileName
, "SYSTEM");
183 ObCreateHandle(PsInitialSystemProcess
,
184 PsInitialSystemProcess
,
187 &SystemProcessHandle
);
190 VOID
PiDeleteProcess(PVOID ObjectBody
)
194 DPRINT1("PiDeleteProcess(ObjectBody %x)\n",ObjectBody
);
196 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
197 RemoveEntryList(&((PEPROCESS
)ObjectBody
)->Pcb
.ProcessListEntry
);
198 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
199 (VOID
)MmReleaseMmInfo((PEPROCESS
)ObjectBody
);
200 ObDeleteHandleTable((PEPROCESS
)ObjectBody
);
204 static NTSTATUS
PsCreatePeb(HANDLE ProcessHandle
,
214 memset(&Peb
, 0, sizeof(Peb
));
215 Peb
.ImageBaseAddress
= ImageBase
;
217 PebBase
= (PVOID
)PEB_BASE
;
219 Status
= NtAllocateVirtualMemory(ProcessHandle
,
225 if (!NT_SUCCESS(Status
))
230 ZwWriteVirtualMemory(ProcessHandle
,
236 DPRINT("PsCreatePeb: Peb created at %x\n", PebBase
);
240 return(STATUS_SUCCESS
);
244 PKPROCESS
KeGetCurrentProcess(VOID
)
246 * FUNCTION: Returns a pointer to the current process
249 return(&(PsGetCurrentProcess()->Pcb
));
252 HANDLE STDCALL
PsGetCurrentProcessId(VOID
)
254 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
257 struct _EPROCESS
* PsGetCurrentProcess(VOID
)
259 * FUNCTION: Returns a pointer to the current process
262 if (PsGetCurrentThread() == NULL
||
263 PsGetCurrentThread()->ThreadsProcess
== NULL
)
265 return(PsInitialSystemProcess
);
269 return(PsGetCurrentThread()->ThreadsProcess
);
273 NTSTATUS STDCALL
NtCreateProcess (OUT PHANDLE ProcessHandle
,
274 IN ACCESS_MASK DesiredAccess
,
275 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
276 IN HANDLE ParentProcessHandle
,
277 IN BOOLEAN InheritObjectTable
,
278 IN HANDLE SectionHandle OPTIONAL
,
279 IN HANDLE DebugPortHandle OPTIONAL
,
280 IN HANDLE ExceptionPortHandle OPTIONAL
)
282 * FUNCTION: Creates a process.
284 * ProcessHandle (OUT) = Caller supplied storage for the resulting
286 * DesiredAccess = Specifies the allowed or desired access to the
287 * process can be a combination of
288 * STANDARD_RIGHTS_REQUIRED| ..
289 * ObjectAttribute = Initialized attributes for the object, contains
290 * the rootdirectory and the filename
291 * ParentProcess = Handle to the parent process.
292 * InheritObjectTable = Specifies to inherit the objects of the parent
294 * SectionHandle = Handle to a section object to back the image file
295 * DebugPort = Handle to a DebugPort if NULL the system default debug
297 * ExceptionPort = Handle to a exception port.
299 * This function maps to the win32 CreateProcess.
304 PEPROCESS ParentProcess
;
308 PVOID LdrStartupAddr
;
312 PEPORT ExceptionPort
;
314 DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes
);
316 Status
= ObReferenceObjectByHandle(ParentProcessHandle
,
317 PROCESS_CREATE_PROCESS
,
320 (PVOID
*)&ParentProcess
,
323 if (Status
!= STATUS_SUCCESS
)
325 DPRINT("NtCreateProcess() = %x\n",Status
);
329 Process
= ObCreateObject(ProcessHandle
,
333 KeInitializeDispatcherHeader(&Process
->Pcb
.DispatcherHeader
,
337 KProcess
= &Process
->Pcb
;
339 KProcess
->BasePriority
= PROCESS_PRIO_NORMAL
;
340 MmInitializeAddressSpace(Process
,
341 &KProcess
->AddressSpace
);
342 Process
->UniqueProcessId
= InterlockedIncrement(&PiNextProcessUniqueId
);
343 Process
->InheritedFromUniqueProcessId
= ParentProcess
->UniqueProcessId
;
344 ObCreateHandleTable(ParentProcess
,
347 MmCopyMmInfo(ParentProcess
, Process
);
349 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
350 InsertHeadList(&PsProcessListHead
, &KProcess
->ProcessListEntry
);
351 InitializeListHead( &KProcess
->ThreadListHead
);
352 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
354 Process
->Pcb
.ProcessState
= PROCESS_STATE_ACTIVE
;
359 if (DebugPortHandle
!= NULL
)
361 Status
= ObReferenceObjectByHandle(DebugPortHandle
,
367 if (!NT_SUCCESS(Status
))
369 ObDereferenceObject(Process
);
370 ObDereferenceObject(ParentProcess
);
371 ZwClose(*ProcessHandle
);
372 *ProcessHandle
= NULL
;
375 Process
->DebugPort
= DebugPort
;
379 * Add the exception port
381 if (ExceptionPortHandle
!= NULL
)
383 Status
= ObReferenceObjectByHandle(ExceptionPortHandle
,
387 (PVOID
*)&ExceptionPort
,
389 if (!NT_SUCCESS(Status
))
391 ObDereferenceObject(Process
);
392 ObDereferenceObject(ParentProcess
);
393 ZwClose(*ProcessHandle
);
394 *ProcessHandle
= NULL
;
397 Process
->ExceptionPort
= ExceptionPort
;
401 * Now we have created the process proper
407 Status
= LdrpMapSystemDll(*ProcessHandle
,
409 if (!NT_SUCCESS(Status
))
411 DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status
);
412 ObDereferenceObject(Process
);
413 ObDereferenceObject(ParentProcess
);
418 * Map the process image
420 if (SectionHandle
!= NULL
)
422 DPRINT("Mapping process image\n");
423 Status
= LdrpMapImage(*ProcessHandle
,
426 if (!NT_SUCCESS(Status
))
428 DbgPrint("LdrpMapImage failed (Status %x)\n", Status
);
429 ObDereferenceObject(Process
);
430 ObDereferenceObject(ParentProcess
);
442 DPRINT("Creating PEB\n");
443 Status
= PsCreatePeb(*ProcessHandle
,
446 if (!NT_SUCCESS(Status
))
448 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
449 ObDereferenceObject(Process
);
450 ObDereferenceObject(ParentProcess
);
451 ZwClose(*ProcessHandle
);
452 *ProcessHandle
= NULL
;
458 * Maybe send a message to the creator process's debugger
460 if (ParentProcess
->DebugPort
!= NULL
)
462 LPC_DBG_MESSAGE Message
;
465 ObCreateHandle(NULL
, // Debugger Process
466 NULL
, // SectionHandle
471 Message
.Header
.MessageSize
= sizeof(LPC_DBG_MESSAGE
);
472 Message
.Header
.DataSize
= sizeof(LPC_DBG_MESSAGE
) -
473 sizeof(LPC_MESSAGE_HEADER
);
474 Message
.Type
= DBG_EVENT_CREATE_PROCESS
;
475 Message
.Data
.CreateProcess
.FileHandle
= FileHandle
;
476 Message
.Data
.CreateProcess
.Base
= ImageBase
;
477 Message
.Data
.CreateProcess
.EntryPoint
= NULL
; //
479 Status
= LpcSendDebugMessagePort(ParentProcess
->DebugPort
,
483 ObDereferenceObject(Process
);
484 ObDereferenceObject(ParentProcess
);
485 return(STATUS_SUCCESS
);
489 NTSTATUS STDCALL
NtOpenProcess (OUT PHANDLE ProcessHandle
,
490 IN ACCESS_MASK DesiredAccess
,
491 IN POBJECT_ATTRIBUTES ObjectAttributes
,
492 IN PCLIENT_ID ClientId
)
494 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
495 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
496 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
497 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
501 * Not sure of the exact semantics
503 if (ObjectAttributes
!= NULL
&& ObjectAttributes
->ObjectName
!= NULL
&&
504 ObjectAttributes
->ObjectName
->Buffer
!= NULL
)
509 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
510 ObjectAttributes
->Attributes
,
517 if (Status
!= STATUS_SUCCESS
)
522 Status
= ObCreateHandle(PsGetCurrentProcess(),
527 ObDereferenceObject(Process
);
534 PLIST_ENTRY current_entry
;
538 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
539 current_entry
= PsProcessListHead
.Flink
;
540 while (current_entry
!= &PsProcessListHead
)
542 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
543 Pcb
.ProcessListEntry
);
544 if (current
->UniqueProcessId
== (ULONG
)ClientId
->UniqueProcess
)
546 ObReferenceObjectByPointer(current
,
550 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
551 Status
= ObCreateHandle(PsGetCurrentProcess(),
556 ObDereferenceObject(current
);
557 DPRINT("*ProcessHandle %x\n", ProcessHandle
);
558 DPRINT("NtOpenProcess() = %x\n", Status
);
561 current_entry
= current_entry
->Flink
;
563 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
564 DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
565 return(STATUS_UNSUCCESSFUL
);
567 return(STATUS_UNSUCCESSFUL
);
571 NTSTATUS STDCALL
NtQueryInformationProcess (IN HANDLE ProcessHandle
,
572 IN CINT ProcessInformationClass
,
573 OUT PVOID ProcessInformation
,
574 IN ULONG ProcessInformationLength
,
575 OUT PULONG ReturnLength
)
579 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
;
581 Status
= ObReferenceObjectByHandle(ProcessHandle
,
582 PROCESS_SET_INFORMATION
,
587 if (Status
!= STATUS_SUCCESS
)
592 switch (ProcessInformationClass
)
594 case ProcessBasicInformation
:
595 ProcessBasicInformationP
= (PPROCESS_BASIC_INFORMATION
)
597 ProcessBasicInformationP
->ExitStatus
= Process
->ExitStatus
;
598 ProcessBasicInformationP
->PebBaseAddress
= Process
->Peb
;
599 ProcessBasicInformationP
->AffinityMask
= Process
->Pcb
.Affinity
;
600 ProcessBasicInformationP
->UniqueProcessId
=
601 Process
->UniqueProcessId
;
602 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
603 Process
->InheritedFromUniqueProcessId
;
604 Status
= STATUS_SUCCESS
;
607 case ProcessQuotaLimits
:
608 case ProcessIoCounters
:
609 case ProcessVmCounters
:
611 case ProcessBasePriority
:
612 case ProcessRaisePriority
:
613 case ProcessDebugPort
:
614 case ProcessExceptionPort
:
615 case ProcessAccessToken
:
616 case ProcessLdtInformation
:
618 Status
= STATUS_NOT_IMPLEMENTED
;
621 case ProcessDefaultHardErrorMode
:
622 *((PULONG
)ProcessInformation
) = Process
->DefaultHardErrorProcessing
;
625 case ProcessIoPortHandlers
:
626 case ProcessWorkingSetWatch
:
627 case ProcessUserModeIOPL
:
628 case ProcessEnableAlignmentFaultFixup
:
629 case ProcessPriorityClass
:
630 case ProcessWx86Information
:
631 case ProcessHandleCount
:
632 case ProcessAffinityMask
:
634 Status
= STATUS_NOT_IMPLEMENTED
;
636 ObDereferenceObject(Process
);
640 NTSTATUS
PspAssignPrimaryToken(PEPROCESS Process
,
644 PACCESS_TOKEN OldToken
;
647 Status
= ObReferenceObjectByHandle(TokenHandle
,
653 if (!NT_SUCCESS(Status
))
657 Status
= SeExchangePrimaryToken(Process
, Token
, &OldToken
);
658 if (!NT_SUCCESS(Status
))
660 ObDereferenceObject(OldToken
);
662 ObDereferenceObject(Token
);
666 NTSTATUS STDCALL
NtSetInformationProcess(IN HANDLE ProcessHandle
,
667 IN CINT ProcessInformationClass
,
668 IN PVOID ProcessInformation
,
669 IN ULONG ProcessInformationLength
)
673 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
;
674 PHANDLE ProcessAccessTokenP
;
676 Status
= ObReferenceObjectByHandle(ProcessHandle
,
677 PROCESS_SET_INFORMATION
,
682 if (!NT_SUCCESS(Status
))
687 switch (ProcessInformationClass
)
689 case ProcessBasicInformation
:
690 ProcessBasicInformationP
= (PPROCESS_BASIC_INFORMATION
)
692 memset(ProcessBasicInformationP
, 0, sizeof(PROCESS_BASIC_INFORMATION
));
693 Process
->Pcb
.Affinity
= ProcessBasicInformationP
->AffinityMask
;
694 Status
= STATUS_SUCCESS
;
697 case ProcessQuotaLimits
:
698 case ProcessIoCounters
:
699 case ProcessVmCounters
:
701 case ProcessBasePriority
:
702 case ProcessRaisePriority
:
703 case ProcessDebugPort
:
704 case ProcessExceptionPort
:
705 case ProcessAccessToken
:
706 ProcessAccessTokenP
= (PHANDLE
)ProcessInformation
;
707 Status
= PspAssignPrimaryToken(Process
, *ProcessAccessTokenP
);
710 case ProcessImageFileName
:
711 memcpy(Process
->ImageFileName
, ProcessInformation
, 8);
712 // DPRINT1("Process->ImageFileName %.8s\n", Process->ImageFileName);
713 Status
= STATUS_SUCCESS
;
716 case ProcessLdtInformation
:
718 case ProcessDefaultHardErrorMode
:
719 case ProcessIoPortHandlers
:
720 case ProcessWorkingSetWatch
:
721 case ProcessUserModeIOPL
:
722 case ProcessEnableAlignmentFaultFixup
:
723 case ProcessPriorityClass
:
724 case ProcessWx86Information
:
725 case ProcessHandleCount
:
726 case ProcessAffinityMask
:
728 Status
= STATUS_NOT_IMPLEMENTED
;
730 ObDereferenceObject(Process
);
736 /**********************************************************************
738 * PiSnapshotProcessTable
741 * Compute the size of a process+thread snapshot as
742 * expected by NtQuerySystemInformation.
745 * 0 on error; otherwise the size, in bytes of the buffer
746 * required to write a full snapshot.
749 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
753 PiSnapshotProcessTable (
754 IN PVOID SnapshotBuffer
,
756 IN PULONG pRequiredSize
760 PLIST_ENTRY CurrentEntry
;
763 ULONG RequiredSize
= 0L;
764 BOOLEAN SizeOnly
= FALSE
;
766 ULONG SpiSizeLast
= 0L;
767 ULONG SpiSizeCurrent
= 0L;
769 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
770 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
774 * Lock the process list.
781 * Scan the process list. Since the
782 * list is circular, the guard is false
783 * after the last process.
785 for ( CurrentEntry
= PsProcessListHead
.Flink
;
786 (CurrentEntry
!= & PsProcessListHead
);
787 CurrentEntry
= CurrentEntry
->Flink
791 * Get a reference to the
792 * process object we are
795 Current
= CONTAINING_RECORD(
800 /* FIXME: assert (NULL != Current) */
802 * Compute how much space is
803 * occupied in the snapshot
804 * by adding this process info.
807 sizeof (SYSTEM_PROCESS_INFORMATION
)
809 (Current
->ThreadCount
- 1)
810 * sizeof (SYSTEM_THREAD_INFORMATION
)
812 RequiredSize
+= SpiSizeCurrent
;
814 * Do not write process data in the
815 * buffer if it is too small.
817 if (TRUE
== SizeOnly
) continue;
819 * Check if the buffer can contain
822 if (Size
< RequiredSize
)
828 * Compute the offset of the
829 * SYSTEM_PROCESS_INFORMATION
830 * descriptor in the snapshot
831 * buffer for this process.
833 if (0L != SpiSizeLast
)
835 (ULONG
) pInfoP
+= SpiSizeLast
;
836 /* Save current process SpiSize */
837 SpiSizeLast
= SpiSizeCurrent
;
840 * Write process data in the buffer.
842 pInfoP
->RelativeOffset
= SpiSizeCurrent
;
844 pInfoP
->ThreadCount
=
845 pInfoP
->ProcessId
= Current
->UniqueProcessId
;
846 RtlInitUnicodeString (
848 Current
->ImageFileName
851 for ( ThreadIndex
= 0;
852 (ThreadIndex
< Current
->ThreadCount
);
859 * Unlock the process list.
866 * Return the proper error status code,
867 * if the buffer was too small.
869 if (TRUE
== SizeOnly
)
871 *pRequiredSize
= RequiredSize
;
872 return STATUS_INFO_LENGTH_MISMATCH
;
875 * Mark the end of the snapshot.
877 pInfoP
->RelativeOffset
= 0L;
879 return STATUS_SUCCESS
;