3e6034cb232eba0f96011b3a518109539c6a1b47
[reactos.git] / reactos / ntoskrnl / ps / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Set/Query Process/Thread Information APIs
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File
8 * David Welch
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
20 {
21 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */
22 ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */
23 ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */
24 ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */
25 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */
26 ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */
27 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */
28 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY ), /* ProcessDebugPort */
29 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */
30 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */
31 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */
32 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */
33 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */
34 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */
35 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */
36 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */
37 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */
38 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */
39 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */
40 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */
41 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */
42 ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */
43 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */
44
45 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */
46 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
47 /*Q*/ sizeof(ULONG),
48 /*S*/ sizeof(ULONG),
49 ICIF_QUERY | ICIF_SET ),
50
51 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */
52 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */
53 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */
54 ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */
55
56 /* FIXME */
57 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
58 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
59 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
60 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
61 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
62 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
63 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
64 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
65
66 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */
67 };
68
69 /*
70 * FIXME:
71 * Remove the Implemented value if all functions are implemented.
72 */
73
74 static const struct
75 {
76 BOOLEAN Implemented;
77 ULONG Size;
78 } QueryInformationData[MaxThreadInfoClass + 1] =
79 {
80 {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation
81 {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes
82 {TRUE, 0}, // ThreadPriority
83 {TRUE, 0}, // ThreadBasePriority
84 {TRUE, 0}, // ThreadAffinityMask
85 {TRUE, 0}, // ThreadImpersonationToken
86 {FALSE, 0}, // ThreadDescriptorTableEntry
87 {TRUE, 0}, // ThreadEnableAlignmentFaultFixup
88 {TRUE, 0}, // ThreadEventPair
89 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
90 {TRUE, 0}, // ThreadZeroTlsCell
91 {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount
92 {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread
93 {TRUE, 0}, // ThreadIdealProcessor
94 {FALSE, 0}, // ThreadPriorityBoost
95 {TRUE, 0}, // ThreadSetTlsArrayAddress
96 {FALSE, 0}, // ThreadIsIoPending
97 {TRUE, 0} // ThreadHideFromDebugger
98 };
99
100 static const struct
101 {
102 BOOLEAN Implemented;
103 ULONG Size;
104 } SetInformationData[MaxThreadInfoClass + 1] =
105 {
106 {TRUE, 0}, // ThreadBasicInformation
107 {TRUE, 0}, // ThreadTimes
108 {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
109 {TRUE, sizeof(LONG)}, // ThreadBasePriority
110 {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
111 {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken
112 {TRUE, 0}, // ThreadDescriptorTableEntry
113 {FALSE, 0}, // ThreadEnableAlignmentFaultFixup
114 {FALSE, 0}, // ThreadEventPair
115 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
116 {FALSE, 0}, // ThreadZeroTlsCell
117 {TRUE, 0}, // ThreadPerformanceCount
118 {TRUE, 0}, // ThreadAmILastThread
119 {FALSE, 0}, // ThreadIdealProcessor
120 {FALSE, 0}, // ThreadPriorityBoost
121 {FALSE, 0}, // ThreadSetTlsArrayAddress
122 {TRUE, 0}, // ThreadIsIoPending
123 {FALSE, 0} // ThreadHideFromDebugger
124 };
125
126 /* FUNCTIONS *****************************************************************/
127
128 /*
129 * @unimplemented
130 */
131 NTSTATUS STDCALL
132 NtQueryInformationProcess(IN HANDLE ProcessHandle,
133 IN PROCESSINFOCLASS ProcessInformationClass,
134 OUT PVOID ProcessInformation,
135 IN ULONG ProcessInformationLength,
136 OUT PULONG ReturnLength OPTIONAL)
137 {
138 PEPROCESS Process;
139 KPROCESSOR_MODE PreviousMode;
140 NTSTATUS Status = STATUS_SUCCESS;
141
142 PAGED_CODE();
143
144 PreviousMode = ExGetPreviousMode();
145
146 DefaultQueryInfoBufferCheck(ProcessInformationClass,
147 PsProcessInfoClass,
148 ProcessInformation,
149 ProcessInformationLength,
150 ReturnLength,
151 PreviousMode,
152 &Status);
153 if(!NT_SUCCESS(Status))
154 {
155 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
156 return Status;
157 }
158
159 if(ProcessInformationClass != ProcessCookie)
160 {
161 Status = ObReferenceObjectByHandle(ProcessHandle,
162 PROCESS_QUERY_INFORMATION,
163 PsProcessType,
164 PreviousMode,
165 (PVOID*)&Process,
166 NULL);
167 if (!NT_SUCCESS(Status))
168 {
169 return(Status);
170 }
171 }
172 else if(ProcessHandle != NtCurrentProcess())
173 {
174 /* retreiving the process cookie is only allowed for the calling process
175 itself! XP only allowes NtCurrentProcess() as process handles even if a
176 real handle actually represents the current process. */
177 return STATUS_INVALID_PARAMETER;
178 }
179
180 switch (ProcessInformationClass)
181 {
182 case ProcessBasicInformation:
183 {
184 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
185 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
186
187 _SEH_TRY
188 {
189 ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
190 ProcessBasicInformationP->PebBaseAddress = Process->Peb;
191 ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
192 ProcessBasicInformationP->UniqueProcessId =
193 Process->UniqueProcessId;
194 ProcessBasicInformationP->InheritedFromUniqueProcessId =
195 Process->InheritedFromUniqueProcessId;
196 ProcessBasicInformationP->BasePriority =
197 Process->Pcb.BasePriority;
198
199 if (ReturnLength)
200 {
201 *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
202 }
203 }
204 _SEH_HANDLE
205 {
206 Status = _SEH_GetExceptionCode();
207 }
208 _SEH_END;
209 break;
210 }
211
212 case ProcessQuotaLimits:
213 case ProcessIoCounters:
214 Status = STATUS_NOT_IMPLEMENTED;
215 break;
216
217 case ProcessTimes:
218 {
219 PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
220 _SEH_TRY
221 {
222 ProcessTimeP->CreateTime = Process->CreateTime;
223 ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
224 ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
225 ProcessTimeP->ExitTime = Process->ExitTime;
226
227 if (ReturnLength)
228 {
229 *ReturnLength = sizeof(KERNEL_USER_TIMES);
230 }
231 }
232 _SEH_HANDLE
233 {
234 Status = _SEH_GetExceptionCode();
235 }
236 _SEH_END;
237 break;
238 }
239
240 case ProcessDebugPort:
241 {
242 _SEH_TRY
243 {
244 *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
245 if (ReturnLength)
246 {
247 *ReturnLength = sizeof(HANDLE);
248 }
249 }
250 _SEH_HANDLE
251 {
252 Status = _SEH_GetExceptionCode();
253 }
254 _SEH_END;
255 break;
256 }
257
258 case ProcessLdtInformation:
259 case ProcessWorkingSetWatch:
260 case ProcessWx86Information:
261 Status = STATUS_NOT_IMPLEMENTED;
262 break;
263
264 case ProcessHandleCount:
265 {
266 ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
267
268 _SEH_TRY
269 {
270 *(PULONG)ProcessInformation = HandleCount;
271 if (ReturnLength)
272 {
273 *ReturnLength = sizeof(ULONG);
274 }
275 }
276 _SEH_HANDLE
277 {
278 Status = _SEH_GetExceptionCode();
279 }
280 _SEH_END;
281 break;
282 }
283
284 case ProcessSessionInformation:
285 {
286 PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
287
288 _SEH_TRY
289 {
290 SessionInfo->SessionId = Process->SessionId;
291 if (ReturnLength)
292 {
293 *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
294 }
295 }
296 _SEH_HANDLE
297 {
298 Status = _SEH_GetExceptionCode();
299 }
300 _SEH_END;
301 break;
302 }
303
304 case ProcessWow64Information:
305 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
306 Status = STATUS_NOT_IMPLEMENTED;
307 break;
308
309 case ProcessVmCounters:
310 {
311 PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
312
313 _SEH_TRY
314 {
315 pOut->PeakVirtualSize = Process->PeakVirtualSize;
316 /*
317 * Here we should probably use VirtualSize.LowPart, but due to
318 * incompatibilities in current headers (no unnamed union),
319 * I opted for cast.
320 */
321 pOut->VirtualSize = (ULONG)Process->VirtualSize.QuadPart;
322 pOut->PageFaultCount = Process->Vm.PageFaultCount;
323 pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
324 pOut->WorkingSetSize = Process->Vm.WorkingSetSize;
325 pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeakPoolUsage[0]; // TODO: Verify!
326 pOut->QuotaPagedPoolUsage = Process->QuotaPoolUsage[0]; // TODO: Verify!
327 pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify!
328 pOut->QuotaNonPagedPoolUsage = Process->QuotaPoolUsage[1]; // TODO: Verify!
329 pOut->PagefileUsage = Process->PagefileUsage;
330 pOut->PeakPagefileUsage = Process->PeakPagefileUsage;
331
332 if (ReturnLength)
333 {
334 *ReturnLength = sizeof(VM_COUNTERS);
335 }
336 }
337 _SEH_HANDLE
338 {
339 Status = _SEH_GetExceptionCode();
340 }
341 _SEH_END;
342 break;
343 }
344
345 case ProcessDefaultHardErrorMode:
346 {
347 PULONG HardErrMode = (PULONG)ProcessInformation;
348 _SEH_TRY
349 {
350 *HardErrMode = Process->DefaultHardErrorProcessing;
351 if (ReturnLength)
352 {
353 *ReturnLength = sizeof(ULONG);
354 }
355 }
356 _SEH_HANDLE
357 {
358 Status = _SEH_GetExceptionCode();
359 }
360 _SEH_END;
361 break;
362 }
363
364 case ProcessPriorityBoost:
365 {
366 PULONG BoostEnabled = (PULONG)ProcessInformation;
367
368 _SEH_TRY
369 {
370 *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
371
372 if (ReturnLength)
373 {
374 *ReturnLength = sizeof(ULONG);
375 }
376 }
377 _SEH_HANDLE
378 {
379 Status = _SEH_GetExceptionCode();
380 }
381 _SEH_END;
382 break;
383 }
384
385 case ProcessDeviceMap:
386 {
387 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
388
389 ObQueryDeviceMapInformation(Process, &DeviceMap);
390
391 _SEH_TRY
392 {
393 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
394 if (ReturnLength)
395 {
396 *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
397 }
398 }
399 _SEH_HANDLE
400 {
401 Status = _SEH_GetExceptionCode();
402 }
403 _SEH_END;
404 break;
405 }
406
407 case ProcessPriorityClass:
408 {
409 PUSHORT Priority = (PUSHORT)ProcessInformation;
410
411 _SEH_TRY
412 {
413 *Priority = Process->PriorityClass;
414
415 if (ReturnLength)
416 {
417 *ReturnLength = sizeof(USHORT);
418 }
419 }
420 _SEH_HANDLE
421 {
422 Status = _SEH_GetExceptionCode();
423 }
424 _SEH_END;
425 break;
426 }
427
428 case ProcessImageFileName:
429 {
430 /*
431 * We DO NOT return the file name stored in the EPROCESS structure.
432 * Propably if we can't find a PEB or ProcessParameters structure for the
433 * process!
434 */
435 if(Process->Peb != NULL)
436 {
437 PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL;
438 UNICODE_STRING LocalDest;
439 BOOLEAN Attached;
440 ULONG ImagePathLen = 0;
441 PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
442
443 /* we need to attach to the process to make sure we're in the right context! */
444 Attached = Process != PsGetCurrentProcess();
445
446 if(Attached)
447 KeAttachProcess(&Process->Pcb);
448
449 _SEH_TRY
450 {
451 ProcParams = Process->Peb->ProcessParameters;
452 ImagePathLen = ProcParams->ImagePathName.Length;
453 }
454 _SEH_HANDLE
455 {
456 Status = _SEH_GetExceptionCode();
457 }
458 _SEH_END;
459
460 if(NT_SUCCESS(Status))
461 {
462 if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
463 {
464 Status = STATUS_INFO_LENGTH_MISMATCH;
465 }
466 else
467 {
468 PWSTR StrSource = NULL;
469
470 RtlZeroMemory(&LocalDest, sizeof(LocalDest));
471
472 /* create a DstPath structure on the stack */
473 _SEH_TRY
474 {
475 LocalDest.Length = ImagePathLen;
476 LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR);
477 LocalDest.Buffer = (PWSTR)(DstPath + 1);
478
479 /* save a copy of the pointer to the source buffer */
480 StrSource = ProcParams->ImagePathName.Buffer;
481 }
482 _SEH_HANDLE
483 {
484 Status = _SEH_GetExceptionCode();
485 }
486 _SEH_END;
487
488 if(NT_SUCCESS(Status))
489 {
490 /* now, let's allocate some anonymous memory to copy the string to.
491 we can't just copy it to the buffer the caller pointed as it might
492 be user memory in another context */
493 PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR));
494 if(PathCopy != NULL)
495 {
496 /* make a copy of the buffer to the temporary buffer */
497 _SEH_TRY
498 {
499 RtlCopyMemory(PathCopy, StrSource, LocalDest.Length);
500 PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0';
501 }
502 _SEH_HANDLE
503 {
504 Status = _SEH_GetExceptionCode();
505 }
506 _SEH_END;
507
508 /* detach from the process */
509 if(Attached)
510 KeDetachProcess();
511
512 /* only copy the string back to the caller if we were able to
513 copy it into the temporary buffer! */
514 if(NT_SUCCESS(Status))
515 {
516 /* now let's copy the buffer back to the caller */
517 _SEH_TRY
518 {
519 *DstPath = LocalDest;
520 RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR));
521 if (ReturnLength)
522 {
523 *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR);
524 }
525 }
526 _SEH_HANDLE
527 {
528 Status = _SEH_GetExceptionCode();
529 }
530 _SEH_END;
531 }
532
533 /* we're done with the copy operation, free the temporary kernel buffer */
534 ExFreePool(PathCopy);
535
536 /* we need to bail because we're already detached from the process */
537 break;
538 }
539 else
540 {
541 Status = STATUS_INSUFFICIENT_RESOURCES;
542 }
543 }
544 }
545 }
546
547 /* don't forget to detach from the process!!! */
548 if(Attached)
549 KeDetachProcess();
550 }
551 else
552 {
553 /* FIXME - what to do here? */
554 Status = STATUS_UNSUCCESSFUL;
555 }
556 break;
557 }
558
559 case ProcessCookie:
560 {
561 ULONG Cookie;
562
563 /* receive the process cookie, this is only allowed for the current
564 process! */
565
566 Process = PsGetCurrentProcess();
567
568 Cookie = Process->Cookie;
569 if(Cookie == 0)
570 {
571 LARGE_INTEGER SystemTime;
572 ULONG NewCookie;
573 PKPRCB Prcb;
574
575 /* generate a new cookie */
576
577 KeQuerySystemTime(&SystemTime);
578
579 Prcb = KeGetCurrentPrcb();
580
581 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
582 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
583
584 /* try to set the new cookie, return the current one if another thread
585 set it in the meanwhile */
586 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
587 NewCookie,
588 Cookie);
589 if(Cookie == 0)
590 {
591 /* successfully set the cookie */
592 Cookie = NewCookie;
593 }
594 }
595
596 _SEH_TRY
597 {
598 *(PULONG)ProcessInformation = Cookie;
599 if (ReturnLength)
600 {
601 *ReturnLength = sizeof(ULONG);
602 }
603 }
604 _SEH_HANDLE
605 {
606 Status = _SEH_GetExceptionCode();
607 }
608 _SEH_END;
609
610 break;
611 }
612
613 /*
614 * Note: The following 10 information classes are verified to not be
615 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
616 */
617 case ProcessBasePriority:
618 case ProcessRaisePriority:
619 case ProcessExceptionPort:
620 case ProcessAccessToken:
621 case ProcessLdtSize:
622 case ProcessIoPortHandlers:
623 case ProcessUserModeIOPL:
624 case ProcessEnableAlignmentFaultFixup:
625 case ProcessAffinityMask:
626 case ProcessForegroundInformation:
627 default:
628 Status = STATUS_INVALID_INFO_CLASS;
629 }
630
631 if(ProcessInformationClass != ProcessCookie)
632 {
633 ObDereferenceObject(Process);
634 }
635
636 return Status;
637 }
638
639 /*
640 * @unimplemented
641 */
642 NTSTATUS STDCALL
643 NtSetInformationProcess(IN HANDLE ProcessHandle,
644 IN PROCESSINFOCLASS ProcessInformationClass,
645 IN PVOID ProcessInformation,
646 IN ULONG ProcessInformationLength)
647 {
648 PEPROCESS Process;
649 KPROCESSOR_MODE PreviousMode;
650 ACCESS_MASK Access;
651 NTSTATUS Status = STATUS_SUCCESS;
652
653 PAGED_CODE();
654
655 PreviousMode = ExGetPreviousMode();
656
657 DefaultSetInfoBufferCheck(ProcessInformationClass,
658 PsProcessInfoClass,
659 ProcessInformation,
660 ProcessInformationLength,
661 PreviousMode,
662 &Status);
663 if(!NT_SUCCESS(Status))
664 {
665 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
666 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
667 return Status;
668 }
669
670 switch(ProcessInformationClass)
671 {
672 case ProcessSessionInformation:
673 Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
674 break;
675 case ProcessExceptionPort:
676 Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
677 break;
678
679 default:
680 Access = PROCESS_SET_INFORMATION;
681 break;
682 }
683
684 Status = ObReferenceObjectByHandle(ProcessHandle,
685 Access,
686 PsProcessType,
687 PreviousMode,
688 (PVOID*)&Process,
689 NULL);
690 if (!NT_SUCCESS(Status))
691 {
692 return(Status);
693 }
694
695 switch (ProcessInformationClass)
696 {
697 case ProcessQuotaLimits:
698 case ProcessBasePriority:
699 case ProcessRaisePriority:
700 Status = STATUS_NOT_IMPLEMENTED;
701 break;
702
703 case ProcessExceptionPort:
704 {
705 HANDLE PortHandle = NULL;
706
707 /* make a safe copy of the buffer on the stack */
708 _SEH_TRY
709 {
710 PortHandle = *(PHANDLE)ProcessInformation;
711 Status = STATUS_SUCCESS;
712 }
713 _SEH_HANDLE
714 {
715 Status = _SEH_GetExceptionCode();
716 }
717 _SEH_END;
718
719 if(NT_SUCCESS(Status))
720 {
721 PEPORT ExceptionPort;
722
723 /* in case we had success reading from the buffer, verify the provided
724 * LPC port handle
725 */
726 Status = ObReferenceObjectByHandle(PortHandle,
727 0,
728 LpcPortObjectType,
729 PreviousMode,
730 (PVOID)&ExceptionPort,
731 NULL);
732 if(NT_SUCCESS(Status))
733 {
734 /* lock the process to be thread-safe! */
735
736 Status = PsLockProcess(Process, FALSE);
737 if(NT_SUCCESS(Status))
738 {
739 /*
740 * according to "NT Native API" documentation, setting the exception
741 * port is only permitted once!
742 */
743 if(Process->ExceptionPort == NULL)
744 {
745 /* keep the reference to the handle! */
746 Process->ExceptionPort = ExceptionPort;
747 Status = STATUS_SUCCESS;
748 }
749 else
750 {
751 ObDereferenceObject(ExceptionPort);
752 Status = STATUS_PORT_ALREADY_SET;
753 }
754 PsUnlockProcess(Process);
755 }
756 else
757 {
758 ObDereferenceObject(ExceptionPort);
759 }
760 }
761 }
762 break;
763 }
764
765 case ProcessAccessToken:
766 {
767 HANDLE TokenHandle = NULL;
768
769 /* make a safe copy of the buffer on the stack */
770 _SEH_TRY
771 {
772 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
773 Status = STATUS_SUCCESS;
774 }
775 _SEH_HANDLE
776 {
777 Status = _SEH_GetExceptionCode();
778 }
779 _SEH_END;
780
781 if(NT_SUCCESS(Status))
782 {
783 /* in case we had success reading from the buffer, perform the actual task */
784 Status = PspAssignPrimaryToken(Process, TokenHandle);
785 }
786 break;
787 }
788
789 case ProcessDefaultHardErrorMode:
790 {
791 _SEH_TRY
792 {
793 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
794 *(PLONG)ProcessInformation);
795 Status = STATUS_SUCCESS;
796 }
797 _SEH_HANDLE
798 {
799 Status = _SEH_GetExceptionCode();
800 }
801 _SEH_END;
802 break;
803 }
804
805 case ProcessSessionInformation:
806 {
807 PROCESS_SESSION_INFORMATION SessionInfo;
808 Status = STATUS_SUCCESS;
809
810 RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
811
812 _SEH_TRY
813 {
814 /* copy the structure to the stack */
815 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
816 }
817 _SEH_HANDLE
818 {
819 Status = _SEH_GetExceptionCode();
820 }
821 _SEH_END;
822
823 if(NT_SUCCESS(Status))
824 {
825 /* we successfully copied the structure to the stack, continue processing */
826
827 /*
828 * setting the session id requires the SeTcbPrivilege!
829 */
830 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
831 PreviousMode))
832 {
833 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
834 /* can't set the session id, bail! */
835 Status = STATUS_PRIVILEGE_NOT_HELD;
836 break;
837 }
838
839 /* FIXME - update the session id for the process token */
840
841 Status = PsLockProcess(Process, FALSE);
842 if(NT_SUCCESS(Status))
843 {
844 Process->SessionId = SessionInfo.SessionId;
845
846 /* Update the session id in the PEB structure */
847 if(Process->Peb != NULL)
848 {
849 /* we need to attach to the process to make sure we're in the right
850 context to access the PEB structure */
851 KeAttachProcess(&Process->Pcb);
852
853 _SEH_TRY
854 {
855 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
856
857 Status = STATUS_SUCCESS;
858 }
859 _SEH_HANDLE
860 {
861 Status = _SEH_GetExceptionCode();
862 }
863 _SEH_END;
864
865 KeDetachProcess();
866 }
867
868 PsUnlockProcess(Process);
869 }
870 }
871 break;
872 }
873
874 case ProcessPriorityClass:
875 {
876 PROCESS_PRIORITY_CLASS ppc;
877
878 _SEH_TRY
879 {
880 ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
881 }
882 _SEH_HANDLE
883 {
884 Status = _SEH_GetExceptionCode();
885 }
886 _SEH_END;
887
888 if(NT_SUCCESS(Status))
889 {
890 }
891
892 break;
893 }
894
895 case ProcessLdtInformation:
896 case ProcessLdtSize:
897 case ProcessIoPortHandlers:
898 case ProcessWorkingSetWatch:
899 case ProcessUserModeIOPL:
900 case ProcessEnableAlignmentFaultFixup:
901 case ProcessAffinityMask:
902 Status = STATUS_NOT_IMPLEMENTED;
903 break;
904
905 case ProcessBasicInformation:
906 case ProcessIoCounters:
907 case ProcessTimes:
908 case ProcessPooledUsageAndLimits:
909 case ProcessWx86Information:
910 case ProcessHandleCount:
911 case ProcessWow64Information:
912 case ProcessDebugPort:
913 default:
914 Status = STATUS_INVALID_INFO_CLASS;
915 }
916 ObDereferenceObject(Process);
917 return(Status);
918 }
919
920
921 /**********************************************************************
922 * NAME INTERNAL
923 * PiQuerySystemProcessInformation
924 *
925 * DESCRIPTION
926 * Compute the size of a process+thread snapshot as
927 * expected by NtQuerySystemInformation.
928 *
929 * RETURN VALUE
930 * 0 on error; otherwise the size, in bytes of the buffer
931 * required to write a full snapshot.
932 *
933 * NOTE
934 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
935 */
936 NTSTATUS
937 PiQuerySystemProcessInformation(PVOID Buffer,
938 ULONG Size,
939 PULONG ReqSize)
940 {
941 return STATUS_NOT_IMPLEMENTED;
942
943 #if 0
944 PLIST_ENTRY CurrentEntryP;
945 PEPROCESS CurrentP;
946 PLIST_ENTRY CurrentEntryT;
947 PETHREAD CurrentT;
948
949 ULONG RequiredSize = 0L;
950 BOOLEAN SizeOnly = FALSE;
951
952 ULONG SpiSize = 0L;
953
954 PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
955 PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
956 PSYSTEM_THREAD_INFO pInfoT = NULL;
957
958
959 /* Lock the process list. */
960 ExAcquireFastMutex(&PspActiveProcessMutex);
961
962 /*
963 * Scan the process list. Since the
964 * list is circular, the guard is false
965 * after the last process.
966 */
967 for ( CurrentEntryP = PsActiveProcessHead.Flink;
968 (CurrentEntryP != & PsActiveProcessHead);
969 CurrentEntryP = CurrentEntryP->Flink
970 )
971 {
972 /*
973 * Compute how much space is
974 * occupied in the snapshot
975 * by adding this process info.
976 * (at least one thread).
977 */
978 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
979 RequiredSize += SpiSizeCurrent;
980 /*
981 * Do not write process data in the
982 * buffer if it is too small.
983 */
984 if (TRUE == SizeOnly) continue;
985 /*
986 * Check if the buffer can contain
987 * the full snapshot.
988 */
989 if (Size < RequiredSize)
990 {
991 SizeOnly = TRUE;
992 continue;
993 }
994 /*
995 * Get a reference to the
996 * process descriptor we are
997 * handling.
998 */
999 CurrentP = CONTAINING_RECORD(
1000 CurrentEntryP,
1001 EPROCESS,
1002 ProcessListEntry
1003 );
1004 /*
1005 * Write process data in the buffer.
1006 */
1007 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1008 /* PROCESS */
1009 pInfoP->ThreadCount = 0L;
1010 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1011 RtlInitUnicodeString (
1012 & pInfoP->Name,
1013 CurrentP->ImageFileName
1014 );
1015 /* THREAD */
1016 for ( pInfoT = & CurrentP->ThreadSysInfo [0],
1017 CurrentEntryT = CurrentP->ThreadListHead.Flink;
1018
1019 (CurrentEntryT != & CurrentP->ThreadListHead);
1020
1021 pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1022 CurrentEntryT = CurrentEntryT->Flink
1023 )
1024 {
1025 /*
1026 * Recalculate the size of the
1027 * information block.
1028 */
1029 if (0 < pInfoP->ThreadCount)
1030 {
1031 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1032 }
1033 /*
1034 * Do not write thread data in the
1035 * buffer if it is too small.
1036 */
1037 if (TRUE == SizeOnly) continue;
1038 /*
1039 * Check if the buffer can contain
1040 * the full snapshot.
1041 */
1042 if (Size < RequiredSize)
1043 {
1044 SizeOnly = TRUE;
1045 continue;
1046 }
1047 /*
1048 * Get a reference to the
1049 * thread descriptor we are
1050 * handling.
1051 */
1052 CurrentT = CONTAINING_RECORD(
1053 CurrentEntryT,
1054 KTHREAD,
1055 ThreadListEntry
1056 );
1057 /*
1058 * Write thread data.
1059 */
1060 RtlZeroMemory (
1061 pInfoT,
1062 sizeof (SYSTEM_THREAD_INFORMATION)
1063 );
1064 pInfoT->KernelTime = CurrentT-> ; /* TIME */
1065 pInfoT->UserTime = CurrentT-> ; /* TIME */
1066 pInfoT->CreateTime = CurrentT-> ; /* TIME */
1067 pInfoT->TickCount = CurrentT-> ; /* ULONG */
1068 pInfoT->StartEIP = CurrentT-> ; /* ULONG */
1069 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1070 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1071 pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */
1072 pInfoT->BasePriority = CurrentT-> ; /* ULONG */
1073 pInfoT->nSwitches = CurrentT-> ; /* ULONG */
1074 pInfoT->State = CurrentT-> ; /* DWORD */
1075 pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */
1076 /*
1077 * Count the number of threads
1078 * this process has.
1079 */
1080 ++ pInfoP->ThreadCount;
1081 }
1082 /*
1083 * Save the size of information
1084 * stored in the buffer for the
1085 * current process.
1086 */
1087 pInfoP->RelativeOffset = SpiSize;
1088 /*
1089 * Save a reference to the last
1090 * valid information block.
1091 */
1092 pInfoPLast = pInfoP;
1093 /*
1094 * Compute the offset of the
1095 * SYSTEM_PROCESS_INFORMATION
1096 * descriptor in the snapshot
1097 * buffer for the next process.
1098 */
1099 (ULONG) pInfoP += SpiSize;
1100 }
1101 /*
1102 * Unlock the process list.
1103 */
1104 ExReleaseFastMutex (
1105 & PspActiveProcessMutex
1106 );
1107 /*
1108 * Return the proper error status code,
1109 * if the buffer was too small.
1110 */
1111 if (TRUE == SizeOnly)
1112 {
1113 if (NULL != RequiredSize)
1114 {
1115 *pRequiredSize = RequiredSize;
1116 }
1117 return STATUS_INFO_LENGTH_MISMATCH;
1118 }
1119 /*
1120 * Mark the end of the snapshot.
1121 */
1122 pInfoP->RelativeOffset = 0L;
1123 /* OK */
1124 return STATUS_SUCCESS;
1125 #endif
1126 }
1127
1128 /*
1129 * @unimplemented
1130 */
1131 NTSTATUS STDCALL
1132 NtSetInformationThread (IN HANDLE ThreadHandle,
1133 IN THREADINFOCLASS ThreadInformationClass,
1134 IN PVOID ThreadInformation,
1135 IN ULONG ThreadInformationLength)
1136 {
1137 PETHREAD Thread;
1138 NTSTATUS Status;
1139 union
1140 {
1141 KPRIORITY Priority;
1142 LONG Increment;
1143 KAFFINITY Affinity;
1144 HANDLE Handle;
1145 PVOID Address;
1146 }u;
1147
1148 PAGED_CODE();
1149
1150 if (ThreadInformationClass <= MaxThreadInfoClass &&
1151 !SetInformationData[ThreadInformationClass].Implemented)
1152 {
1153 return STATUS_NOT_IMPLEMENTED;
1154 }
1155 if (ThreadInformationClass > MaxThreadInfoClass ||
1156 SetInformationData[ThreadInformationClass].Size == 0)
1157 {
1158 return STATUS_INVALID_INFO_CLASS;
1159 }
1160 if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
1161 {
1162 return STATUS_INFO_LENGTH_MISMATCH;
1163 }
1164
1165 Status = ObReferenceObjectByHandle (ThreadHandle,
1166 THREAD_SET_INFORMATION,
1167 PsThreadType,
1168 ExGetPreviousMode (),
1169 (PVOID*)&Thread,
1170 NULL);
1171 if (!NT_SUCCESS(Status))
1172 {
1173 return Status;
1174 }
1175
1176 Status = MmCopyFromCaller(&u.Priority,
1177 ThreadInformation,
1178 SetInformationData[ThreadInformationClass].Size);
1179 if (NT_SUCCESS(Status))
1180 {
1181 switch (ThreadInformationClass)
1182 {
1183 case ThreadPriority:
1184 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
1185 {
1186 Status = STATUS_INVALID_PARAMETER;
1187 break;
1188 }
1189 KeSetPriorityThread(&Thread->Tcb, u.Priority);
1190 break;
1191
1192 case ThreadBasePriority:
1193 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
1194 break;
1195
1196 case ThreadAffinityMask:
1197 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
1198 break;
1199
1200 case ThreadImpersonationToken:
1201 Status = PsAssignImpersonationToken (Thread, u.Handle);
1202 break;
1203
1204 case ThreadQuerySetWin32StartAddress:
1205 Thread->Win32StartAddress = u.Address;
1206 break;
1207
1208 default:
1209 /* Shoult never occure if the data table is correct */
1210 KEBUGCHECK(0);
1211 }
1212 }
1213 ObDereferenceObject (Thread);
1214
1215 return Status;
1216 }
1217
1218 /*
1219 * @implemented
1220 */
1221 NTSTATUS STDCALL
1222 NtQueryInformationThread (IN HANDLE ThreadHandle,
1223 IN THREADINFOCLASS ThreadInformationClass,
1224 OUT PVOID ThreadInformation,
1225 IN ULONG ThreadInformationLength,
1226 OUT PULONG ReturnLength OPTIONAL)
1227 {
1228 PETHREAD Thread;
1229 NTSTATUS Status;
1230 union
1231 {
1232 THREAD_BASIC_INFORMATION TBI;
1233 KERNEL_USER_TIMES TTI;
1234 PVOID Address;
1235 LARGE_INTEGER Count;
1236 BOOLEAN Last;
1237 }u;
1238
1239 PAGED_CODE();
1240
1241 if (ThreadInformationClass <= MaxThreadInfoClass &&
1242 !QueryInformationData[ThreadInformationClass].Implemented)
1243 {
1244 return STATUS_NOT_IMPLEMENTED;
1245 }
1246 if (ThreadInformationClass > MaxThreadInfoClass ||
1247 QueryInformationData[ThreadInformationClass].Size == 0)
1248 {
1249 return STATUS_INVALID_INFO_CLASS;
1250 }
1251 if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
1252 {
1253 return STATUS_INFO_LENGTH_MISMATCH;
1254 }
1255
1256 Status = ObReferenceObjectByHandle(ThreadHandle,
1257 THREAD_QUERY_INFORMATION,
1258 PsThreadType,
1259 ExGetPreviousMode(),
1260 (PVOID*)&Thread,
1261 NULL);
1262 if (!NT_SUCCESS(Status))
1263 {
1264 return Status;
1265 }
1266
1267 switch (ThreadInformationClass)
1268 {
1269 case ThreadBasicInformation:
1270 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1271 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1272 * 0. So do the conversion here:
1273 * -Gunnar */
1274 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
1275 u.TBI.TebBaseAddress = Thread->Tcb.Teb;
1276 u.TBI.ClientId = Thread->Cid;
1277 u.TBI.AffinityMask = Thread->Tcb.Affinity;
1278 u.TBI.Priority = Thread->Tcb.Priority;
1279 u.TBI.BasePriority = Thread->Tcb.BasePriority;
1280 break;
1281
1282 case ThreadTimes:
1283 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
1284 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
1285 u.TTI.CreateTime = Thread->CreateTime;
1286 /*This works*/
1287 u.TTI.ExitTime = Thread->ExitTime;
1288 break;
1289
1290 case ThreadQuerySetWin32StartAddress:
1291 u.Address = Thread->Win32StartAddress;
1292 break;
1293
1294 case ThreadPerformanceCount:
1295 /* Nebbett says this class is always zero */
1296 u.Count.QuadPart = 0;
1297 break;
1298
1299 case ThreadAmILastThread:
1300 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
1301 &Thread->ThreadsProcess->ThreadListHead)
1302 {
1303 u.Last = TRUE;
1304 }
1305 else
1306 {
1307 u.Last = FALSE;
1308 }
1309 break;
1310 default:
1311 /* Shoult never occure if the data table is correct */
1312 KEBUGCHECK(0);
1313 }
1314 if (QueryInformationData[ThreadInformationClass].Size)
1315 {
1316 Status = MmCopyToCaller(ThreadInformation,
1317 &u.TBI,
1318 QueryInformationData[ThreadInformationClass].Size);
1319 }
1320 if (ReturnLength)
1321 {
1322 NTSTATUS Status2;
1323 static ULONG Null = 0;
1324 Status2 = MmCopyToCaller(ReturnLength,
1325 NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null,
1326 sizeof(ULONG));
1327 if (NT_SUCCESS(Status))
1328 {
1329 Status = Status2;
1330 }
1331 }
1332
1333 ObDereferenceObject(Thread);
1334 return(Status);
1335 }
1336 /* EOF */