[CMAKE]
[reactos.git] / ntoskrnl / ps / query.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Process Manager: Thread/Process Query/Set Information
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 * Eric Kohl
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* Include Information Class Tables */
18 #include "internal/ps_i.h"
19
20 /* Debugging Level */
21 ULONG PspTraceLevel = 0;
22
23 /* PRIVATE FUNCTIONS *********************************************************/
24
25 NTSTATUS
26 NTAPI
27 PsReferenceProcessFilePointer(IN PEPROCESS Process,
28 OUT PFILE_OBJECT *FileObject)
29 {
30 PSECTION Section;
31 PAGED_CODE();
32
33 /* Lock the process */
34 ExAcquireRundownProtection(&Process->RundownProtect);
35
36 /* Get the section */
37 Section = Process->SectionObject;
38 if (Section)
39 {
40 /* Get the file object and reference it */
41 *FileObject = MmGetFileObjectForSection((PVOID)Section);
42 ObReferenceObject(*FileObject);
43 }
44
45 /* Release the protection */
46 ExReleaseRundownProtection(&Process->RundownProtect);
47
48 /* Return status */
49 return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
50 }
51
52 /* PUBLIC FUNCTIONS **********************************************************/
53
54 /*
55 * @implemented
56 */
57 NTSTATUS
58 NTAPI
59 NtQueryInformationProcess(IN HANDLE ProcessHandle,
60 IN PROCESSINFOCLASS ProcessInformationClass,
61 OUT PVOID ProcessInformation,
62 IN ULONG ProcessInformationLength,
63 OUT PULONG ReturnLength OPTIONAL)
64 {
65 PEPROCESS Process;
66 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
67 NTSTATUS Status;
68 ULONG Length = 0;
69 PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
70 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
71 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
72 PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
73 ULONG HandleCount;
74 PPROCESS_SESSION_INFORMATION SessionInfo =
75 (PPROCESS_SESSION_INFORMATION)ProcessInformation;
76 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
77 PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
78 PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
79 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
80 PUNICODE_STRING ImageName;
81 ULONG Cookie;
82 PAGED_CODE();
83
84 /* Check for user-mode caller */
85 if (PreviousMode != KernelMode)
86 {
87 /* Prepare to probe parameters */
88 _SEH2_TRY
89 {
90 /* Probe the buffer */
91 ProbeForWrite(ProcessInformation,
92 ProcessInformationLength,
93 sizeof(ULONG));
94
95 /* Probe the return length if required */
96 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
97 }
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
99 {
100 /* Return the exception code */
101 _SEH2_YIELD(return _SEH2_GetExceptionCode());
102 }
103 _SEH2_END;
104 }
105
106 if((ProcessInformationClass == ProcessCookie) &&
107 (ProcessHandle != NtCurrentProcess()))
108 {
109 /*
110 * Retreiving the process cookie is only allowed for the calling process
111 * itself! XP only allowes NtCurrentProcess() as process handles even if
112 * a real handle actually represents the current process.
113 */
114 return STATUS_INVALID_PARAMETER;
115 }
116
117 /* Check the information class */
118 switch (ProcessInformationClass)
119 {
120 /* Basic process information */
121 case ProcessBasicInformation:
122
123 /* Set return length */
124 Length = sizeof(PROCESS_BASIC_INFORMATION);
125
126 if (ProcessInformationLength != Length)
127 {
128 Status = STATUS_INFO_LENGTH_MISMATCH;
129 break;
130 }
131
132 /* Reference the process */
133 Status = ObReferenceObjectByHandle(ProcessHandle,
134 PROCESS_QUERY_INFORMATION,
135 PsProcessType,
136 PreviousMode,
137 (PVOID*)&Process,
138 NULL);
139 if (!NT_SUCCESS(Status)) break;
140
141 /* Protect writes with SEH */
142 _SEH2_TRY
143 {
144 /* Write all the information from the EPROCESS/KPROCESS */
145 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
146 ProcessBasicInfo->PebBaseAddress = Process->Peb;
147 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
148 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
149 UniqueProcessId;
150 ProcessBasicInfo->InheritedFromUniqueProcessId =
151 (ULONG)Process->InheritedFromUniqueProcessId;
152 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
153
154 }
155 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
156 {
157 /* Get exception code */
158 Status = _SEH2_GetExceptionCode();
159 }
160 _SEH2_END;
161
162 /* Dereference the process */
163 ObDereferenceObject(Process);
164 break;
165
166 /* Process quota limits */
167 case ProcessQuotaLimits:
168
169 Length = sizeof(QUOTA_LIMITS);
170 if (ProcessInformationLength != Length)
171 {
172 Status = STATUS_INFO_LENGTH_MISMATCH;
173 break;
174 }
175
176 /* Reference the process */
177 Status = ObReferenceObjectByHandle(ProcessHandle,
178 PROCESS_QUERY_INFORMATION,
179 PsProcessType,
180 PreviousMode,
181 (PVOID*)&Process,
182 NULL);
183 if (!NT_SUCCESS(Status)) break;
184
185 /* Indicate success */
186 Status = STATUS_SUCCESS;
187
188 _SEH2_TRY
189 {
190 /* Set max/min working set sizes */
191 QuotaLimits->MaximumWorkingSetSize =
192 Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
193 QuotaLimits->MinimumWorkingSetSize =
194 Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
195
196 /* Set default time limits */
197 QuotaLimits->TimeLimit.LowPart = MAXULONG;
198 QuotaLimits->TimeLimit.HighPart = MAXULONG;
199
200 /* Is quota block a default one? */
201 if (Process->QuotaBlock == &PspDefaultQuotaBlock)
202 {
203 /* Set default pools and pagefile limits */
204 QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
205 QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
206 QuotaLimits->PagefileLimit = (SIZE_T)-1;
207 }
208 else
209 {
210 /* Get limits from non-default quota block */
211 QuotaLimits->PagedPoolLimit =
212 Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
213 QuotaLimits->NonPagedPoolLimit =
214 Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
215 QuotaLimits->PagefileLimit =
216 Process->QuotaBlock->QuotaEntry[2].Limit;
217 }
218 }
219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
220 {
221 /* Get exception code */
222 Status = _SEH2_GetExceptionCode();
223 }
224 _SEH2_END;
225
226 /* Dereference the process */
227 ObDereferenceObject(Process);
228 break;
229
230 case ProcessIoCounters:
231
232 Length = sizeof(IO_COUNTERS);
233 if (ProcessInformationLength != Length)
234 {
235 Status = STATUS_INFO_LENGTH_MISMATCH;
236 break;
237 }
238
239 /* Reference the process */
240 Status = ObReferenceObjectByHandle(ProcessHandle,
241 PROCESS_QUERY_INFORMATION,
242 PsProcessType,
243 PreviousMode,
244 (PVOID*)&Process,
245 NULL);
246 if (!NT_SUCCESS(Status)) break;
247
248 _SEH2_TRY
249 {
250 IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
251 IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
252 IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
253 IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
254 IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
255 IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
256 }
257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
258 {
259 /* Ignore exception */
260 }
261 _SEH2_END;
262
263 /* Set status to success in any case */
264 Status = STATUS_SUCCESS;
265
266 /* Dereference the process */
267 ObDereferenceObject(Process);
268 break;
269
270 /* Timing */
271 case ProcessTimes:
272
273 /* Set the return length */
274 Length = sizeof(KERNEL_USER_TIMES);
275
276 if (ProcessInformationLength != Length)
277 {
278 Status = STATUS_INFO_LENGTH_MISMATCH;
279 break;
280 }
281
282 /* Reference the process */
283 Status = ObReferenceObjectByHandle(ProcessHandle,
284 PROCESS_QUERY_INFORMATION,
285 PsProcessType,
286 PreviousMode,
287 (PVOID*)&Process,
288 NULL);
289 if (!NT_SUCCESS(Status)) break;
290
291 /* Protect writes with SEH */
292 _SEH2_TRY
293 {
294 /* Copy time information from EPROCESS/KPROCESS */
295 ProcessTime->CreateTime = Process->CreateTime;
296 ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
297 100000LL;
298 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
299 100000LL;
300 ProcessTime->ExitTime = Process->ExitTime;
301 }
302 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
303 {
304 /* Get exception code */
305 Status = _SEH2_GetExceptionCode();
306 }
307 _SEH2_END;
308
309 /* Dereference the process */
310 ObDereferenceObject(Process);
311 break;
312
313 /* Process Debug Port */
314 case ProcessDebugPort:
315
316 /* Set return length */
317 Length = sizeof(HANDLE);
318
319 if (ProcessInformationLength != Length)
320 {
321 Status = STATUS_INFO_LENGTH_MISMATCH;
322 break;
323 }
324
325 /* Reference the process */
326 Status = ObReferenceObjectByHandle(ProcessHandle,
327 PROCESS_QUERY_INFORMATION,
328 PsProcessType,
329 PreviousMode,
330 (PVOID*)&Process,
331 NULL);
332 if (!NT_SUCCESS(Status)) break;
333
334 /* Protect write with SEH */
335 _SEH2_TRY
336 {
337 /* Return whether or not we have a debug port */
338 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
339 (HANDLE)-1 : NULL);
340 }
341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
342 {
343 /* Get exception code */
344 Status = _SEH2_GetExceptionCode();
345 }
346 _SEH2_END;
347
348 /* Dereference the process */
349 ObDereferenceObject(Process);
350 break;
351
352 /* LDT, WS and VDM Information: not implemented */
353 case ProcessLdtInformation:
354 case ProcessWorkingSetWatch:
355 case ProcessWx86Information:
356
357 /* Reference the process */
358 Status = ObReferenceObjectByHandle(ProcessHandle,
359 PROCESS_QUERY_INFORMATION,
360 PsProcessType,
361 PreviousMode,
362 (PVOID*)&Process,
363 NULL);
364 if (!NT_SUCCESS(Status)) break;
365
366 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
367
368 /* Dereference the process */
369 ObDereferenceObject(Process);
370 Status = STATUS_NOT_IMPLEMENTED;
371 break;
372
373 case ProcessHandleCount:
374
375 /* Set the return length*/
376 Length = sizeof(ULONG);
377
378 if (ProcessInformationLength != Length)
379 {
380 Status = STATUS_INFO_LENGTH_MISMATCH;
381 break;
382 }
383
384 /* Reference the process */
385 Status = ObReferenceObjectByHandle(ProcessHandle,
386 PROCESS_QUERY_INFORMATION,
387 PsProcessType,
388 PreviousMode,
389 (PVOID*)&Process,
390 NULL);
391 if (!NT_SUCCESS(Status)) break;
392
393 /* Count the number of handles this process has */
394 HandleCount = ObGetProcessHandleCount(Process);
395
396 /* Protect write in SEH */
397 _SEH2_TRY
398 {
399 /* Return the count of handles */
400 *(PULONG)ProcessInformation = HandleCount;
401 }
402 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
403 {
404 /* Get the exception code */
405 Status = _SEH2_GetExceptionCode();
406 }
407 _SEH2_END;
408
409 /* Dereference the process */
410 ObDereferenceObject(Process);
411 break;
412
413 /* Session ID for the process */
414 case ProcessSessionInformation:
415
416 /* Set the return length*/
417 Length = sizeof(PROCESS_SESSION_INFORMATION);
418
419 if (ProcessInformationLength != Length)
420 {
421 Status = STATUS_INFO_LENGTH_MISMATCH;
422 break;
423 }
424
425 /* Reference the process */
426 Status = ObReferenceObjectByHandle(ProcessHandle,
427 PROCESS_QUERY_INFORMATION,
428 PsProcessType,
429 PreviousMode,
430 (PVOID*)&Process,
431 NULL);
432 if (!NT_SUCCESS(Status)) break;
433
434 /* Enter SEH for write safety */
435 _SEH2_TRY
436 {
437 /* Write back the Session ID */
438 SessionInfo->SessionId = Process->Session;
439 }
440 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
441 {
442 /* Get the exception code */
443 Status = _SEH2_GetExceptionCode();
444 }
445 _SEH2_END;
446
447 /* Dereference the process */
448 ObDereferenceObject(Process);
449 break;
450
451 /* WOW64: Not implemented */
452 case ProcessWow64Information:
453
454 /* Set the return length */
455 Length = sizeof(ULONG_PTR);
456
457 if (ProcessInformationLength != Length)
458 {
459 Status = STATUS_INFO_LENGTH_MISMATCH;
460 break;
461 }
462
463 /* Reference the process */
464 Status = ObReferenceObjectByHandle(ProcessHandle,
465 PROCESS_QUERY_INFORMATION,
466 PsProcessType,
467 PreviousMode,
468 (PVOID*)&Process,
469 NULL);
470 if (!NT_SUCCESS(Status)) break;
471
472 /* Protect write in SEH */
473 _SEH2_TRY
474 {
475 #ifdef _WIN64
476 DPRINT1("Not implemented: ProcessWow64Information\n");
477 Status = STATUS_NOT_IMPLEMENTED;
478 #else
479 /* Wow64 not present */
480 *(PULONG_PTR)ProcessInformation = 0;
481 #endif
482 }
483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
484 {
485 /* Get the exception code */
486 Status = _SEH2_GetExceptionCode();
487 }
488 _SEH2_END;
489
490 /* Dereference the process */
491 ObDereferenceObject(Process);
492 break;
493
494 /* Virtual Memory Statistics */
495 case ProcessVmCounters:
496
497 /* Set the return length */
498 Length = sizeof(VM_COUNTERS);
499
500 if (ProcessInformationLength != Length)
501 {
502 Status = STATUS_INFO_LENGTH_MISMATCH;
503 break;
504 }
505
506 /* Reference the process */
507 Status = ObReferenceObjectByHandle(ProcessHandle,
508 PROCESS_QUERY_INFORMATION,
509 PsProcessType,
510 PreviousMode,
511 (PVOID*)&Process,
512 NULL);
513 if (!NT_SUCCESS(Status)) break;
514
515 /* Enter SEH for write safety */
516 _SEH2_TRY
517 {
518 /* Return data from EPROCESS */
519 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
520 VmCounters->VirtualSize = Process->VirtualSize;
521 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
522 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
523 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
524 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
525 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
526 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
527 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
528 VmCounters->PagefileUsage = Process->QuotaUsage[2];
529 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
530
531 }
532 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
533 {
534 /* Get the exception code */
535 Status = _SEH2_GetExceptionCode();
536 }
537 _SEH2_END;
538
539 /* Dereference the process */
540 ObDereferenceObject(Process);
541 break;
542
543 /* Hard Error Processing Mode */
544 case ProcessDefaultHardErrorMode:
545
546 /* Set the return length*/
547 Length = sizeof(ULONG);
548
549 if (ProcessInformationLength != Length)
550 {
551 Status = STATUS_INFO_LENGTH_MISMATCH;
552 break;
553 }
554
555 /* Reference the process */
556 Status = ObReferenceObjectByHandle(ProcessHandle,
557 PROCESS_QUERY_INFORMATION,
558 PsProcessType,
559 PreviousMode,
560 (PVOID*)&Process,
561 NULL);
562 if (!NT_SUCCESS(Status)) break;
563
564 /* Enter SEH for writing back data */
565 _SEH2_TRY
566 {
567 /* Write the current processing mode */
568 *(PULONG)ProcessInformation = Process->
569 DefaultHardErrorProcessing;
570 }
571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
572 {
573 /* Get the exception code */
574 Status = _SEH2_GetExceptionCode();
575 }
576 _SEH2_END;
577
578 /* Dereference the process */
579 ObDereferenceObject(Process);
580 break;
581
582 /* Priority Boosting status */
583 case ProcessPriorityBoost:
584
585 /* Set the return length*/
586 Length = sizeof(ULONG);
587
588 if (ProcessInformationLength != Length)
589 {
590 Status = STATUS_INFO_LENGTH_MISMATCH;
591 break;
592 }
593
594 /* Reference the process */
595 Status = ObReferenceObjectByHandle(ProcessHandle,
596 PROCESS_QUERY_INFORMATION,
597 PsProcessType,
598 PreviousMode,
599 (PVOID*)&Process,
600 NULL);
601 if (!NT_SUCCESS(Status)) break;
602
603 /* Enter SEH for writing back data */
604 _SEH2_TRY
605 {
606 /* Return boost status */
607 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
608 TRUE : FALSE;
609 }
610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
611 {
612 /* Get the exception code */
613 Status = _SEH2_GetExceptionCode();
614 }
615 _SEH2_END;
616
617 /* Dereference the process */
618 ObDereferenceObject(Process);
619 break;
620
621 /* DOS Device Map */
622 case ProcessDeviceMap:
623
624 /* Set the return length*/
625 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
626
627 if (ProcessInformationLength != Length)
628 {
629 Status = STATUS_INFO_LENGTH_MISMATCH;
630 break;
631 }
632
633 /* Reference the process */
634 Status = ObReferenceObjectByHandle(ProcessHandle,
635 PROCESS_QUERY_INFORMATION,
636 PsProcessType,
637 PreviousMode,
638 (PVOID*)&Process,
639 NULL);
640 if (!NT_SUCCESS(Status)) break;
641
642 /* Query the device map information */
643 ObQueryDeviceMapInformation(Process, &DeviceMap);
644
645 /* Enter SEH for writing back data */
646 _SEH2_TRY
647 {
648 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
649 }
650 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
651 {
652 /* Get the exception code */
653 Status = _SEH2_GetExceptionCode();
654 }
655 _SEH2_END;
656
657 /* Dereference the process */
658 ObDereferenceObject(Process);
659 break;
660
661 /* Priority class */
662 case ProcessPriorityClass:
663
664 /* Set the return length*/
665 Length = sizeof(PROCESS_PRIORITY_CLASS);
666
667 if (ProcessInformationLength != Length)
668 {
669 Status = STATUS_INFO_LENGTH_MISMATCH;
670 break;
671 }
672
673 /* Reference the process */
674 Status = ObReferenceObjectByHandle(ProcessHandle,
675 PROCESS_QUERY_INFORMATION,
676 PsProcessType,
677 PreviousMode,
678 (PVOID*)&Process,
679 NULL);
680 if (!NT_SUCCESS(Status)) break;
681
682 /* Enter SEH for writing back data */
683 _SEH2_TRY
684 {
685 /* Return current priority class */
686 PsPriorityClass->PriorityClass = Process->PriorityClass;
687 PsPriorityClass->Foreground = FALSE;
688 }
689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
690 {
691 /* Get the exception code */
692 Status = _SEH2_GetExceptionCode();
693 }
694 _SEH2_END;
695
696 /* Dereference the process */
697 ObDereferenceObject(Process);
698 break;
699
700 case ProcessImageFileName:
701
702 /* Reference the process */
703 Status = ObReferenceObjectByHandle(ProcessHandle,
704 PROCESS_QUERY_INFORMATION,
705 PsProcessType,
706 PreviousMode,
707 (PVOID*)&Process,
708 NULL);
709 if (!NT_SUCCESS(Status)) break;
710
711 /* Get the image path */
712 Status = SeLocateProcessImageName(Process, &ImageName);
713 if (NT_SUCCESS(Status))
714 {
715 /* Set return length */
716 Length = ImageName->MaximumLength +
717 sizeof(OBJECT_NAME_INFORMATION);
718
719 /* Make sure it's large enough */
720 if (Length <= ProcessInformationLength)
721 {
722 /* Enter SEH to protect write */
723 _SEH2_TRY
724 {
725 /* Copy it */
726 RtlCopyMemory(ProcessInformation,
727 ImageName,
728 Length);
729
730 /* Update pointer */
731 ((PUNICODE_STRING)ProcessInformation)->Buffer =
732 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
733 }
734 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
735 {
736 /* Get the exception code */
737 Status = _SEH2_GetExceptionCode();
738 }
739 _SEH2_END;
740 }
741 else
742 {
743 /* Buffer too small */
744 Status = STATUS_INFO_LENGTH_MISMATCH;
745 }
746
747 /* Free the image path */
748 ExFreePool(ImageName);
749 }
750 /* Dereference the process */
751 ObDereferenceObject(Process);
752 break;
753
754 case ProcessBreakOnTermination:
755
756 /* Set the return length*/
757 Length = sizeof(ULONG);
758 if (ProcessInformationLength != Length)
759 {
760 Status = STATUS_INFO_LENGTH_MISMATCH;
761 break;
762 }
763
764 /* Reference the process */
765 Status = ObReferenceObjectByHandle(ProcessHandle,
766 PROCESS_QUERY_INFORMATION,
767 PsProcessType,
768 PreviousMode,
769 (PVOID*)&Process,
770 NULL);
771 if (!NT_SUCCESS(Status)) break;
772
773 /* Enter SEH for writing back data */
774 _SEH2_TRY
775 {
776 /* Return the BreakOnTermination state */
777 *(PULONG)ProcessInformation = Process->BreakOnTermination;
778 }
779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
780 {
781 /* Get the exception code */
782 Status = _SEH2_GetExceptionCode();
783 }
784 _SEH2_END;
785
786 /* Dereference the process */
787 ObDereferenceObject(Process);
788 break;
789
790 /* Per-process security cookie */
791 case ProcessCookie:
792
793 /* Get the current process and cookie */
794 Process = PsGetCurrentProcess();
795 Cookie = Process->Cookie;
796 if (!Cookie)
797 {
798 LARGE_INTEGER SystemTime;
799 ULONG NewCookie;
800 PKPRCB Prcb;
801
802 /* Generate a new cookie */
803 KeQuerySystemTime(&SystemTime);
804 Prcb = KeGetCurrentPrcb();
805 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
806 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
807
808 /* Set the new cookie or return the current one */
809 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
810 NewCookie,
811 Cookie);
812 if (!Cookie) Cookie = NewCookie;
813
814 /* Set return length */
815 Length = sizeof(ULONG);
816 }
817
818 /* Indicate success */
819 Status = STATUS_SUCCESS;
820
821 /* Enter SEH to protect write */
822 _SEH2_TRY
823 {
824 /* Write back the cookie */
825 *(PULONG)ProcessInformation = Cookie;
826 }
827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
828 {
829 /* Get the exception code */
830 Status = _SEH2_GetExceptionCode();
831 }
832 _SEH2_END;
833 break;
834
835 /* Not yet implemented, or unknown */
836 case ProcessBasePriority:
837 case ProcessRaisePriority:
838 case ProcessExceptionPort:
839 case ProcessAccessToken:
840 case ProcessLdtSize:
841 case ProcessIoPortHandlers:
842 case ProcessUserModeIOPL:
843 case ProcessEnableAlignmentFaultFixup:
844 case ProcessAffinityMask:
845 case ProcessForegroundInformation:
846 default:
847 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
848 Status = STATUS_INVALID_INFO_CLASS;
849 }
850
851 /* Protect write with SEH */
852 _SEH2_TRY
853 {
854 /* Check if caller wanted return length */
855 if (ReturnLength) *ReturnLength = Length;
856 }
857 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
858 {
859 /* Get exception code */
860 Status = _SEH2_GetExceptionCode();
861 }
862 _SEH2_END;
863
864 return Status;
865 }
866
867 /*
868 * @implemented
869 */
870 NTSTATUS
871 NTAPI
872 NtSetInformationProcess(IN HANDLE ProcessHandle,
873 IN PROCESSINFOCLASS ProcessInformationClass,
874 IN PVOID ProcessInformation,
875 IN ULONG ProcessInformationLength)
876 {
877 PEPROCESS Process;
878 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
879 ACCESS_MASK Access;
880 NTSTATUS Status;
881 HANDLE PortHandle = NULL;
882 HANDLE TokenHandle = NULL;
883 PROCESS_SESSION_INFORMATION SessionInfo = {0};
884 PROCESS_PRIORITY_CLASS PriorityClass = {0};
885 PVOID ExceptionPort;
886 ULONG Break;
887 PAGED_CODE();
888
889 /* Verify Information Class validity */
890 #if 0
891 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
892 PsProcessInfoClass,
893 RTL_NUMBER_OF(PsProcessInfoClass),
894 ProcessInformation,
895 ProcessInformationLength,
896 PreviousMode);
897 if (!NT_SUCCESS(Status)) return Status;
898 #endif
899
900 /* Check what class this is */
901 Access = PROCESS_SET_INFORMATION;
902 if (ProcessInformationClass == ProcessSessionInformation)
903 {
904 /* Setting the Session ID needs a special mask */
905 Access |= PROCESS_SET_SESSIONID;
906 }
907 else if (ProcessInformationClass == ProcessExceptionPort)
908 {
909 /* Setting the exception port needs a special mask */
910 Access |= PROCESS_SUSPEND_RESUME;
911 }
912
913 /* Reference the process */
914 Status = ObReferenceObjectByHandle(ProcessHandle,
915 Access,
916 PsProcessType,
917 PreviousMode,
918 (PVOID*)&Process,
919 NULL);
920 if (!NT_SUCCESS(Status)) return Status;
921
922 /* Check what kind of information class this is */
923 switch (ProcessInformationClass)
924 {
925 /* Error/Exception Port */
926 case ProcessExceptionPort:
927
928 /* Check buffer length */
929 if (ProcessInformationLength != sizeof(HANDLE))
930 {
931 Status = STATUS_INFO_LENGTH_MISMATCH;
932 break;
933 }
934
935 /* Use SEH for capture */
936 _SEH2_TRY
937 {
938 /* Capture the handle */
939 PortHandle = *(PHANDLE)ProcessInformation;
940 }
941 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
942 {
943 /* Get the exception code */
944 Status = _SEH2_GetExceptionCode();
945 _SEH2_YIELD(break);
946 }
947 _SEH2_END;
948
949 /* Get the LPC Port */
950 Status = ObReferenceObjectByHandle(PortHandle,
951 0,
952 LpcPortObjectType,
953 PreviousMode,
954 (PVOID)&ExceptionPort,
955 NULL);
956 if (!NT_SUCCESS(Status)) break;
957
958 /* Change the pointer */
959 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
960 ExceptionPort,
961 NULL))
962 {
963 /* We already had one, fail */
964 ObDereferenceObject(ExceptionPort);
965 Status = STATUS_PORT_ALREADY_SET;
966 }
967 break;
968
969 /* Security Token */
970 case ProcessAccessToken:
971
972 /* Check buffer length */
973 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
974 {
975 Status = STATUS_INFO_LENGTH_MISMATCH;
976 break;
977 }
978
979 /* Use SEH for capture */
980 _SEH2_TRY
981 {
982 /* Save the token handle */
983 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
984 Token;
985 }
986 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
987 {
988 /* Get the exception code */
989 Status = _SEH2_GetExceptionCode();
990 _SEH2_YIELD(break);
991 }
992 _SEH2_END;
993
994 /* Assign the actual token */
995 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
996 break;
997
998 /* Hard error processing */
999 case ProcessDefaultHardErrorMode:
1000
1001 /* Check buffer length */
1002 if (ProcessInformationLength != sizeof(ULONG))
1003 {
1004 Status = STATUS_INFO_LENGTH_MISMATCH;
1005 break;
1006 }
1007
1008 /* Enter SEH for direct buffer read */
1009 _SEH2_TRY
1010 {
1011 /* Update the current mode abd return the previous one */
1012 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
1013 *(PLONG)ProcessInformation);
1014 }
1015 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1016 {
1017 /* Get exception code */
1018 Status = _SEH2_GetExceptionCode();
1019 }
1020 _SEH2_END;
1021 break;
1022
1023 /* Session ID */
1024 case ProcessSessionInformation:
1025
1026 /* Check buffer length */
1027 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
1028 {
1029 Status = STATUS_INFO_LENGTH_MISMATCH;
1030 break;
1031 }
1032
1033 /* Enter SEH for capture */
1034 _SEH2_TRY
1035 {
1036 /* Capture the caller's buffer */
1037 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1038 }
1039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1040 {
1041 /* Get the exception code */
1042 Status = _SEH2_GetExceptionCode();
1043 _SEH2_YIELD(break);
1044 }
1045 _SEH2_END;
1046
1047 /* Setting the session id requires the SeTcbPrivilege */
1048 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1049 {
1050 /* Can't set the session ID, bail out. */
1051 Status = STATUS_PRIVILEGE_NOT_HELD;
1052 break;
1053 }
1054
1055 /* FIXME - update the session id for the process token */
1056 //Status = PsLockProcess(Process, FALSE);
1057 if (!NT_SUCCESS(Status)) break;
1058
1059 /* Write the session ID in the EPROCESS */
1060 Process->Session = SessionInfo.SessionId;
1061
1062 /* Check if the process also has a PEB */
1063 if (Process->Peb)
1064 {
1065 /*
1066 * Attach to the process to make sure we're in the right
1067 * context to access the PEB structure
1068 */
1069 KeAttachProcess(&Process->Pcb);
1070
1071 /* Enter SEH for write to user-mode PEB */
1072 _SEH2_TRY
1073 {
1074 /* Write the session ID */
1075 Process->Peb->SessionId = SessionInfo.SessionId;
1076 }
1077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1078 {
1079 /* Get exception code */
1080 Status = _SEH2_GetExceptionCode();
1081 }
1082 _SEH2_END;
1083
1084 /* Detach from the process */
1085 KeDetachProcess();
1086 }
1087
1088 /* Unlock the process */
1089 //PsUnlockProcess(Process);
1090 break;
1091
1092 case ProcessPriorityClass:
1093
1094 /* Check buffer length */
1095 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1096 {
1097 Status = STATUS_INFO_LENGTH_MISMATCH;
1098 break;
1099 }
1100
1101 /* Enter SEH for capture */
1102 _SEH2_TRY
1103 {
1104 /* Capture the caller's buffer */
1105 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1106 }
1107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1108 {
1109 /* Return the exception code */
1110 Status = _SEH2_GetExceptionCode();
1111 _SEH2_YIELD(break);
1112 }
1113 _SEH2_END;
1114
1115 /* Check for invalid PriorityClass value */
1116 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1117 {
1118 Status = STATUS_INVALID_PARAMETER;
1119 break;
1120 }
1121
1122 /* TODO: Check privileges */
1123
1124 /* Check if we have a job */
1125 if (Process->Job)
1126 {
1127 DPRINT1("Jobs not yet supported\n");
1128 }
1129
1130 /* Set process priority class */
1131 Process->PriorityClass = PriorityClass.PriorityClass;
1132
1133 /* Set process priority mode (foreground or background) */
1134 PsSetProcessPriorityByClass(Process,
1135 !PriorityClass.Foreground ? PsProcessPriorityBackground :
1136 PsProcessPriorityForeground);
1137
1138 Status = STATUS_SUCCESS;
1139 break;
1140
1141 case ProcessQuotaLimits:
1142
1143 /* Check buffer length */
1144 if (ProcessInformationLength != sizeof(QUOTA_LIMITS))
1145 {
1146 Status = STATUS_INFO_LENGTH_MISMATCH;
1147 break;
1148 }
1149
1150 DPRINT1("Not implemented: ProcessQuotaLimits\n");
1151 Status = STATUS_NOT_IMPLEMENTED;
1152 break;
1153
1154 case ProcessBasePriority:
1155
1156 /* Check buffer length */
1157 if (ProcessInformationLength != sizeof(KPRIORITY))
1158 {
1159 Status = STATUS_INFO_LENGTH_MISMATCH;
1160 break;
1161 }
1162
1163 DPRINT1("Not implemented: ProcessBasePriority\n");
1164 Status = STATUS_NOT_IMPLEMENTED;
1165 break;
1166
1167 case ProcessRaisePriority:
1168
1169 /* Check buffer length */
1170 if (ProcessInformationLength != sizeof(ULONG))
1171 {
1172 Status = STATUS_INFO_LENGTH_MISMATCH;
1173 break;
1174 }
1175
1176 DPRINT1("Not implemented: ProcessRaisePriority\n");
1177 Status = STATUS_NOT_IMPLEMENTED;
1178 break;
1179
1180 case ProcessWx86Information:
1181
1182 /* Check buffer length */
1183 if (ProcessInformationLength != sizeof(HANDLE))
1184 {
1185 Status = STATUS_INFO_LENGTH_MISMATCH;
1186 break;
1187 }
1188
1189 DPRINT1("Not implemented: ProcessWx86Information\n");
1190 Status = STATUS_NOT_IMPLEMENTED;
1191 break;
1192
1193 case ProcessDebugPort:
1194
1195 /* Check buffer length */
1196 if (ProcessInformationLength != sizeof(HANDLE))
1197 {
1198 Status = STATUS_INFO_LENGTH_MISMATCH;
1199 break;
1200 }
1201
1202 DPRINT1("Not implemented: ProcessDebugPort\n");
1203 Status = STATUS_NOT_IMPLEMENTED;
1204 break;
1205
1206 case ProcessBreakOnTermination:
1207
1208 /* Check buffer length */
1209 if (ProcessInformationLength != sizeof(ULONG))
1210 {
1211 Status = STATUS_INFO_LENGTH_MISMATCH;
1212 break;
1213 }
1214
1215 /* Enter SEH for direct buffer read */
1216 _SEH2_TRY
1217 {
1218 Break = *(PULONG)ProcessInformation;
1219 }
1220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1221 {
1222 /* Get exception code */
1223 Break = 0;
1224 Status = _SEH2_GetExceptionCode();
1225 _SEH2_YIELD(break);
1226 }
1227 _SEH2_END;
1228
1229 /* Setting 'break on termination' requires the SeDebugPrivilege */
1230 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1231 {
1232 Status = STATUS_PRIVILEGE_NOT_HELD;
1233 break;
1234 }
1235
1236 /* Set or clear the flag */
1237 if (Break)
1238 {
1239 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1240 }
1241 else
1242 {
1243 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1244 }
1245
1246 break;
1247
1248 /* We currently don't implement any of these */
1249 case ProcessLdtInformation:
1250 case ProcessLdtSize:
1251 case ProcessIoPortHandlers:
1252 case ProcessWorkingSetWatch:
1253 case ProcessUserModeIOPL:
1254 case ProcessEnableAlignmentFaultFixup:
1255 case ProcessAffinityMask:
1256 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
1257 Status = STATUS_NOT_IMPLEMENTED;
1258 break;
1259
1260 /* Supposedly these are invalid...!? verify! */
1261 case ProcessBasicInformation:
1262 case ProcessIoCounters:
1263 case ProcessTimes:
1264 case ProcessPooledUsageAndLimits:
1265 case ProcessHandleCount:
1266 case ProcessWow64Information:
1267 default:
1268 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
1269 Status = STATUS_INVALID_INFO_CLASS;
1270 }
1271
1272 /* Dereference and return status */
1273 ObDereferenceObject(Process);
1274 return Status;
1275 }
1276
1277 /*
1278 * @implemented
1279 */
1280 NTSTATUS
1281 NTAPI
1282 NtSetInformationThread(IN HANDLE ThreadHandle,
1283 IN THREADINFOCLASS ThreadInformationClass,
1284 IN PVOID ThreadInformation,
1285 IN ULONG ThreadInformationLength)
1286 {
1287 PETHREAD Thread;
1288 ULONG Access;
1289 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1290 NTSTATUS Status;
1291 HANDLE TokenHandle = NULL;
1292 KPRIORITY Priority = 0;
1293 KAFFINITY Affinity = 0, CombinedAffinity;
1294 PVOID Address = NULL;
1295 PEPROCESS Process;
1296 ULONG DisableBoost = 0;
1297 ULONG IdealProcessor = 0;
1298 PTEB Teb;
1299 ULONG TlsIndex = 0;
1300 PVOID *ExpansionSlots;
1301 PETHREAD ProcThread;
1302 PAGED_CODE();
1303
1304 /* Verify Information Class validity */
1305 #if 0
1306 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1307 PsThreadInfoClass,
1308 RTL_NUMBER_OF(PsThreadInfoClass),
1309 ThreadInformation,
1310 ThreadInformationLength,
1311 PreviousMode);
1312 if (!NT_SUCCESS(Status)) return Status;
1313 #endif
1314
1315 /* Check what class this is */
1316 Access = THREAD_SET_INFORMATION;
1317 if (ThreadInformationClass == ThreadImpersonationToken)
1318 {
1319 /* Setting the impersonation token needs a special mask */
1320 Access = THREAD_SET_THREAD_TOKEN;
1321 }
1322
1323 /* Reference the thread */
1324 Status = ObReferenceObjectByHandle(ThreadHandle,
1325 Access,
1326 PsThreadType,
1327 PreviousMode,
1328 (PVOID*)&Thread,
1329 NULL);
1330 if (!NT_SUCCESS(Status)) return Status;
1331
1332 /* Check what kind of information class this is */
1333 switch (ThreadInformationClass)
1334 {
1335 /* Thread priority */
1336 case ThreadPriority:
1337
1338 /* Check buffer length */
1339 if (ThreadInformationLength != sizeof(KPRIORITY))
1340 {
1341 Status = STATUS_INFO_LENGTH_MISMATCH;
1342 break;
1343 }
1344
1345 /* Use SEH for capture */
1346 _SEH2_TRY
1347 {
1348 /* Get the priority */
1349 Priority = *(PLONG)ThreadInformation;
1350 }
1351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1352 {
1353 /* Get the exception code */
1354 Status = _SEH2_GetExceptionCode();
1355 _SEH2_YIELD(break);
1356 }
1357 _SEH2_END;
1358
1359 /* Validate it */
1360 if ((Priority > HIGH_PRIORITY) ||
1361 (Priority <= LOW_PRIORITY))
1362 {
1363 /* Fail */
1364 Status = STATUS_INVALID_PARAMETER;
1365 break;
1366 }
1367
1368 /* Set the priority */
1369 KeSetPriorityThread(&Thread->Tcb, Priority);
1370 break;
1371
1372 case ThreadBasePriority:
1373
1374 /* Check buffer length */
1375 if (ThreadInformationLength != sizeof(LONG))
1376 {
1377 Status = STATUS_INFO_LENGTH_MISMATCH;
1378 break;
1379 }
1380
1381 /* Use SEH for capture */
1382 _SEH2_TRY
1383 {
1384 /* Get the priority */
1385 Priority = *(PLONG)ThreadInformation;
1386 }
1387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1388 {
1389 /* Get the exception code */
1390 Status = _SEH2_GetExceptionCode();
1391 _SEH2_YIELD(break);
1392 }
1393 _SEH2_END;
1394
1395 /* Validate it */
1396 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
1397 (Priority < THREAD_BASE_PRIORITY_MIN))
1398 {
1399 /* These ones are OK */
1400 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
1401 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
1402 {
1403 /* Check if the process is real time */
1404 if (PsGetCurrentProcess()->PriorityClass !=
1405 PROCESS_PRIORITY_CLASS_REALTIME)
1406 {
1407 /* It isn't, fail */
1408 Status = STATUS_INVALID_PARAMETER;
1409 break;
1410 }
1411 }
1412 }
1413
1414 /* Set the base priority */
1415 KeSetBasePriorityThread(&Thread->Tcb, Priority);
1416 break;
1417
1418 case ThreadAffinityMask:
1419
1420 /* Check buffer length */
1421 if (ThreadInformationLength != sizeof(ULONG_PTR))
1422 {
1423 Status = STATUS_INFO_LENGTH_MISMATCH;
1424 break;
1425 }
1426
1427 /* Use SEH for capture */
1428 _SEH2_TRY
1429 {
1430 /* Get the priority */
1431 Affinity = *(PULONG_PTR)ThreadInformation;
1432 }
1433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1434 {
1435 /* Get the exception code */
1436 Status = _SEH2_GetExceptionCode();
1437 }
1438 _SEH2_END;
1439
1440 /* Validate it */
1441 if (!Affinity)
1442 {
1443 /* Fail */
1444 Status = STATUS_INVALID_PARAMETER;
1445 break;
1446 }
1447
1448 /* Get the process */
1449 Process = Thread->ThreadsProcess;
1450
1451 /* Try to acquire rundown */
1452 if (ExAcquireRundownProtection(&Process->RundownProtect))
1453 {
1454 /* Lock it */
1455 KeEnterCriticalRegion();
1456 ExAcquirePushLockShared(&Process->ProcessLock);
1457
1458 /* Combine masks */
1459 CombinedAffinity = Affinity & Process->Pcb.Affinity;
1460 if (CombinedAffinity != Affinity)
1461 {
1462 /* Fail */
1463 Status = STATUS_INVALID_PARAMETER;
1464 }
1465 else
1466 {
1467 /* Set the affinity */
1468 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
1469 }
1470
1471 /* Release the lock and rundown */
1472 ExReleasePushLockShared(&Process->ProcessLock);
1473 KeLeaveCriticalRegion();
1474 ExReleaseRundownProtection(&Process->RundownProtect);
1475 }
1476 else
1477 {
1478 /* Too late */
1479 Status = STATUS_PROCESS_IS_TERMINATING;
1480 }
1481
1482 /* Return status */
1483 break;
1484
1485 case ThreadImpersonationToken:
1486
1487 /* Check buffer length */
1488 if (ThreadInformationLength != sizeof(HANDLE))
1489 {
1490 Status = STATUS_INFO_LENGTH_MISMATCH;
1491 break;
1492 }
1493
1494 /* Use SEH for capture */
1495 _SEH2_TRY
1496 {
1497 /* Save the token handle */
1498 TokenHandle = *(PHANDLE)ThreadInformation;
1499 }
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1501 {
1502 /* Get the exception code */
1503 Status = _SEH2_GetExceptionCode();
1504 _SEH2_YIELD(break);
1505 }
1506 _SEH2_END;
1507
1508 /* Assign the actual token */
1509 Status = PsAssignImpersonationToken(Thread, TokenHandle);
1510 break;
1511
1512 case ThreadQuerySetWin32StartAddress:
1513
1514 /* Check buffer length */
1515 if (ThreadInformationLength != sizeof(ULONG_PTR))
1516 {
1517 Status = STATUS_INFO_LENGTH_MISMATCH;
1518 break;
1519 }
1520
1521 /* Use SEH for capture */
1522 _SEH2_TRY
1523 {
1524 /* Get the priority */
1525 Address = *(PVOID*)ThreadInformation;
1526 }
1527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1528 {
1529 /* Get the exception code */
1530 Status = _SEH2_GetExceptionCode();
1531 _SEH2_YIELD(break);
1532 }
1533 _SEH2_END;
1534
1535 /* Set the address */
1536 Thread->Win32StartAddress = Address;
1537 break;
1538
1539 case ThreadIdealProcessor:
1540
1541 /* Check buffer length */
1542 if (ThreadInformationLength != sizeof(ULONG_PTR))
1543 {
1544 Status = STATUS_INFO_LENGTH_MISMATCH;
1545 break;
1546 }
1547
1548 /* Use SEH for capture */
1549 _SEH2_TRY
1550 {
1551 /* Get the priority */
1552 IdealProcessor = *(PULONG_PTR)ThreadInformation;
1553 }
1554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1555 {
1556 /* Get the exception code */
1557 Status = _SEH2_GetExceptionCode();
1558 _SEH2_YIELD(break);
1559 }
1560 _SEH2_END;
1561
1562 /* Validate it */
1563 if (IdealProcessor > MAXIMUM_PROCESSORS)
1564 {
1565 /* Fail */
1566 Status = STATUS_INVALID_PARAMETER;
1567 break;
1568 }
1569
1570 /* Set the ideal */
1571 Status = KeSetIdealProcessorThread(&Thread->Tcb,
1572 (CCHAR)IdealProcessor);
1573
1574 /* Get the TEB and protect the thread */
1575 Teb = Thread->Tcb.Teb;
1576 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
1577 {
1578 /* Save the ideal processor */
1579 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
1580
1581 /* Release rundown protection */
1582 ExReleaseRundownProtection(&Thread->RundownProtect);
1583 }
1584
1585 break;
1586
1587 case ThreadPriorityBoost:
1588
1589 /* Check buffer length */
1590 if (ThreadInformationLength != sizeof(ULONG_PTR))
1591 {
1592 Status = STATUS_INFO_LENGTH_MISMATCH;
1593 break;
1594 }
1595
1596 /* Use SEH for capture */
1597 _SEH2_TRY
1598 {
1599 /* Get the priority */
1600 DisableBoost = *(PULONG_PTR)ThreadInformation;
1601 }
1602 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1603 {
1604 /* Get the exception code */
1605 Status = _SEH2_GetExceptionCode();
1606 _SEH2_YIELD(break);
1607 }
1608 _SEH2_END;
1609
1610 /* Call the kernel */
1611 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
1612 break;
1613
1614 case ThreadZeroTlsCell:
1615
1616 /* Check buffer length */
1617 if (ThreadInformationLength != sizeof(ULONG_PTR))
1618 {
1619 Status = STATUS_INFO_LENGTH_MISMATCH;
1620 break;
1621 }
1622
1623 /* Use SEH for capture */
1624 _SEH2_TRY
1625 {
1626 /* Get the priority */
1627 TlsIndex = *(PULONG_PTR)ThreadInformation;
1628 }
1629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1630 {
1631 /* Get the exception code */
1632 Status = _SEH2_GetExceptionCode();
1633 _SEH2_YIELD(break);
1634 }
1635 _SEH2_END;
1636
1637 /* This is only valid for the current thread */
1638 if (Thread != PsGetCurrentThread())
1639 {
1640 /* Fail */
1641 Status = STATUS_INVALID_PARAMETER;
1642 break;
1643 }
1644
1645 /* Get the process */
1646 Process = Thread->ThreadsProcess;
1647
1648 /* Loop the threads */
1649 ProcThread = PsGetNextProcessThread(Process, NULL);
1650 while (ProcThread)
1651 {
1652 /* Acquire rundown */
1653 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
1654 {
1655 /* Get the TEB */
1656 Teb = ProcThread->Tcb.Teb;
1657 if (Teb)
1658 {
1659 /* Check if we're in the expansion range */
1660 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
1661 {
1662 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
1663 TLS_EXPANSION_SLOTS) - 1)
1664 {
1665 /* Check if we have expansion slots */
1666 ExpansionSlots = Teb->TlsExpansionSlots;
1667 if (ExpansionSlots)
1668 {
1669 /* Clear the index */
1670 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
1671 }
1672 }
1673 }
1674 else
1675 {
1676 /* Clear the index */
1677 Teb->TlsSlots[TlsIndex] = NULL;
1678 }
1679 }
1680
1681 /* Release rundown */
1682 ExReleaseRundownProtection(&ProcThread->RundownProtect);
1683 }
1684
1685 /* Go to the next thread */
1686 ProcThread = PsGetNextProcessThread(Process, ProcThread);
1687 }
1688
1689 /* All done */
1690 break;
1691
1692 default:
1693 /* We don't implement it yet */
1694 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1695 Status = STATUS_NOT_IMPLEMENTED;
1696 }
1697
1698 /* Dereference and return status */
1699 ObDereferenceObject(Thread);
1700 return Status;
1701 }
1702
1703 /*
1704 * @implemented
1705 */
1706 NTSTATUS
1707 NTAPI
1708 NtQueryInformationThread(IN HANDLE ThreadHandle,
1709 IN THREADINFOCLASS ThreadInformationClass,
1710 OUT PVOID ThreadInformation,
1711 IN ULONG ThreadInformationLength,
1712 OUT PULONG ReturnLength OPTIONAL)
1713 {
1714 PETHREAD Thread;
1715 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1716 NTSTATUS Status;
1717 ULONG Access;
1718 ULONG Length = 0;
1719 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
1720 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
1721 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
1722 KIRQL OldIrql;
1723 PAGED_CODE();
1724
1725 /* Check if we were called from user mode */
1726 if (PreviousMode != KernelMode)
1727 {
1728 /* Enter SEH */
1729 _SEH2_TRY
1730 {
1731 /* Probe the buffer */
1732 ProbeForWrite(ThreadInformation,
1733 ThreadInformationLength,
1734 sizeof(ULONG));
1735
1736 /* Probe the return length if required */
1737 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
1738 }
1739 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1740 {
1741 /* Return the exception code */
1742 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1743 }
1744 _SEH2_END;
1745 }
1746
1747 /* Check what class this is */
1748 Access = THREAD_QUERY_INFORMATION;
1749
1750 /* Reference the process */
1751 Status = ObReferenceObjectByHandle(ThreadHandle,
1752 Access,
1753 PsThreadType,
1754 PreviousMode,
1755 (PVOID*)&Thread,
1756 NULL);
1757 if (!NT_SUCCESS(Status)) return Status;
1758
1759 /* Check what kind of information class this is */
1760 switch (ThreadInformationClass)
1761 {
1762 /* Basic thread information */
1763 case ThreadBasicInformation:
1764
1765 /* Set return length */
1766 Length = sizeof(THREAD_BASIC_INFORMATION);
1767
1768 if (ThreadInformationLength != Length)
1769 {
1770 Status = STATUS_INFO_LENGTH_MISMATCH;
1771 break;
1772 }
1773 /* Protect writes with SEH */
1774 _SEH2_TRY
1775 {
1776 /* Write all the information from the ETHREAD/KTHREAD */
1777 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
1778 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1779 ThreadBasicInfo->ClientId = Thread->Cid;
1780 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
1781 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
1782 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1783 }
1784 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1785 {
1786 /* Get exception code */
1787 Status = _SEH2_GetExceptionCode();
1788 }
1789 _SEH2_END;
1790 break;
1791
1792 /* Thread time information */
1793 case ThreadTimes:
1794
1795 /* Set the return length */
1796 Length = sizeof(KERNEL_USER_TIMES);
1797
1798 if (ThreadInformationLength != Length)
1799 {
1800 Status = STATUS_INFO_LENGTH_MISMATCH;
1801 break;
1802 }
1803 /* Protect writes with SEH */
1804 _SEH2_TRY
1805 {
1806 /* Copy time information from ETHREAD/KTHREAD */
1807 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
1808 100000LL;
1809 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
1810 100000LL;
1811 ThreadTime->CreateTime = Thread->CreateTime;
1812 ThreadTime->ExitTime = Thread->ExitTime;
1813 }
1814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1815 {
1816 /* Get exception code */
1817 Status = _SEH2_GetExceptionCode();
1818 }
1819 _SEH2_END;
1820 break;
1821
1822 case ThreadQuerySetWin32StartAddress:
1823
1824 /* Set the return length*/
1825 Length = sizeof(PVOID);
1826
1827 if (ThreadInformationLength != Length)
1828 {
1829 Status = STATUS_INFO_LENGTH_MISMATCH;
1830 break;
1831 }
1832 /* Protect write with SEH */
1833 _SEH2_TRY
1834 {
1835 /* Return the Win32 Start Address */
1836 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
1837 }
1838 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1839 {
1840 /* Get exception code */
1841 Status = _SEH2_GetExceptionCode();
1842 }
1843 _SEH2_END;
1844 break;
1845
1846 case ThreadPerformanceCount:
1847
1848 /* Set the return length*/
1849 Length = sizeof(LARGE_INTEGER);
1850
1851 if (ThreadInformationLength != Length)
1852 {
1853 Status = STATUS_INFO_LENGTH_MISMATCH;
1854 break;
1855 }
1856 /* Protect write with SEH */
1857 _SEH2_TRY
1858 {
1859 /* FIXME */
1860 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
1861 }
1862 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1863 {
1864 /* Get exception code */
1865 Status = _SEH2_GetExceptionCode();
1866 }
1867 _SEH2_END;
1868 break;
1869
1870 case ThreadAmILastThread:
1871
1872 /* Set the return length*/
1873 Length = sizeof(ULONG);
1874
1875 if (ThreadInformationLength != Length)
1876 {
1877 Status = STATUS_INFO_LENGTH_MISMATCH;
1878 break;
1879 }
1880 /* Protect write with SEH */
1881 _SEH2_TRY
1882 {
1883 /* Return whether or not we are the last thread */
1884 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1885 ThreadListHead.Flink->Flink ==
1886 &Thread->ThreadsProcess->
1887 ThreadListHead) ?
1888 TRUE : FALSE);
1889 }
1890 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1891 {
1892 /* Get exception code */
1893 Status = _SEH2_GetExceptionCode();
1894 }
1895 _SEH2_END;
1896 break;
1897
1898 case ThreadIsIoPending:
1899
1900 /* Set the return length*/
1901 Length = sizeof(ULONG);
1902
1903 if (ThreadInformationLength != Length)
1904 {
1905 Status = STATUS_INFO_LENGTH_MISMATCH;
1906 break;
1907 }
1908 /* Raise the IRQL to protect the IRP list */
1909 KeRaiseIrql(APC_LEVEL, &OldIrql);
1910
1911 /* Protect write with SEH */
1912 _SEH2_TRY
1913 {
1914 /* Check if the IRP list is empty or not */
1915 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1916 }
1917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1918 {
1919 /* Get exception code */
1920 Status = _SEH2_GetExceptionCode();
1921 }
1922 _SEH2_END;
1923
1924 /* Lower IRQL back */
1925 KeLowerIrql(OldIrql);
1926 break;
1927
1928 /* LDT and GDT information */
1929 case ThreadDescriptorTableEntry:
1930
1931 #if defined(_X86_)
1932 /* Call the worker routine */
1933 Status = PspQueryDescriptorThread(Thread,
1934 ThreadInformation,
1935 ThreadInformationLength,
1936 ReturnLength);
1937 #else
1938 /* Only implemented on x86 */
1939 Status = STATUS_NOT_IMPLEMENTED;
1940 #endif
1941 break;
1942
1943 case ThreadPriorityBoost:
1944
1945 /* Set the return length*/
1946 Length = sizeof(ULONG);
1947
1948 if (ThreadInformationLength != Length)
1949 {
1950 Status = STATUS_INFO_LENGTH_MISMATCH;
1951 break;
1952 }
1953
1954 _SEH2_TRY
1955 {
1956 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
1957 }
1958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1959 {
1960 Status = _SEH2_GetExceptionCode();
1961 }
1962 _SEH2_END;
1963 break;
1964
1965 /* Anything else */
1966 default:
1967
1968 /* Not yet implemented */
1969 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1970 Status = STATUS_NOT_IMPLEMENTED;
1971 }
1972
1973 /* Protect write with SEH */
1974 _SEH2_TRY
1975 {
1976 /* Check if caller wanted return length */
1977 if (ReturnLength) *ReturnLength = Length;
1978 }
1979 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1980 {
1981 /* Get exception code */
1982 Status = _SEH2_GetExceptionCode();
1983 }
1984 _SEH2_END;
1985
1986 /* Dereference the thread, and return */
1987 ObDereferenceObject(Thread);
1988 return Status;
1989 }
1990
1991 /* EOF */