the system process should be called "System", not "SYSTEM"
[reactos.git] / reactos / ntoskrnl / ps / process.c
1 /* $Id$
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 /* GLOBALS ******************************************************************/
19
20 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
21
22 POBJECT_TYPE EXPORTED PsProcessType = NULL;
23
24 LIST_ENTRY PsProcessListHead;
25 static KSPIN_LOCK PsProcessListLock;
26 static ULONG PiNextProcessUniqueId = 0; /* TODO */
27 static LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
28
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,
34 PROCESS_ALL_ACCESS};
35
36 static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
37 {
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 */
61
62 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */
63 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
64 /*Q*/ sizeof(USHORT),
65 /*S*/ sizeof(USHORT),
66 ICIF_QUERY | ICIF_SET ),
67
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 */
72 };
73
74 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8
75 #define MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT 8
76
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];
81
82
83 typedef struct
84 {
85 WORK_QUEUE_ITEM WorkQueueItem;
86 KEVENT Event;
87 PEPROCESS Process;
88 BOOLEAN IsWorkerQueue;
89 } DEL_CONTEXT, *PDEL_CONTEXT;
90
91 /* FUNCTIONS *****************************************************************/
92
93 VOID
94 STDCALL
95 PsExitSpecialApc(PKAPC Apc,
96 PKNORMAL_ROUTINE *NormalRoutine,
97 PVOID *NormalContext,
98 PVOID *SystemArgument1,
99 PVOID *SystemArgument2)
100 {
101 }
102
103 PEPROCESS
104 PsGetNextProcess(PEPROCESS OldProcess)
105 {
106 KIRQL oldIrql;
107 PEPROCESS NextProcess;
108 NTSTATUS Status;
109
110 if (OldProcess == NULL)
111 {
112 Status = ObReferenceObjectByPointer(PsInitialSystemProcess,
113 PROCESS_ALL_ACCESS,
114 PsProcessType,
115 KernelMode);
116 if (!NT_SUCCESS(Status))
117 {
118 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsInitialSystemProcess\n");
119 KEBUGCHECK(0);
120 }
121 return PsInitialSystemProcess;
122 }
123
124 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
125 NextProcess = OldProcess;
126 while (1)
127 {
128 if (NextProcess->ProcessListEntry.Blink == &PsProcessListHead)
129 {
130 NextProcess = CONTAINING_RECORD(PsProcessListHead.Blink,
131 EPROCESS,
132 ProcessListEntry);
133 }
134 else
135 {
136 NextProcess = CONTAINING_RECORD(NextProcess->ProcessListEntry.Blink,
137 EPROCESS,
138 ProcessListEntry);
139 }
140 Status = ObReferenceObjectByPointer(NextProcess,
141 PROCESS_ALL_ACCESS,
142 PsProcessType,
143 KernelMode);
144 if (NT_SUCCESS(Status))
145 {
146 break;
147 }
148 else if (Status == STATUS_PROCESS_IS_TERMINATING)
149 {
150 continue;
151 }
152 else if (!NT_SUCCESS(Status))
153 {
154 CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
155 KEBUGCHECK(0);
156 }
157 }
158
159 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
160 ObDereferenceObject(OldProcess);
161
162 return(NextProcess);
163 }
164
165
166 /*
167 * @implemented
168 */
169 NTSTATUS STDCALL
170 NtOpenProcessToken(IN HANDLE ProcessHandle,
171 IN ACCESS_MASK DesiredAccess,
172 OUT PHANDLE TokenHandle)
173 {
174 return NtOpenProcessTokenEx(ProcessHandle,
175 DesiredAccess,
176 0,
177 TokenHandle);
178 }
179
180
181 /*
182 * @unimplemented
183 */
184 NTSTATUS
185 STDCALL
186 NtOpenProcessTokenEx(
187 IN HANDLE ProcessHandle,
188 IN ACCESS_MASK DesiredAccess,
189 IN ULONG HandleAttributes,
190 OUT PHANDLE TokenHandle
191 )
192 {
193 PACCESS_TOKEN Token;
194 HANDLE hToken;
195 NTSTATUS Status;
196
197 Status = PsOpenTokenOfProcess(ProcessHandle,
198 &Token);
199 if (!NT_SUCCESS(Status))
200 {
201 return(Status);
202 }
203 Status = ObCreateHandle(PsGetCurrentProcess(),
204 Token,
205 DesiredAccess,
206 FALSE,
207 &hToken);
208 ObDereferenceObject(Token);
209
210 if(NT_SUCCESS(Status))
211 {
212 Status = MmCopyToCaller(TokenHandle, &hToken, sizeof(HANDLE));
213 }
214 return(Status);
215 }
216
217
218 /*
219 * @implemented
220 */
221 PACCESS_TOKEN STDCALL
222 PsReferencePrimaryToken(PEPROCESS Process)
223 {
224 ObReferenceObjectByPointer(Process->Token,
225 TOKEN_ALL_ACCESS,
226 SepTokenObjectType,
227 UserMode);
228 return(Process->Token);
229 }
230
231
232 NTSTATUS
233 PsOpenTokenOfProcess(HANDLE ProcessHandle,
234 PACCESS_TOKEN* Token)
235 {
236 PEPROCESS Process;
237 NTSTATUS Status;
238
239 Status = ObReferenceObjectByHandle(ProcessHandle,
240 PROCESS_QUERY_INFORMATION,
241 PsProcessType,
242 UserMode,
243 (PVOID*)&Process,
244 NULL);
245 if (!NT_SUCCESS(Status))
246 {
247 return(Status);
248 }
249 *Token = PsReferencePrimaryToken(Process);
250 ObDereferenceObject(Process);
251 return(STATUS_SUCCESS);
252 }
253
254
255 VOID
256 PiKillMostProcesses(VOID)
257 {
258 KIRQL oldIrql;
259 PLIST_ENTRY current_entry;
260 PEPROCESS current;
261
262 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
263
264 current_entry = PsProcessListHead.Flink;
265 while (current_entry != &PsProcessListHead)
266 {
267 current = CONTAINING_RECORD(current_entry, EPROCESS,
268 ProcessListEntry);
269 current_entry = current_entry->Flink;
270
271 if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId &&
272 current->UniqueProcessId != (ULONG)PsGetCurrentProcessId())
273 {
274 PiTerminateProcessThreads(current, STATUS_SUCCESS);
275 }
276 }
277
278 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
279 }
280
281
282 VOID INIT_FUNCTION
283 PsInitProcessManagment(VOID)
284 {
285 PKPROCESS KProcess;
286 KIRQL oldIrql;
287 NTSTATUS Status;
288
289 ShortPsLockDelay.QuadPart = -100LL;
290 PsLockTimeout.QuadPart = -10000000LL; /* one second */
291 /*
292 * Register the process object type
293 */
294
295 PsProcessType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
296
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;
315
316 RtlRosInitUnicodeStringFromLiteral(&PsProcessType->TypeName, L"Process");
317
318 ObpCreateTypeObject(PsProcessType);
319
320 InitializeListHead(&PsProcessListHead);
321 KeInitializeSpinLock(&PsProcessListLock);
322
323 RtlZeroMemory(PiProcessNotifyRoutine, sizeof(PiProcessNotifyRoutine));
324 RtlZeroMemory(PiLoadImageNotifyRoutine, sizeof(PiLoadImageNotifyRoutine));
325
326 /*
327 * Initialize the system process
328 */
329 Status = ObCreateObject(KernelMode,
330 PsProcessType,
331 NULL,
332 KernelMode,
333 NULL,
334 sizeof(EPROCESS),
335 0,
336 0,
337 (PVOID*)&PsInitialSystemProcess);
338 if (!NT_SUCCESS(Status))
339 {
340 return;
341 }
342
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,
352 InternalProcessType,
353 sizeof(EPROCESS),
354 FALSE);
355 KProcess = &PsInitialSystemProcess->Pcb;
356
357 MmInitializeAddressSpace(PsInitialSystemProcess,
358 &PsInitialSystemProcess->AddressSpace);
359 ObCreateHandleTable(NULL,FALSE,PsInitialSystemProcess);
360
361 KeInitializeEvent(&PsInitialSystemProcess->LockEvent, SynchronizationEvent, FALSE);
362 PsInitialSystemProcess->LockCount = 0;
363 PsInitialSystemProcess->LockOwner = NULL;
364
365 #if defined(__GNUC__)
366 KProcess->DirectoryTableBase =
367 (LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
368 #else
369 {
370 LARGE_INTEGER dummy;
371 dummy.QuadPart = (LONGLONG)(ULONG)MmGetPageDirectory();
372 KProcess->DirectoryTableBase = dummy;
373 }
374 #endif
375
376 PsInitialSystemProcess->UniqueProcessId =
377 InterlockedIncrementUL(&PiNextProcessUniqueId); /* TODO */
378 PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
379
380 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
381 InsertHeadList(&PsProcessListHead,
382 &PsInitialSystemProcess->ProcessListEntry);
383 InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
384 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
385
386 strcpy(PsInitialSystemProcess->ImageFileName, "System");
387
388 SepCreateSystemProcessToken(PsInitialSystemProcess);
389 }
390
391 VOID STDCALL
392 PiDeleteProcessWorker(PVOID pContext)
393 {
394 KIRQL oldIrql;
395 PDEL_CONTEXT Context;
396 PEPROCESS CurrentProcess;
397 PEPROCESS Process;
398
399 Context = (PDEL_CONTEXT)pContext;
400 Process = Context->Process;
401 CurrentProcess = PsGetCurrentProcess();
402
403 DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process);
404
405 if (CurrentProcess != Process)
406 {
407 KeAttachProcess(&Process->Pcb);
408 }
409
410 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
411 RemoveEntryList(&Process->ProcessListEntry);
412 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
413
414 /* KDB hook */
415 KDB_DELETEPROCESS_HOOK(Process);
416
417 ObDereferenceObject(Process->Token);
418 ObDeleteHandleTable(Process);
419
420 if (CurrentProcess != Process)
421 {
422 KeDetachProcess();
423 }
424
425 MmReleaseMmInfo(Process);
426 if (Context->IsWorkerQueue)
427 {
428 KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
429 }
430 }
431
432 VOID STDCALL
433 PiDeleteProcess(PVOID ObjectBody)
434 {
435 DEL_CONTEXT Context;
436
437 Context.Process = (PEPROCESS)ObjectBody;
438
439 if (PsGetCurrentProcess() == Context.Process ||
440 PsGetCurrentThread()->ThreadsProcess == Context.Process)
441 {
442 KEBUGCHECK(0);
443 }
444
445 if (PsGetCurrentThread()->ThreadsProcess == PsGetCurrentProcess())
446 {
447 Context.IsWorkerQueue = FALSE;
448 PiDeleteProcessWorker(&Context);
449 }
450 else
451 {
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)
457 {
458 KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
459 }
460 }
461
462 if(((PEPROCESS)ObjectBody)->Win32Process != NULL)
463 {
464 /* delete the W32PROCESS structure if there's one associated */
465 ExFreePool (((PEPROCESS)ObjectBody)->Win32Process);
466 }
467 }
468
469 static NTSTATUS
470 PsCreatePeb(HANDLE ProcessHandle,
471 PEPROCESS Process,
472 PVOID ImageBase)
473 {
474 ULONG AllocSize;
475 ULONG PebSize;
476 PPEB Peb;
477 LARGE_INTEGER SectionOffset;
478 ULONG ViewSize;
479 PVOID TableBase;
480 NTSTATUS Status;
481
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,
486 &Process->TebBlock,
487 0,
488 &AllocSize,
489 MEM_RESERVE,
490 PAGE_READWRITE);
491 if (!NT_SUCCESS(Status))
492 {
493 DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
494 return(Status);
495 }
496 ASSERT((ULONG_PTR) Process->TebBlock <= PEB_BASE &&
497 PEB_BASE + PAGE_SIZE <= (ULONG_PTR) Process->TebBlock + AllocSize);
498 Peb = (PPEB)PEB_BASE;
499 PebSize = PAGE_SIZE;
500 Status = NtAllocateVirtualMemory(ProcessHandle,
501 (PVOID*)&Peb,
502 0,
503 &PebSize,
504 MEM_COMMIT,
505 PAGE_READWRITE);
506 if (!NT_SUCCESS(Status))
507 {
508 DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
509 return(Status);
510 }
511 DPRINT("Peb %p PebSize %lu\n", Peb, PebSize);
512 ASSERT((PPEB) PEB_BASE == Peb && PAGE_SIZE <= PebSize);
513 Process->TebLastAllocated = (PVOID) Peb;
514
515 ViewSize = 0;
516 SectionOffset.QuadPart = (ULONGLONG)0;
517 TableBase = NULL;
518 Status = MmMapViewOfSection(NlsSectionObject,
519 Process,
520 &TableBase,
521 0,
522 0,
523 &SectionOffset,
524 &ViewSize,
525 ViewShare,
526 MEM_TOP_DOWN,
527 PAGE_READONLY);
528 if (!NT_SUCCESS(Status))
529 {
530 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
531 return(Status);
532 }
533 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
534
535 KeAttachProcess(&Process->Pcb);
536
537 /* Initialize the PEB */
538 RtlZeroMemory(Peb, sizeof(PEB));
539 Peb->ImageBaseAddress = ImageBase;
540
541 Peb->OSMajorVersion = 4;
542 Peb->OSMinorVersion = 0;
543 Peb->OSBuildNumber = 1381;
544 Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
545 Peb->SPMajorVersion = 6;
546
547 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
548 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
549 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
550
551 Process->Peb = Peb;
552 KeDetachProcess();
553
554 DPRINT("PsCreatePeb: Peb created at %p\n", Peb);
555
556 return(STATUS_SUCCESS);
557 }
558
559
560 PKPROCESS
561 KeGetCurrentProcess(VOID)
562 /*
563 * FUNCTION: Returns a pointer to the current process
564 */
565 {
566 return(&(PsGetCurrentProcess()->Pcb));
567 }
568
569 /*
570 * Warning: Even though it returns HANDLE, it's not a real HANDLE but really a
571 * ULONG ProcessId! (Skywing)
572 */
573 /*
574 * @implemented
575 */
576 HANDLE STDCALL
577 PsGetCurrentProcessId(VOID)
578 {
579 return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
580 }
581
582 /*
583 * @unimplemented
584 */
585 ULONG
586 STDCALL
587 PsGetCurrentProcessSessionId (
588 VOID
589 )
590 {
591 return PsGetCurrentProcess()->SessionId;
592 }
593
594 /*
595 * FUNCTION: Returns a pointer to the current process
596 *
597 * @implemented
598 */
599 PEPROCESS STDCALL
600 IoGetCurrentProcess(VOID)
601 {
602 if (PsGetCurrentThread() == NULL ||
603 PsGetCurrentThread()->Tcb.ApcState.Process == NULL)
604 {
605 return(PsInitialSystemProcess);
606 }
607 else
608 {
609 return(PEPROCESS)(PsGetCurrentThread()->Tcb.ApcState.Process);
610 }
611 }
612
613 /*
614 * @implemented
615 */
616 NTSTATUS STDCALL
617 PsCreateSystemProcess(PHANDLE ProcessHandle,
618 ACCESS_MASK DesiredAccess,
619 POBJECT_ATTRIBUTES ObjectAttributes)
620 {
621 HANDLE SystemProcessHandle;
622 NTSTATUS Status;
623
624 /* FIXME - what about security? should there be any privilege checks or something
625 security related? */
626
627 Status = ObCreateHandle(PsGetCurrentProcess(),
628 PsInitialSystemProcess,
629 PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION,
630 FALSE,
631 &SystemProcessHandle);
632 if(!NT_SUCCESS(Status))
633 {
634 DPRINT1("Failed to create a handle for the system process!\n");
635 return Status;
636 }
637
638 Status = NtCreateProcess(ProcessHandle,
639 DesiredAccess,
640 ObjectAttributes,
641 SystemProcessHandle,
642 FALSE,
643 NULL,
644 NULL,
645 NULL);
646
647 NtClose(SystemProcessHandle);
648
649 return Status;
650 }
651
652 NTSTATUS STDCALL
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)
661 /*
662 * FUNCTION: Creates a process.
663 * ARGUMENTS:
664 * ProcessHandle (OUT) = Caller supplied storage for the resulting
665 * handle
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
673 * process if true.
674 * SectionHandle = Handle to a section object to back the image file
675 * DebugPort = Handle to a DebugPort if NULL the system default debug
676 * port will be used.
677 * ExceptionPort = Handle to a exception port.
678 * REMARKS:
679 * This function maps to the win32 CreateProcess.
680 * RETURNS: Status
681 */
682 {
683 PEPROCESS Process;
684 PEPROCESS pParentProcess;
685 PKPROCESS KProcess;
686 NTSTATUS Status;
687 KIRQL oldIrql;
688 PVOID LdrStartupAddr;
689 PVOID ImageBase;
690 PEPORT pDebugPort;
691 PEPORT pExceptionPort;
692 PVOID BaseAddress;
693 PMEMORY_AREA MemoryArea;
694 PHYSICAL_ADDRESS BoundaryAddressMultiple;
695
696 DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
697
698 BoundaryAddressMultiple.QuadPart = 0;
699
700 Status = ObReferenceObjectByHandle(ParentProcess,
701 PROCESS_CREATE_PROCESS,
702 PsProcessType,
703 ExGetPreviousMode(),
704 (PVOID*)&pParentProcess,
705 NULL);
706 if (!NT_SUCCESS(Status))
707 {
708 DPRINT("NtCreateProcess() = %x\n",Status);
709 return(Status);
710 }
711
712 Status = ObCreateObject(ExGetPreviousMode(),
713 PsProcessType,
714 ObjectAttributes,
715 ExGetPreviousMode(),
716 NULL,
717 sizeof(EPROCESS),
718 0,
719 0,
720 (PVOID*)&Process);
721 if (!NT_SUCCESS(Status))
722 {
723 ObDereferenceObject(pParentProcess);
724 DPRINT("ObCreateObject() = %x\n",Status);
725 return(Status);
726 }
727
728 Status = ObInsertObject ((PVOID)Process,
729 NULL,
730 DesiredAccess,
731 0,
732 NULL,
733 ProcessHandle);
734 if (!NT_SUCCESS(Status))
735 {
736 ObDereferenceObject (Process);
737 ObDereferenceObject (pParentProcess);
738 DPRINT("ObInsertObject() = %x\n",Status);
739 return Status;
740 }
741
742 KeInitializeDispatcherHeader(&Process->Pcb.DispatcherHeader,
743 InternalProcessType,
744 sizeof(EPROCESS),
745 FALSE);
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,
762 InheritObjectTable,
763 Process);
764 MmCopyMmInfo(ParentProcess, Process);
765
766 KeInitializeEvent(&Process->LockEvent, SynchronizationEvent, FALSE);
767 Process->LockCount = 0;
768 Process->LockOwner = NULL;
769
770 Process->Win32WindowStation = (HANDLE)0;
771
772 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
773 InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
774 InitializeListHead(&Process->ThreadListHead);
775 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
776
777 ExInitializeFastMutex(&Process->TebLock);
778 Process->Pcb.State = PROCESS_STATE_ACTIVE;
779
780 /*
781 * Add the debug port
782 */
783 if (DebugPort != NULL)
784 {
785 Status = ObReferenceObjectByHandle(DebugPort,
786 PORT_ALL_ACCESS,
787 LpcPortObjectType,
788 UserMode,
789 (PVOID*)&pDebugPort,
790 NULL);
791 if (!NT_SUCCESS(Status))
792 {
793 ObDereferenceObject(Process);
794 ObDereferenceObject(pParentProcess);
795 ZwClose(*ProcessHandle);
796 *ProcessHandle = NULL;
797 return(Status);
798 }
799 Process->DebugPort = pDebugPort;
800 }
801
802 /*
803 * Add the exception port
804 */
805 if (ExceptionPort != NULL)
806 {
807 Status = ObReferenceObjectByHandle(ExceptionPort,
808 PORT_ALL_ACCESS,
809 LpcPortObjectType,
810 UserMode,
811 (PVOID*)&pExceptionPort,
812 NULL);
813 if (!NT_SUCCESS(Status))
814 {
815 ObDereferenceObject(Process);
816 ObDereferenceObject(pParentProcess);
817 ZwClose(*ProcessHandle);
818 *ProcessHandle = NULL;
819 return(Status);
820 }
821 Process->ExceptionPort = pExceptionPort;
822 }
823
824 /*
825 * Now we have created the process proper
826 */
827
828 MmLockAddressSpace(&Process->AddressSpace);
829
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,
835 &BaseAddress,
836 0x10000,
837 PAGE_NOACCESS,
838 &MemoryArea,
839 FALSE,
840 FALSE,
841 BoundaryAddressMultiple);
842 if (!NT_SUCCESS(Status))
843 {
844 MmUnlockAddressSpace(&Process->AddressSpace);
845 DPRINT1("Failed to protect the highest 64KB of the process address space\n");
846 KEBUGCHECK(0);
847 }
848
849 /* Protect the lowest 64KB of the process address space */
850 #if 0
851 BaseAddress = (PVOID)0x00000000;
852 Status = MmCreateMemoryArea(Process,
853 &Process->AddressSpace,
854 MEMORY_AREA_NO_ACCESS,
855 &BaseAddress,
856 0x10000,
857 PAGE_NOACCESS,
858 &MemoryArea,
859 FALSE,
860 FALSE,
861 BoundaryAddressMultiple);
862 if (!NT_SUCCESS(Status))
863 {
864 MmUnlockAddressSpace(&Process->AddressSpace);
865 DPRINT1("Failed to protect the lowest 64KB of the process address space\n");
866 KEBUGCHECK(0);
867 }
868 #endif
869
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,
875 &BaseAddress,
876 0x10000 - PAGE_SIZE,
877 PAGE_NOACCESS,
878 &MemoryArea,
879 FALSE,
880 FALSE,
881 BoundaryAddressMultiple);
882 if (!NT_SUCCESS(Status))
883 {
884 MmUnlockAddressSpace(&Process->AddressSpace);
885 DPRINT1("Failed to protect the memory above the shared user page\n");
886 KEBUGCHECK(0);
887 }
888
889 /* Create the shared data page */
890 BaseAddress = (PVOID)USER_SHARED_DATA;
891 Status = MmCreateMemoryArea(Process,
892 &Process->AddressSpace,
893 MEMORY_AREA_SHARED_DATA,
894 &BaseAddress,
895 PAGE_SIZE,
896 PAGE_READONLY,
897 &MemoryArea,
898 FALSE,
899 FALSE,
900 BoundaryAddressMultiple);
901 MmUnlockAddressSpace(&Process->AddressSpace);
902 if (!NT_SUCCESS(Status))
903 {
904 DPRINT1("Failed to create shared data page\n");
905 KEBUGCHECK(0);
906 }
907
908 if (SectionHandle != NULL)
909 {
910 PSECTION_OBJECT SectionObject;
911 UNICODE_STRING FileName;
912 PWCHAR szSrc;
913 PCHAR szDest;
914 USHORT lnFName = 0;
915
916 /*
917 * Determine the image file name and save it to the EPROCESS structure
918 */
919 Status = ObReferenceObjectByHandle(SectionHandle,
920 0,
921 MmSectionObjectType,
922 UserMode,
923 (PVOID*)&SectionObject,
924 NULL);
925 if (!NT_SUCCESS(Status))
926 {
927 DbgPrint("Failed to reference section object\n", Status);
928 ObDereferenceObject(Process);
929 ObDereferenceObject(pParentProcess);
930 return(Status);
931 }
932
933 FileName = SectionObject->FileObject->FileName;
934 szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
935 while(szSrc >= FileName.Buffer)
936 {
937 if(*szSrc == L'\\')
938 {
939 szSrc++;
940 break;
941 }
942 else
943 {
944 szSrc--;
945 lnFName++;
946 }
947 }
948
949 /* copy the image file name to the process and truncate it to 15 characters
950 if necessary */
951 szDest = Process->ImageFileName;
952 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
953 while(lnFName-- > 0)
954 {
955 *(szDest++) = (UCHAR)*(szSrc++);
956 }
957 *szDest = '\0';
958
959
960 ObDereferenceObject(SectionObject);
961 }
962 else
963 {
964 Process->ImageFileName[0] = '\0';
965 }
966
967 /*
968 * Map ntdll
969 */
970 Status = LdrpMapSystemDll(*ProcessHandle,
971 &LdrStartupAddr);
972 if (!NT_SUCCESS(Status))
973 {
974 DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status);
975 ObDereferenceObject(Process);
976 ObDereferenceObject(pParentProcess);
977 return(Status);
978 }
979
980 /*
981 * Map the process image
982 */
983 if (SectionHandle != NULL)
984 {
985 DPRINT("Mapping process image\n");
986 Status = LdrpMapImage(*ProcessHandle,
987 SectionHandle,
988 &ImageBase);
989 if (!NT_SUCCESS(Status))
990 {
991 DbgPrint("LdrpMapImage failed (Status %x)\n", Status);
992 ObDereferenceObject(Process);
993 ObDereferenceObject(pParentProcess);
994 return(Status);
995 }
996 }
997 else
998 {
999 ImageBase = NULL;
1000 }
1001
1002 /*
1003 * Duplicate the token
1004 */
1005 Status = SepInitializeNewProcess(Process, pParentProcess);
1006 if (!NT_SUCCESS(Status))
1007 {
1008 DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status);
1009 ObDereferenceObject(Process);
1010 ObDereferenceObject(pParentProcess);
1011 return(Status);
1012 }
1013
1014 /*
1015 *
1016 */
1017 DPRINT("Creating PEB\n");
1018 Status = PsCreatePeb(*ProcessHandle,
1019 Process,
1020 ImageBase);
1021 if (!NT_SUCCESS(Status))
1022 {
1023 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
1024 ObDereferenceObject(Process);
1025 ObDereferenceObject(pParentProcess);
1026 ZwClose(*ProcessHandle);
1027 *ProcessHandle = NULL;
1028 return(Status);
1029 }
1030
1031 /*
1032 * Maybe send a message to the creator process's debugger
1033 */
1034 #if 0
1035 if (pParentProcess->DebugPort != NULL)
1036 {
1037 LPC_DBG_MESSAGE Message;
1038 HANDLE FileHandle;
1039
1040 ObCreateHandle(NULL, // Debugger Process
1041 NULL, // SectionHandle
1042 FILE_ALL_ACCESS,
1043 FALSE,
1044 &FileHandle);
1045
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; //
1053
1054 Status = LpcSendDebugMessagePort(pParentProcess->DebugPort,
1055 &Message);
1056 }
1057 #endif
1058
1059 PspRunCreateProcessNotifyRoutines(Process, TRUE);
1060
1061 ObDereferenceObject(Process);
1062 ObDereferenceObject(pParentProcess);
1063 return(STATUS_SUCCESS);
1064 }
1065
1066
1067 /*
1068 * @unimplemented
1069 */
1070 NTSTATUS STDCALL
1071 NtOpenProcess(OUT PHANDLE ProcessHandle,
1072 IN ACCESS_MASK DesiredAccess,
1073 IN POBJECT_ATTRIBUTES ObjectAttributes,
1074 IN PCLIENT_ID ClientId)
1075 {
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);
1080
1081
1082 /*
1083 * Not sure of the exact semantics
1084 */
1085 if (ObjectAttributes != NULL && ObjectAttributes->ObjectName != NULL &&
1086 ObjectAttributes->ObjectName->Buffer != NULL)
1087 {
1088 NTSTATUS Status;
1089 PEPROCESS Process;
1090
1091 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
1092 ObjectAttributes->Attributes,
1093 NULL,
1094 DesiredAccess,
1095 PsProcessType,
1096 UserMode,
1097 NULL,
1098 (PVOID*)&Process);
1099 if (Status != STATUS_SUCCESS)
1100 {
1101 return(Status);
1102 }
1103
1104 Status = ObCreateHandle(PsGetCurrentProcess(),
1105 Process,
1106 DesiredAccess,
1107 FALSE,
1108 ProcessHandle);
1109 ObDereferenceObject(Process);
1110
1111 return(Status);
1112 }
1113 else
1114 {
1115 KIRQL oldIrql;
1116 PLIST_ENTRY current_entry;
1117 PEPROCESS current;
1118 NTSTATUS Status;
1119
1120 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1121 current_entry = PsProcessListHead.Flink;
1122 while (current_entry != &PsProcessListHead)
1123 {
1124 current = CONTAINING_RECORD(current_entry, EPROCESS,
1125 ProcessListEntry);
1126 if (current->UniqueProcessId == (ULONG)ClientId->UniqueProcess)
1127 {
1128 if (current->Pcb.State == PROCESS_STATE_TERMINATED)
1129 {
1130 Status = STATUS_PROCESS_IS_TERMINATING;
1131 }
1132 else
1133 {
1134 Status = ObReferenceObjectByPointer(current,
1135 DesiredAccess,
1136 PsProcessType,
1137 UserMode);
1138 }
1139 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1140 if (NT_SUCCESS(Status))
1141 {
1142 Status = ObCreateHandle(PsGetCurrentProcess(),
1143 current,
1144 DesiredAccess,
1145 FALSE,
1146 ProcessHandle);
1147 ObDereferenceObject(current);
1148 DPRINT("*ProcessHandle %x\n", ProcessHandle);
1149 DPRINT("NtOpenProcess() = %x\n", Status);
1150 }
1151 return(Status);
1152 }
1153 current_entry = current_entry->Flink;
1154 }
1155 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1156 DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
1157 return(STATUS_UNSUCCESSFUL);
1158 }
1159 return(STATUS_UNSUCCESSFUL);
1160 }
1161
1162
1163 /*
1164 * @unimplemented
1165 */
1166 NTSTATUS STDCALL
1167 NtQueryInformationProcess(IN HANDLE ProcessHandle,
1168 IN PROCESSINFOCLASS ProcessInformationClass,
1169 OUT PVOID ProcessInformation,
1170 IN ULONG ProcessInformationLength,
1171 OUT PULONG ReturnLength OPTIONAL)
1172 {
1173 PEPROCESS Process;
1174 KPROCESSOR_MODE PreviousMode;
1175 NTSTATUS Status = STATUS_SUCCESS;
1176
1177 PreviousMode = ExGetPreviousMode();
1178
1179 DefaultQueryInfoBufferCheck(ProcessInformationClass,
1180 PsProcessInfoClass,
1181 ProcessInformation,
1182 ProcessInformationLength,
1183 ReturnLength,
1184 PreviousMode,
1185 &Status);
1186 if(!NT_SUCCESS(Status))
1187 {
1188 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
1189 return Status;
1190 }
1191
1192 /*
1193 * TODO: Here we should probably check that ProcessInformationLength
1194 * bytes indeed are writable at address ProcessInformation.
1195 */
1196
1197 Status = ObReferenceObjectByHandle(ProcessHandle,
1198 PROCESS_QUERY_INFORMATION,
1199 PsProcessType,
1200 PreviousMode,
1201 (PVOID*)&Process,
1202 NULL);
1203 if (!NT_SUCCESS(Status))
1204 {
1205 return(Status);
1206 }
1207
1208 switch (ProcessInformationClass)
1209 {
1210 case ProcessBasicInformation:
1211 {
1212 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
1213 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
1214
1215 _SEH_TRY
1216 {
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;
1226
1227 if (ReturnLength)
1228 {
1229 *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
1230 }
1231 }
1232 _SEH_HANDLE
1233 {
1234 Status = _SEH_GetExceptionCode();
1235 }
1236 _SEH_END;
1237 break;
1238 }
1239
1240 case ProcessQuotaLimits:
1241 case ProcessIoCounters:
1242 Status = STATUS_NOT_IMPLEMENTED;
1243 break;
1244
1245 case ProcessTimes:
1246 {
1247 PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
1248 _SEH_TRY
1249 {
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;
1254
1255 if (ReturnLength)
1256 {
1257 *ReturnLength = sizeof(KERNEL_USER_TIMES);
1258 }
1259 }
1260 _SEH_HANDLE
1261 {
1262 Status = _SEH_GetExceptionCode();
1263 }
1264 _SEH_END;
1265 break;
1266 }
1267
1268 case ProcessDebugPort:
1269 {
1270 _SEH_TRY
1271 {
1272 *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
1273 if (ReturnLength)
1274 {
1275 *ReturnLength = sizeof(HANDLE);
1276 }
1277 }
1278 _SEH_HANDLE
1279 {
1280 Status = _SEH_GetExceptionCode();
1281 }
1282 _SEH_END;
1283 break;
1284 }
1285
1286 case ProcessLdtInformation:
1287 case ProcessWorkingSetWatch:
1288 case ProcessWx86Information:
1289 Status = STATUS_NOT_IMPLEMENTED;
1290 break;
1291
1292 case ProcessHandleCount:
1293 {
1294 ULONG HandleCount = ObpGetHandleCountByHandleTable(&Process->HandleTable);
1295
1296 _SEH_TRY
1297 {
1298 *(PULONG)ProcessInformation = HandleCount;
1299 if (ReturnLength)
1300 {
1301 *ReturnLength = sizeof(ULONG);
1302 }
1303 }
1304 _SEH_HANDLE
1305 {
1306 Status = _SEH_GetExceptionCode();
1307 }
1308 _SEH_END;
1309 break;
1310 }
1311
1312 case ProcessSessionInformation:
1313 {
1314 PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
1315
1316 _SEH_TRY
1317 {
1318 SessionInfo->SessionId = Process->SessionId;
1319 if (ReturnLength)
1320 {
1321 *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
1322 }
1323 }
1324 _SEH_HANDLE
1325 {
1326 Status = _SEH_GetExceptionCode();
1327 }
1328 _SEH_END;
1329 break;
1330 }
1331
1332 case ProcessWow64Information:
1333 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
1334 Status = STATUS_NOT_IMPLEMENTED;
1335 break;
1336
1337 case ProcessVmCounters:
1338 {
1339 PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
1340
1341 _SEH_TRY
1342 {
1343 pOut->PeakVirtualSize = Process->PeakVirtualSize;
1344 /*
1345 * Here we should probably use VirtualSize.LowPart, but due to
1346 * incompatibilities in current headers (no unnamed union),
1347 * I opted for cast.
1348 */
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;
1359
1360 if (ReturnLength)
1361 {
1362 *ReturnLength = sizeof(VM_COUNTERS);
1363 }
1364 }
1365 _SEH_HANDLE
1366 {
1367 Status = _SEH_GetExceptionCode();
1368 }
1369 _SEH_END;
1370 break;
1371 }
1372
1373 case ProcessDefaultHardErrorMode:
1374 {
1375 PULONG HardErrMode = (PULONG)ProcessInformation;
1376 _SEH_TRY
1377 {
1378 *HardErrMode = Process->DefaultHardErrorProcessing;
1379 if (ReturnLength)
1380 {
1381 *ReturnLength = sizeof(ULONG);
1382 }
1383 }
1384 _SEH_HANDLE
1385 {
1386 Status = _SEH_GetExceptionCode();
1387 }
1388 _SEH_END;
1389 break;
1390 }
1391
1392 case ProcessPriorityBoost:
1393 {
1394 PULONG BoostEnabled = (PULONG)ProcessInformation;
1395
1396 _SEH_TRY
1397 {
1398 *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
1399
1400 if (ReturnLength)
1401 {
1402 *ReturnLength = sizeof(ULONG);
1403 }
1404 }
1405 _SEH_HANDLE
1406 {
1407 Status = _SEH_GetExceptionCode();
1408 }
1409 _SEH_END;
1410 break;
1411 }
1412
1413 case ProcessDeviceMap:
1414 {
1415 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
1416
1417 ObQueryDeviceMapInformation(Process, &DeviceMap);
1418
1419 _SEH_TRY
1420 {
1421 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
1422 if (ReturnLength)
1423 {
1424 *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
1425 }
1426 }
1427 _SEH_HANDLE
1428 {
1429 Status = _SEH_GetExceptionCode();
1430 }
1431 _SEH_END;
1432 break;
1433 }
1434
1435 case ProcessPriorityClass:
1436 {
1437 PUSHORT Priority = (PUSHORT)ProcessInformation;
1438
1439 _SEH_TRY
1440 {
1441 *Priority = Process->PriorityClass;
1442
1443 if (ReturnLength)
1444 {
1445 *ReturnLength = sizeof(USHORT);
1446 }
1447 }
1448 _SEH_HANDLE
1449 {
1450 Status = _SEH_GetExceptionCode();
1451 }
1452 _SEH_END;
1453 break;
1454 }
1455
1456 case ProcessImageFileName:
1457 {
1458 /*
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
1461 * process!
1462 */
1463 if(Process->Peb != NULL)
1464 {
1465 PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL;
1466 UNICODE_STRING LocalDest;
1467 ULONG ImagePathLen = 0;
1468 PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
1469
1470 /* we need to attach to the process to make sure we're in the right context! */
1471 KeAttachProcess(&Process->Pcb);
1472
1473 _SEH_TRY
1474 {
1475 ProcParams = Process->Peb->ProcessParameters;
1476 ImagePathLen = ProcParams->ImagePathName.Length;
1477 }
1478 _SEH_HANDLE
1479 {
1480 Status = _SEH_GetExceptionCode();
1481 }
1482 _SEH_END;
1483
1484 if(NT_SUCCESS(Status))
1485 {
1486 if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
1487 {
1488 Status = STATUS_INFO_LENGTH_MISMATCH;
1489 }
1490 else
1491 {
1492 PWSTR StrSource = NULL;
1493
1494 /* create a DstPath structure on the stack */
1495 _SEH_TRY
1496 {
1497 LocalDest.Length = ImagePathLen;
1498 LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR);
1499 LocalDest.Buffer = (PWSTR)(DstPath + 1);
1500
1501 /* save a copy of the pointer to the source buffer */
1502 StrSource = ProcParams->ImagePathName.Buffer;
1503 }
1504 _SEH_HANDLE
1505 {
1506 Status = _SEH_GetExceptionCode();
1507 }
1508 _SEH_END;
1509
1510 if(NT_SUCCESS(Status))
1511 {
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)
1517 {
1518 /* make a copy of the buffer to the temporary buffer */
1519 _SEH_TRY
1520 {
1521 RtlCopyMemory(PathCopy, StrSource, LocalDest.Length);
1522 PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0';
1523 }
1524 _SEH_HANDLE
1525 {
1526 Status = _SEH_GetExceptionCode();
1527 }
1528 _SEH_END;
1529
1530 /* detach from the process */
1531 KeDetachProcess();
1532
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))
1536 {
1537 /* now let's copy the buffer back to the caller */
1538 _SEH_TRY
1539 {
1540 *DstPath = LocalDest;
1541 RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR));
1542 if (ReturnLength)
1543 {
1544 *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR);
1545 }
1546 }
1547 _SEH_HANDLE
1548 {
1549 Status = _SEH_GetExceptionCode();
1550 }
1551 _SEH_END;
1552 }
1553
1554 /* we're done with the copy operation, free the temporary kernel buffer */
1555 ExFreePool(PathCopy);
1556
1557 /* we need to bail because we're already detached from the process */
1558 break;
1559 }
1560 else
1561 {
1562 Status = STATUS_INSUFFICIENT_RESOURCES;
1563 }
1564 }
1565 }
1566 }
1567
1568 /* don't forget to detach from the process!!! */
1569 KeDetachProcess();
1570 }
1571 else
1572 {
1573 /* FIXME - what to do here? */
1574 Status = STATUS_UNSUCCESSFUL;
1575 }
1576 break;
1577 }
1578
1579 /*
1580 * Note: The following 10 information classes are verified to not be
1581 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
1582 */
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:
1593 default:
1594 Status = STATUS_INVALID_INFO_CLASS;
1595 }
1596
1597 ObDereferenceObject(Process);
1598 return Status;
1599 }
1600
1601
1602 NTSTATUS
1603 PspAssignPrimaryToken(PEPROCESS Process,
1604 HANDLE TokenHandle)
1605 {
1606 PACCESS_TOKEN Token;
1607 PACCESS_TOKEN OldToken;
1608 NTSTATUS Status;
1609
1610 Status = ObReferenceObjectByHandle(TokenHandle,
1611 0,
1612 SepTokenObjectType,
1613 UserMode,
1614 (PVOID*)&Token,
1615 NULL);
1616 if (!NT_SUCCESS(Status))
1617 {
1618 return(Status);
1619 }
1620 Status = SeExchangePrimaryToken(Process, Token, &OldToken);
1621 if (NT_SUCCESS(Status))
1622 {
1623 ObDereferenceObject(OldToken);
1624 }
1625 ObDereferenceObject(Token);
1626 return(Status);
1627 }
1628
1629 /*
1630 * @unimplemented
1631 */
1632 NTSTATUS STDCALL
1633 NtSetInformationProcess(IN HANDLE ProcessHandle,
1634 IN PROCESSINFOCLASS ProcessInformationClass,
1635 IN PVOID ProcessInformation,
1636 IN ULONG ProcessInformationLength)
1637 {
1638 PEPROCESS Process;
1639 KPROCESSOR_MODE PreviousMode;
1640 ACCESS_MASK Access;
1641 NTSTATUS Status = STATUS_SUCCESS;
1642
1643 PreviousMode = ExGetPreviousMode();
1644
1645 DefaultSetInfoBufferCheck(ProcessInformationClass,
1646 PsProcessInfoClass,
1647 ProcessInformation,
1648 ProcessInformationLength,
1649 PreviousMode,
1650 &Status);
1651 if(!NT_SUCCESS(Status))
1652 {
1653 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
1654 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
1655 return Status;
1656 }
1657
1658 switch(ProcessInformationClass)
1659 {
1660 case ProcessSessionInformation:
1661 Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
1662 break;
1663 case ProcessExceptionPort:
1664 case ProcessDebugPort:
1665 Access = PROCESS_SET_INFORMATION | PROCESS_SET_PORT;
1666 break;
1667
1668 default:
1669 Access = PROCESS_SET_INFORMATION;
1670 break;
1671 }
1672
1673 Status = ObReferenceObjectByHandle(ProcessHandle,
1674 Access,
1675 PsProcessType,
1676 PreviousMode,
1677 (PVOID*)&Process,
1678 NULL);
1679 if (!NT_SUCCESS(Status))
1680 {
1681 return(Status);
1682 }
1683
1684 switch (ProcessInformationClass)
1685 {
1686 case ProcessQuotaLimits:
1687 case ProcessBasePriority:
1688 case ProcessRaisePriority:
1689 Status = STATUS_NOT_IMPLEMENTED;
1690 break;
1691
1692 case ProcessDebugPort:
1693 {
1694 if(ProcessInformationLength != sizeof(HANDLE))
1695 {
1696 Status = STATUS_INFO_LENGTH_MISMATCH;
1697 }
1698 else
1699 {
1700 HANDLE PortHandle = NULL;
1701
1702 /* make a safe copy of the buffer on the stack */
1703 _SEH_TRY
1704 {
1705 PortHandle = *(PHANDLE)ProcessInformation;
1706 Status = (PortHandle != NULL ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER);
1707 }
1708 _SEH_HANDLE
1709 {
1710 Status = _SEH_GetExceptionCode();
1711 }
1712 _SEH_END;
1713
1714 if(NT_SUCCESS(Status))
1715 {
1716 PEPORT DebugPort;
1717
1718 /* in case we had success reading from the buffer, verify the provided
1719 * LPC port handle
1720 */
1721 Status = ObReferenceObjectByHandle(PortHandle,
1722 0,
1723 LpcPortObjectType,
1724 PreviousMode,
1725 (PVOID)&DebugPort,
1726 NULL);
1727 if(NT_SUCCESS(Status))
1728 {
1729 /* lock the process to be thread-safe! */
1730
1731 Status = PsLockProcess(Process, FALSE);
1732 if(NT_SUCCESS(Status))
1733 {
1734 /*
1735 * according to "NT Native API" documentation, setting the debug
1736 * port is only permitted once!
1737 */
1738 if(Process->DebugPort == NULL)
1739 {
1740 /* keep the reference to the handle! */
1741 Process->DebugPort = DebugPort;
1742
1743 if(Process->Peb)
1744 {
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! */
1748
1749 KeAttachProcess(&Process->Pcb);
1750 _SEH_TRY
1751 {
1752 Process->Peb->BeingDebugged = TRUE;
1753 }
1754 _SEH_HANDLE
1755 {
1756 DPRINT1("Trying to set the Peb->BeingDebugged field of process 0x%x failed, exception: 0x%x\n", Process, _SEH_GetExceptionCode());
1757 }
1758 _SEH_END;
1759 KeDetachProcess();
1760 }
1761 Status = STATUS_SUCCESS;
1762 }
1763 else
1764 {
1765 ObDereferenceObject(DebugPort);
1766 Status = STATUS_PORT_ALREADY_SET;
1767 }
1768 PsUnlockProcess(Process);
1769 }
1770 else
1771 {
1772 ObDereferenceObject(DebugPort);
1773 }
1774 }
1775 }
1776 }
1777 break;
1778 }
1779
1780 case ProcessExceptionPort:
1781 {
1782 if(ProcessInformationLength != sizeof(HANDLE))
1783 {
1784 Status = STATUS_INFO_LENGTH_MISMATCH;
1785 }
1786 else
1787 {
1788 HANDLE PortHandle = NULL;
1789
1790 /* make a safe copy of the buffer on the stack */
1791 _SEH_TRY
1792 {
1793 PortHandle = *(PHANDLE)ProcessInformation;
1794 Status = STATUS_SUCCESS;
1795 }
1796 _SEH_HANDLE
1797 {
1798 Status = _SEH_GetExceptionCode();
1799 }
1800 _SEH_END;
1801
1802 if(NT_SUCCESS(Status))
1803 {
1804 PEPORT ExceptionPort;
1805
1806 /* in case we had success reading from the buffer, verify the provided
1807 * LPC port handle
1808 */
1809 Status = ObReferenceObjectByHandle(PortHandle,
1810 0,
1811 LpcPortObjectType,
1812 PreviousMode,
1813 (PVOID)&ExceptionPort,
1814 NULL);
1815 if(NT_SUCCESS(Status))
1816 {
1817 /* lock the process to be thread-safe! */
1818
1819 Status = PsLockProcess(Process, FALSE);
1820 if(NT_SUCCESS(Status))
1821 {
1822 /*
1823 * according to "NT Native API" documentation, setting the exception
1824 * port is only permitted once!
1825 */
1826 if(Process->ExceptionPort == NULL)
1827 {
1828 /* keep the reference to the handle! */
1829 Process->ExceptionPort = ExceptionPort;
1830 Status = STATUS_SUCCESS;
1831 }
1832 else
1833 {
1834 ObDereferenceObject(ExceptionPort);
1835 Status = STATUS_PORT_ALREADY_SET;
1836 }
1837 PsUnlockProcess(Process);
1838 }
1839 else
1840 {
1841 ObDereferenceObject(ExceptionPort);
1842 }
1843 }
1844 }
1845 }
1846 break;
1847 }
1848
1849 case ProcessAccessToken:
1850 {
1851 if(ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
1852 {
1853 Status = STATUS_INFO_LENGTH_MISMATCH;
1854 }
1855 else
1856 {
1857 HANDLE TokenHandle = NULL;
1858
1859 /* make a safe copy of the buffer on the stack */
1860 _SEH_TRY
1861 {
1862 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
1863 Status = STATUS_SUCCESS;
1864 }
1865 _SEH_HANDLE
1866 {
1867 Status = _SEH_GetExceptionCode();
1868 }
1869 _SEH_END;
1870
1871 if(NT_SUCCESS(Status))
1872 {
1873 /* in case we had success reading from the buffer, perform the actual task */
1874 Status = PspAssignPrimaryToken(Process, TokenHandle);
1875 }
1876 }
1877 break;
1878 }
1879
1880 case ProcessDefaultHardErrorMode:
1881 {
1882 if(ProcessInformationLength != sizeof(UINT))
1883 {
1884 Status = STATUS_INFO_LENGTH_MISMATCH;
1885 }
1886 else
1887 {
1888 _SEH_TRY
1889 {
1890 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
1891 *(PLONG)ProcessInformation);
1892 Status = STATUS_SUCCESS;
1893 }
1894 _SEH_HANDLE
1895 {
1896 Status = _SEH_GetExceptionCode();
1897 }
1898 _SEH_END;
1899 }
1900 break;
1901 }
1902
1903 case ProcessSessionInformation:
1904 {
1905 if(ProcessInformationLength != sizeof(UINT))
1906 {
1907 Status = STATUS_INFO_LENGTH_MISMATCH;
1908 }
1909 else
1910 {
1911 PROCESS_SESSION_INFORMATION SessionInfo;
1912 Status = STATUS_SUCCESS;
1913
1914 _SEH_TRY
1915 {
1916 /* copy the structure to the stack */
1917 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1918 }
1919 _SEH_HANDLE
1920 {
1921 Status = _SEH_GetExceptionCode();
1922 }
1923 _SEH_END;
1924
1925 if(NT_SUCCESS(Status))
1926 {
1927 /* we successfully copied the structure to the stack, continue processing */
1928
1929 /*
1930 * setting the session id requires the SeTcbPrivilege!
1931 */
1932 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
1933 PreviousMode))
1934 {
1935 /* can't set the session id, bail! */
1936 Status = STATUS_PRIVILEGE_NOT_HELD;
1937 break;
1938 }
1939
1940 /* FIXME - update the session id for the process token */
1941
1942 Status = PsLockProcess(Process, FALSE);
1943 if(NT_SUCCESS(Status))
1944 {
1945 Process->SessionId = SessionInfo.SessionId;
1946
1947 /* Update the session id in the PEB structure */
1948 if(Process->Peb != NULL)
1949 {
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);
1953
1954 _SEH_TRY
1955 {
1956 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
1957
1958 Status = STATUS_SUCCESS;
1959 }
1960 _SEH_HANDLE
1961 {
1962 Status = _SEH_GetExceptionCode();
1963 }
1964 _SEH_END;
1965
1966 KeDetachProcess();
1967 }
1968
1969 PsUnlockProcess(Process);
1970 }
1971 }
1972 }
1973 break;
1974 }
1975
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;
1985 break;
1986
1987 case ProcessBasicInformation:
1988 case ProcessIoCounters:
1989 case ProcessTimes:
1990 case ProcessPooledUsageAndLimits:
1991 case ProcessWx86Information:
1992 case ProcessHandleCount:
1993 case ProcessWow64Information:
1994 default:
1995 Status = STATUS_INVALID_INFO_CLASS;
1996 }
1997 ObDereferenceObject(Process);
1998 return(Status);
1999 }
2000
2001
2002 /**********************************************************************
2003 * NAME INTERNAL
2004 * PiQuerySystemProcessInformation
2005 *
2006 * DESCRIPTION
2007 * Compute the size of a process+thread snapshot as
2008 * expected by NtQuerySystemInformation.
2009 *
2010 * RETURN VALUE
2011 * 0 on error; otherwise the size, in bytes of the buffer
2012 * required to write a full snapshot.
2013 *
2014 * NOTE
2015 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
2016 */
2017 NTSTATUS
2018 PiQuerySystemProcessInformation(PVOID Buffer,
2019 ULONG Size,
2020 PULONG ReqSize)
2021 {
2022 return STATUS_NOT_IMPLEMENTED;
2023
2024 #if 0
2025 KIRQL OldIrql;
2026 PLIST_ENTRY CurrentEntryP;
2027 PEPROCESS CurrentP;
2028 PLIST_ENTRY CurrentEntryT;
2029 PETHREAD CurrentT;
2030
2031 ULONG RequiredSize = 0L;
2032 BOOLEAN SizeOnly = FALSE;
2033
2034 ULONG SpiSize = 0L;
2035
2036 PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
2037 PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
2038 PSYSTEM_THREAD_INFO pInfoT = NULL;
2039
2040
2041 /* Lock the process list. */
2042 KeAcquireSpinLock(&PsProcessListLock,
2043 &OldIrql);
2044
2045 /*
2046 * Scan the process list. Since the
2047 * list is circular, the guard is false
2048 * after the last process.
2049 */
2050 for ( CurrentEntryP = PsProcessListHead.Flink;
2051 (CurrentEntryP != & PsProcessListHead);
2052 CurrentEntryP = CurrentEntryP->Flink
2053 )
2054 {
2055 /*
2056 * Compute how much space is
2057 * occupied in the snapshot
2058 * by adding this process info.
2059 * (at least one thread).
2060 */
2061 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
2062 RequiredSize += SpiSizeCurrent;
2063 /*
2064 * Do not write process data in the
2065 * buffer if it is too small.
2066 */
2067 if (TRUE == SizeOnly) continue;
2068 /*
2069 * Check if the buffer can contain
2070 * the full snapshot.
2071 */
2072 if (Size < RequiredSize)
2073 {
2074 SizeOnly = TRUE;
2075 continue;
2076 }
2077 /*
2078 * Get a reference to the
2079 * process descriptor we are
2080 * handling.
2081 */
2082 CurrentP = CONTAINING_RECORD(
2083 CurrentEntryP,
2084 EPROCESS,
2085 ProcessListEntry
2086 );
2087 /*
2088 * Write process data in the buffer.
2089 */
2090 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
2091 /* PROCESS */
2092 pInfoP->ThreadCount = 0L;
2093 pInfoP->ProcessId = CurrentP->UniqueProcessId;
2094 RtlInitUnicodeString (
2095 & pInfoP->Name,
2096 CurrentP->ImageFileName
2097 );
2098 /* THREAD */
2099 for ( pInfoT = & CurrentP->ThreadSysInfo [0],
2100 CurrentEntryT = CurrentP->ThreadListHead.Flink;
2101
2102 (CurrentEntryT != & CurrentP->ThreadListHead);
2103
2104 pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
2105 CurrentEntryT = CurrentEntryT->Flink
2106 )
2107 {
2108 /*
2109 * Recalculate the size of the
2110 * information block.
2111 */
2112 if (0 < pInfoP->ThreadCount)
2113 {
2114 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
2115 }
2116 /*
2117 * Do not write thread data in the
2118 * buffer if it is too small.
2119 */
2120 if (TRUE == SizeOnly) continue;
2121 /*
2122 * Check if the buffer can contain
2123 * the full snapshot.
2124 */
2125 if (Size < RequiredSize)
2126 {
2127 SizeOnly = TRUE;
2128 continue;
2129 }
2130 /*
2131 * Get a reference to the
2132 * thread descriptor we are
2133 * handling.
2134 */
2135 CurrentT = CONTAINING_RECORD(
2136 CurrentEntryT,
2137 KTHREAD,
2138 ThreadListEntry
2139 );
2140 /*
2141 * Write thread data.
2142 */
2143 RtlZeroMemory (
2144 pInfoT,
2145 sizeof (SYSTEM_THREAD_INFORMATION)
2146 );
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 */
2159 /*
2160 * Count the number of threads
2161 * this process has.
2162 */
2163 ++ pInfoP->ThreadCount;
2164 }
2165 /*
2166 * Save the size of information
2167 * stored in the buffer for the
2168 * current process.
2169 */
2170 pInfoP->RelativeOffset = SpiSize;
2171 /*
2172 * Save a reference to the last
2173 * valid information block.
2174 */
2175 pInfoPLast = pInfoP;
2176 /*
2177 * Compute the offset of the
2178 * SYSTEM_PROCESS_INFORMATION
2179 * descriptor in the snapshot
2180 * buffer for the next process.
2181 */
2182 (ULONG) pInfoP += SpiSize;
2183 }
2184 /*
2185 * Unlock the process list.
2186 */
2187 KeReleaseSpinLock (
2188 & PsProcessListLock,
2189 OldIrql
2190 );
2191 /*
2192 * Return the proper error status code,
2193 * if the buffer was too small.
2194 */
2195 if (TRUE == SizeOnly)
2196 {
2197 if (NULL != RequiredSize)
2198 {
2199 *pRequiredSize = RequiredSize;
2200 }
2201 return STATUS_INFO_LENGTH_MISMATCH;
2202 }
2203 /*
2204 * Mark the end of the snapshot.
2205 */
2206 pInfoP->RelativeOffset = 0L;
2207 /* OK */
2208 return STATUS_SUCCESS;
2209 #endif
2210 }
2211
2212 /*
2213 * @implemented
2214 */
2215 LARGE_INTEGER STDCALL
2216 PsGetProcessExitTime(VOID)
2217 {
2218 LARGE_INTEGER Li;
2219 Li.QuadPart = PsGetCurrentProcess()->ExitTime.QuadPart;
2220 return Li;
2221 }
2222
2223 /*
2224 * @implemented
2225 */
2226 LONGLONG
2227 STDCALL
2228 PsGetProcessCreateTimeQuadPart(
2229 PEPROCESS Process
2230 )
2231 {
2232 return Process->CreateTime.QuadPart;
2233 }
2234
2235 /*
2236 * @implemented
2237 */
2238 PVOID
2239 STDCALL
2240 PsGetProcessDebugPort(
2241 PEPROCESS Process
2242 )
2243 {
2244 return Process->DebugPort;
2245 }
2246
2247 /*
2248 * @implemented
2249 */
2250 BOOLEAN
2251 STDCALL
2252 PsGetProcessExitProcessCalled(
2253 PEPROCESS Process
2254 )
2255 {
2256 return Process->ExitProcessCalled;
2257 }
2258
2259 /*
2260 * @implemented
2261 */
2262 NTSTATUS
2263 STDCALL
2264 PsGetProcessExitStatus(
2265 PEPROCESS Process
2266 )
2267 {
2268 return Process->ExitStatus;
2269 }
2270
2271 /*
2272 * @implemented
2273 */
2274 HANDLE
2275 STDCALL
2276 PsGetProcessId(
2277 PEPROCESS Process
2278 )
2279 {
2280 return (HANDLE)Process->UniqueProcessId;
2281 }
2282
2283 /*
2284 * @implemented
2285 */
2286 LPSTR
2287 STDCALL
2288 PsGetProcessImageFileName(
2289 PEPROCESS Process
2290 )
2291 {
2292 return (LPSTR)Process->ImageFileName;
2293 }
2294
2295 /*
2296 * @implemented
2297 */
2298 HANDLE
2299 STDCALL
2300 PsGetProcessInheritedFromUniqueProcessId(
2301 PEPROCESS Process
2302 )
2303 {
2304 return Process->InheritedFromUniqueProcessId;
2305 }
2306
2307 /*
2308 * @implemented
2309 */
2310 PEJOB
2311 STDCALL
2312 PsGetProcessJob(
2313 PEPROCESS Process
2314 )
2315 {
2316 return Process->Job;
2317 }
2318
2319 /*
2320 * @implemented
2321 */
2322 PPEB
2323 STDCALL
2324 PsGetProcessPeb(
2325 PEPROCESS Process
2326 )
2327 {
2328 return Process->Peb;
2329 }
2330
2331 /*
2332 * @implemented
2333 */
2334 ULONG
2335 STDCALL
2336 PsGetProcessPriorityClass(
2337 PEPROCESS Process
2338 )
2339 {
2340 return Process->PriorityClass;
2341 }
2342
2343 /*
2344 * @implemented
2345 */
2346 PVOID
2347 STDCALL
2348 PsGetProcessSectionBaseAddress(
2349 PEPROCESS Process
2350 )
2351 {
2352 return Process->SectionBaseAddress;
2353 }
2354
2355 /*
2356 * @implemented
2357 */
2358 PVOID
2359 STDCALL
2360 PsGetProcessSecurityPort(
2361 PEPROCESS Process
2362 )
2363 {
2364 return Process->SecurityPort;
2365 }
2366
2367 /*
2368 * @implemented
2369 */
2370 HANDLE
2371 STDCALL
2372 PsGetProcessSessionId(
2373 PEPROCESS Process
2374 )
2375 {
2376 return (HANDLE)Process->SessionId;
2377 }
2378
2379 /*
2380 * @implemented
2381 */
2382 PVOID
2383 STDCALL
2384 PsGetProcessWin32Process(
2385 PEPROCESS Process
2386 )
2387 {
2388 return Process->Win32Process;
2389 }
2390
2391 /*
2392 * @implemented
2393 */
2394 PVOID
2395 STDCALL
2396 PsGetProcessWin32WindowStation(
2397 PEPROCESS Process
2398 )
2399 {
2400 return Process->Win32WindowStation;
2401 }
2402
2403 /*
2404 * @implemented
2405 */
2406 BOOLEAN
2407 STDCALL
2408 PsIsProcessBeingDebugged(
2409 PEPROCESS Process
2410 )
2411 {
2412 return FALSE/*Process->IsProcessBeingDebugged*/;
2413 }
2414
2415
2416 /*
2417 * @implemented
2418 */
2419 NTSTATUS STDCALL
2420 PsLookupProcessByProcessId(IN PVOID ProcessId,
2421 OUT PEPROCESS *Process)
2422 {
2423 KIRQL oldIrql;
2424 PLIST_ENTRY current_entry;
2425 PEPROCESS current;
2426
2427 KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
2428
2429 current_entry = PsProcessListHead.Flink;
2430 while (current_entry != &PsProcessListHead)
2431 {
2432 current = CONTAINING_RECORD(current_entry,
2433 EPROCESS,
2434 ProcessListEntry);
2435 if (current->UniqueProcessId == (ULONG)ProcessId)
2436 {
2437 *Process = current;
2438 ObReferenceObject(current);
2439 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
2440 return(STATUS_SUCCESS);
2441 }
2442 current_entry = current_entry->Flink;
2443 }
2444
2445 KeReleaseSpinLock(&PsProcessListLock, oldIrql);
2446
2447 return(STATUS_INVALID_PARAMETER);
2448 }
2449
2450 VOID
2451 STDCALL
2452 PspRunCreateProcessNotifyRoutines
2453 (
2454 PEPROCESS CurrentProcess,
2455 BOOLEAN Create
2456 )
2457 {
2458 ULONG i;
2459 HANDLE ProcessId = (HANDLE)CurrentProcess->UniqueProcessId;
2460 HANDLE ParentId = CurrentProcess->InheritedFromUniqueProcessId;
2461
2462 for(i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++ i)
2463 if(PiProcessNotifyRoutine[i])
2464 PiProcessNotifyRoutine[i](ParentId, ProcessId, Create);
2465 }
2466
2467 /*
2468 * @implemented
2469 */
2470 NTSTATUS STDCALL
2471 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
2472 IN BOOLEAN Remove)
2473 {
2474 ULONG i;
2475
2476 if (Remove)
2477 {
2478 for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
2479 {
2480 if ((PVOID)PiProcessNotifyRoutine[i] == (PVOID)NotifyRoutine)
2481 {
2482 PiProcessNotifyRoutine[i] = NULL;
2483 break;
2484 }
2485 }
2486
2487 return(STATUS_SUCCESS);
2488 }
2489
2490 /*insert*/
2491 for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
2492 {
2493 if (PiProcessNotifyRoutine[i] == NULL)
2494 {
2495 PiProcessNotifyRoutine[i] = NotifyRoutine;
2496 break;
2497 }
2498 }
2499
2500 if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
2501 {
2502 return STATUS_INSUFFICIENT_RESOURCES;
2503 }
2504
2505 return STATUS_SUCCESS;
2506 }
2507
2508 VOID STDCALL
2509 PspRunLoadImageNotifyRoutines(
2510 PUNICODE_STRING FullImageName,
2511 HANDLE ProcessId,
2512 PIMAGE_INFO ImageInfo)
2513 {
2514 ULONG i;
2515
2516 for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++ i)
2517 if (PiLoadImageNotifyRoutine[i])
2518 PiLoadImageNotifyRoutine[i](FullImageName, ProcessId, ImageInfo);
2519 }
2520
2521 /*
2522 * @unimplemented
2523 */
2524 NTSTATUS
2525 STDCALL
2526 PsRemoveLoadImageNotifyRoutine(
2527 IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
2528 )
2529 {
2530 UNIMPLEMENTED;
2531 return STATUS_NOT_IMPLEMENTED;
2532 }
2533
2534 /*
2535 * @implemented
2536 */
2537 NTSTATUS STDCALL
2538 PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
2539 {
2540 ULONG i;
2541
2542 for (i = 0; i < MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT; i++)
2543 {
2544 if (PiLoadImageNotifyRoutine[i] == NULL)
2545 {
2546 PiLoadImageNotifyRoutine[i] = NotifyRoutine;
2547 break;
2548 }
2549 }
2550
2551 if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
2552 {
2553 return STATUS_INSUFFICIENT_RESOURCES;
2554 }
2555
2556 return STATUS_SUCCESS;
2557 }
2558
2559 /*
2560 * @implemented
2561 */
2562 VOID
2563 STDCALL
2564 PsSetProcessPriorityClass(
2565 PEPROCESS Process,
2566 ULONG PriorityClass
2567 )
2568 {
2569 Process->PriorityClass = PriorityClass;
2570 }
2571
2572 /*
2573 * @implemented
2574 */
2575 VOID
2576 STDCALL
2577 PsSetProcessSecurityPort(
2578 PEPROCESS Process,
2579 PVOID SecurityPort
2580 )
2581 {
2582 Process->SecurityPort = SecurityPort;
2583 }
2584
2585 /*
2586 * @implemented
2587 */
2588 VOID
2589 STDCALL
2590 PsSetProcessWin32Process(
2591 PEPROCESS Process,
2592 PVOID Win32Process
2593 )
2594 {
2595 Process->Win32Process = Win32Process;
2596 }
2597
2598 /*
2599 * @implemented
2600 */
2601 VOID
2602 STDCALL
2603 PsSetProcessWin32WindowStation(
2604 PEPROCESS Process,
2605 PVOID WindowStation
2606 )
2607 {
2608 Process->Win32WindowStation = WindowStation;
2609 }
2610
2611 /* Pool Quotas */
2612 /*
2613 * @implemented
2614 */
2615 VOID
2616 STDCALL
2617 PsChargePoolQuota(
2618 IN PEPROCESS Process,
2619 IN POOL_TYPE PoolType,
2620 IN ULONG_PTR Amount
2621 )
2622 {
2623 NTSTATUS Status;
2624
2625 /* Charge the usage */
2626 Status = PsChargeProcessPoolQuota(Process, PoolType, Amount);
2627
2628 /* Raise Exception */
2629 if (!NT_SUCCESS(Status)) {
2630 ExRaiseStatus(Status);
2631 }
2632 }
2633
2634 /*
2635 * @implemented
2636 */
2637 NTSTATUS
2638 STDCALL
2639 PsChargeProcessNonPagedPoolQuota (
2640 IN PEPROCESS Process,
2641 IN ULONG_PTR Amount
2642 )
2643 {
2644 /* Call the general function */
2645 return PsChargeProcessPoolQuota(Process, NonPagedPool, Amount);
2646 }
2647
2648 /*
2649 * @implemented
2650 */
2651 NTSTATUS
2652 STDCALL
2653 PsChargeProcessPagedPoolQuota (
2654 IN PEPROCESS Process,
2655 IN ULONG_PTR Amount
2656 )
2657 {
2658 /* Call the general function */
2659 return PsChargeProcessPoolQuota(Process, PagedPool, Amount);
2660 }
2661
2662 /*
2663 * @implemented
2664 */
2665 NTSTATUS
2666 STDCALL
2667 PsChargeProcessPoolQuota(
2668 IN PEPROCESS Process,
2669 IN POOL_TYPE PoolType,
2670 IN ULONG_PTR Amount
2671 )
2672 {
2673 PEPROCESS_QUOTA_BLOCK QuotaBlock;
2674 ULONG NewUsageSize;
2675 ULONG NewMaxQuota;
2676
2677 /* Get current Quota Block */
2678 QuotaBlock = Process->QuotaBlock;
2679
2680 /* Quota Operations are not to be done on the SYSTEM Process */
2681 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
2682
2683 /* New Size in use */
2684 NewUsageSize = QuotaBlock->QuotaEntry[PoolType].Usage + Amount;
2685
2686 /* Does this size respect the quota? */
2687 if (NewUsageSize > QuotaBlock->QuotaEntry[PoolType].Limit) {
2688
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;
2693
2694 /* See if the new Maximum Quota fulfills our need */
2695 if (NewUsageSize <= NewMaxQuota) goto QuotaChanged;
2696 }
2697
2698 return STATUS_QUOTA_EXCEEDED;
2699 }
2700
2701 QuotaChanged:
2702 /* Save new Usage */
2703 QuotaBlock->QuotaEntry[PoolType].Usage = NewUsageSize;
2704
2705 /* Is this a new peak? */
2706 if (NewUsageSize > QuotaBlock->QuotaEntry[PoolType].Peak) {
2707 QuotaBlock->QuotaEntry[PoolType].Peak = NewUsageSize;
2708 }
2709
2710 /* All went well */
2711 return STATUS_SUCCESS;
2712 }
2713
2714 /*
2715 * @unimplemented
2716 */
2717 VOID
2718 STDCALL
2719 PsReturnPoolQuota(
2720 IN PEPROCESS Process,
2721 IN POOL_TYPE PoolType,
2722 IN ULONG_PTR Amount
2723 )
2724 {
2725 UNIMPLEMENTED;
2726 }
2727
2728 /*
2729 * @unimplemented
2730 */
2731 VOID
2732 STDCALL
2733 PsReturnProcessNonPagedPoolQuota(
2734 IN PEPROCESS Process,
2735 IN ULONG_PTR Amount
2736 )
2737 {
2738 UNIMPLEMENTED;
2739 }
2740
2741 /*
2742 * @unimplemented
2743 */
2744 VOID
2745 STDCALL
2746 PsReturnProcessPagedPoolQuota(
2747 IN PEPROCESS Process,
2748 IN ULONG_PTR Amount
2749 )
2750 {
2751 UNIMPLEMENTED;
2752 }
2753
2754 NTSTATUS
2755 PsLockProcess(PEPROCESS Process, BOOL Timeout)
2756 {
2757 ULONG Attempts = 0;
2758 PKTHREAD PrevLockOwner;
2759 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2760 PLARGE_INTEGER Delay = (Timeout ? &PsLockTimeout : NULL);
2761 PKTHREAD CallingThread = KeGetCurrentThread();
2762
2763 KeEnterCriticalRegion();
2764
2765 for(;;)
2766 {
2767 if(Process->Pcb.State == PROCESS_STATE_TERMINATED)
2768 {
2769 KeLeaveCriticalRegion();
2770 return STATUS_PROCESS_IS_TERMINATING;
2771 }
2772
2773 PrevLockOwner = (PKTHREAD)InterlockedCompareExchangePointer(
2774 &Process->LockOwner, CallingThread, NULL);
2775 if(PrevLockOwner == NULL || PrevLockOwner == CallingThread)
2776 {
2777 /* we got the lock or already locked it */
2778 if(InterlockedIncrementUL(&Process->LockCount) == 1)
2779 {
2780 KeClearEvent(&Process->LockEvent);
2781 }
2782
2783 return STATUS_SUCCESS;
2784 }
2785 else
2786 {
2787 if(++Attempts > 2)
2788 {
2789 Status = KeWaitForSingleObject(&Process->LockEvent,
2790 Executive,
2791 KernelMode,
2792 FALSE,
2793 Delay);
2794 if(!NT_SUCCESS(Status))
2795 {
2796 #ifndef NDEBUG
2797 if(Status == STATUS_TIMEOUT)
2798 {
2799 DPRINT1("PsLockProcess(0x%x) timed out!\n", Process);
2800 }
2801 #endif
2802 KeLeaveCriticalRegion();
2803
2804 }
2805 break;
2806 }
2807 else
2808 {
2809 KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
2810 }
2811 }
2812 }
2813
2814 return Status;
2815 }
2816
2817 VOID
2818 PsUnlockProcess(PEPROCESS Process)
2819 {
2820 ASSERT(Process->LockOwner == KeGetCurrentThread());
2821
2822 if(InterlockedDecrementUL(&Process->LockCount) == 0)
2823 {
2824 InterlockedExchangePointer(&Process->LockOwner, NULL);
2825 KeSetEvent(&Process->LockEvent, IO_NO_INCREMENT, FALSE);
2826 }
2827
2828 KeLeaveCriticalRegion();
2829 }
2830
2831 /* EOF */