[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 DPRINT1("Not implemented: ProcessWow64Information\n");
473
474 /* Dereference the process */
475 ObDereferenceObject(Process);
476 Status = STATUS_NOT_IMPLEMENTED;
477 break;
478
479 /* Virtual Memory Statistics */
480 case ProcessVmCounters:
481
482 /* Set the return length */
483 Length = sizeof(VM_COUNTERS);
484
485 if (ProcessInformationLength != Length)
486 {
487 Status = STATUS_INFO_LENGTH_MISMATCH;
488 break;
489 }
490
491 /* Reference the process */
492 Status = ObReferenceObjectByHandle(ProcessHandle,
493 PROCESS_QUERY_INFORMATION,
494 PsProcessType,
495 PreviousMode,
496 (PVOID*)&Process,
497 NULL);
498 if (!NT_SUCCESS(Status)) break;
499
500 /* Enter SEH for write safety */
501 _SEH2_TRY
502 {
503 /* Return data from EPROCESS */
504 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
505 VmCounters->VirtualSize = Process->VirtualSize;
506 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
507 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
508 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
509 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
510 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
511 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
512 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
513 VmCounters->PagefileUsage = Process->QuotaUsage[2];
514 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
515
516 }
517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
518 {
519 /* Get the exception code */
520 Status = _SEH2_GetExceptionCode();
521 }
522 _SEH2_END;
523
524 /* Dereference the process */
525 ObDereferenceObject(Process);
526 break;
527
528 /* Hard Error Processing Mode */
529 case ProcessDefaultHardErrorMode:
530
531 /* Set the return length*/
532 Length = sizeof(ULONG);
533
534 if (ProcessInformationLength != Length)
535 {
536 Status = STATUS_INFO_LENGTH_MISMATCH;
537 break;
538 }
539
540 /* Reference the process */
541 Status = ObReferenceObjectByHandle(ProcessHandle,
542 PROCESS_QUERY_INFORMATION,
543 PsProcessType,
544 PreviousMode,
545 (PVOID*)&Process,
546 NULL);
547 if (!NT_SUCCESS(Status)) break;
548
549 /* Enter SEH for writing back data */
550 _SEH2_TRY
551 {
552 /* Write the current processing mode */
553 *(PULONG)ProcessInformation = Process->
554 DefaultHardErrorProcessing;
555 }
556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
557 {
558 /* Get the exception code */
559 Status = _SEH2_GetExceptionCode();
560 }
561 _SEH2_END;
562
563 /* Dereference the process */
564 ObDereferenceObject(Process);
565 break;
566
567 /* Priority Boosting status */
568 case ProcessPriorityBoost:
569
570 /* Set the return length*/
571 Length = sizeof(ULONG);
572
573 if (ProcessInformationLength != Length)
574 {
575 Status = STATUS_INFO_LENGTH_MISMATCH;
576 break;
577 }
578
579 /* Reference the process */
580 Status = ObReferenceObjectByHandle(ProcessHandle,
581 PROCESS_QUERY_INFORMATION,
582 PsProcessType,
583 PreviousMode,
584 (PVOID*)&Process,
585 NULL);
586 if (!NT_SUCCESS(Status)) break;
587
588 /* Enter SEH for writing back data */
589 _SEH2_TRY
590 {
591 /* Return boost status */
592 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
593 TRUE : FALSE;
594 }
595 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
596 {
597 /* Get the exception code */
598 Status = _SEH2_GetExceptionCode();
599 }
600 _SEH2_END;
601
602 /* Dereference the process */
603 ObDereferenceObject(Process);
604 break;
605
606 /* DOS Device Map */
607 case ProcessDeviceMap:
608
609 /* Set the return length*/
610 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
611
612 if (ProcessInformationLength != Length)
613 {
614 Status = STATUS_INFO_LENGTH_MISMATCH;
615 break;
616 }
617
618 /* Reference the process */
619 Status = ObReferenceObjectByHandle(ProcessHandle,
620 PROCESS_QUERY_INFORMATION,
621 PsProcessType,
622 PreviousMode,
623 (PVOID*)&Process,
624 NULL);
625 if (!NT_SUCCESS(Status)) break;
626
627 /* Query the device map information */
628 ObQueryDeviceMapInformation(Process, &DeviceMap);
629
630 /* Enter SEH for writing back data */
631 _SEH2_TRY
632 {
633 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
634 }
635 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
636 {
637 /* Get the exception code */
638 Status = _SEH2_GetExceptionCode();
639 }
640 _SEH2_END;
641
642 /* Dereference the process */
643 ObDereferenceObject(Process);
644 break;
645
646 /* Priority class */
647 case ProcessPriorityClass:
648
649 /* Set the return length*/
650 Length = sizeof(PROCESS_PRIORITY_CLASS);
651
652 if (ProcessInformationLength != Length)
653 {
654 Status = STATUS_INFO_LENGTH_MISMATCH;
655 break;
656 }
657
658 /* Reference the process */
659 Status = ObReferenceObjectByHandle(ProcessHandle,
660 PROCESS_QUERY_INFORMATION,
661 PsProcessType,
662 PreviousMode,
663 (PVOID*)&Process,
664 NULL);
665 if (!NT_SUCCESS(Status)) break;
666
667 /* Enter SEH for writing back data */
668 _SEH2_TRY
669 {
670 /* Return current priority class */
671 PsPriorityClass->PriorityClass = Process->PriorityClass;
672 PsPriorityClass->Foreground = FALSE;
673 }
674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
675 {
676 /* Get the exception code */
677 Status = _SEH2_GetExceptionCode();
678 }
679 _SEH2_END;
680
681 /* Dereference the process */
682 ObDereferenceObject(Process);
683 break;
684
685 case ProcessImageFileName:
686
687 /* Reference the process */
688 Status = ObReferenceObjectByHandle(ProcessHandle,
689 PROCESS_QUERY_INFORMATION,
690 PsProcessType,
691 PreviousMode,
692 (PVOID*)&Process,
693 NULL);
694 if (!NT_SUCCESS(Status)) break;
695
696 /* Get the image path */
697 Status = SeLocateProcessImageName(Process, &ImageName);
698 if (NT_SUCCESS(Status))
699 {
700 /* Set return length */
701 Length = ImageName->MaximumLength +
702 sizeof(OBJECT_NAME_INFORMATION);
703
704 /* Make sure it's large enough */
705 if (Length <= ProcessInformationLength)
706 {
707 /* Enter SEH to protect write */
708 _SEH2_TRY
709 {
710 /* Copy it */
711 RtlCopyMemory(ProcessInformation,
712 ImageName,
713 Length);
714
715 /* Update pointer */
716 ((PUNICODE_STRING)ProcessInformation)->Buffer =
717 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
718 }
719 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
720 {
721 /* Get the exception code */
722 Status = _SEH2_GetExceptionCode();
723 }
724 _SEH2_END;
725 }
726 else
727 {
728 /* Buffer too small */
729 Status = STATUS_INFO_LENGTH_MISMATCH;
730 }
731
732 /* Free the image path */
733 ExFreePool(ImageName);
734 }
735 /* Dereference the process */
736 ObDereferenceObject(Process);
737 break;
738
739 case ProcessBreakOnTermination:
740
741 /* Set the return length*/
742 Length = sizeof(ULONG);
743 if (ProcessInformationLength != Length)
744 {
745 Status = STATUS_INFO_LENGTH_MISMATCH;
746 break;
747 }
748
749 /* Reference the process */
750 Status = ObReferenceObjectByHandle(ProcessHandle,
751 PROCESS_QUERY_INFORMATION,
752 PsProcessType,
753 PreviousMode,
754 (PVOID*)&Process,
755 NULL);
756 if (!NT_SUCCESS(Status)) break;
757
758 /* Enter SEH for writing back data */
759 _SEH2_TRY
760 {
761 /* Return the BreakOnTermination state */
762 *(PULONG)ProcessInformation = Process->BreakOnTermination;
763 }
764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
765 {
766 /* Get the exception code */
767 Status = _SEH2_GetExceptionCode();
768 }
769 _SEH2_END;
770
771 /* Dereference the process */
772 ObDereferenceObject(Process);
773 break;
774
775 /* Per-process security cookie */
776 case ProcessCookie:
777
778 /* Get the current process and cookie */
779 Process = PsGetCurrentProcess();
780 Cookie = Process->Cookie;
781 if (!Cookie)
782 {
783 LARGE_INTEGER SystemTime;
784 ULONG NewCookie;
785 PKPRCB Prcb;
786
787 /* Generate a new cookie */
788 KeQuerySystemTime(&SystemTime);
789 Prcb = KeGetCurrentPrcb();
790 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
791 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
792
793 /* Set the new cookie or return the current one */
794 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
795 NewCookie,
796 Cookie);
797 if (!Cookie) Cookie = NewCookie;
798
799 /* Set return length */
800 Length = sizeof(ULONG);
801 }
802
803 /* Indicate success */
804 Status = STATUS_SUCCESS;
805
806 /* Enter SEH to protect write */
807 _SEH2_TRY
808 {
809 /* Write back the cookie */
810 *(PULONG)ProcessInformation = Cookie;
811 }
812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
813 {
814 /* Get the exception code */
815 Status = _SEH2_GetExceptionCode();
816 }
817 _SEH2_END;
818 break;
819
820 /* Not yet implemented, or unknown */
821 case ProcessBasePriority:
822 case ProcessRaisePriority:
823 case ProcessExceptionPort:
824 case ProcessAccessToken:
825 case ProcessLdtSize:
826 case ProcessIoPortHandlers:
827 case ProcessUserModeIOPL:
828 case ProcessEnableAlignmentFaultFixup:
829 case ProcessAffinityMask:
830 case ProcessForegroundInformation:
831 default:
832 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
833 Status = STATUS_INVALID_INFO_CLASS;
834 }
835
836 /* Protect write with SEH */
837 _SEH2_TRY
838 {
839 /* Check if caller wanted return length */
840 if (ReturnLength) *ReturnLength = Length;
841 }
842 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
843 {
844 /* Get exception code */
845 Status = _SEH2_GetExceptionCode();
846 }
847 _SEH2_END;
848
849 return Status;
850 }
851
852 /*
853 * @implemented
854 */
855 NTSTATUS
856 NTAPI
857 NtSetInformationProcess(IN HANDLE ProcessHandle,
858 IN PROCESSINFOCLASS ProcessInformationClass,
859 IN PVOID ProcessInformation,
860 IN ULONG ProcessInformationLength)
861 {
862 PEPROCESS Process;
863 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
864 ACCESS_MASK Access;
865 NTSTATUS Status;
866 HANDLE PortHandle = NULL;
867 HANDLE TokenHandle = NULL;
868 PROCESS_SESSION_INFORMATION SessionInfo = {0};
869 PROCESS_PRIORITY_CLASS PriorityClass = {0};
870 PVOID ExceptionPort;
871 ULONG Break;
872 PAGED_CODE();
873
874 /* Verify Information Class validity */
875 #if 0
876 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
877 PsProcessInfoClass,
878 RTL_NUMBER_OF(PsProcessInfoClass),
879 ProcessInformation,
880 ProcessInformationLength,
881 PreviousMode);
882 if (!NT_SUCCESS(Status)) return Status;
883 #endif
884
885 /* Check what class this is */
886 Access = PROCESS_SET_INFORMATION;
887 if (ProcessInformationClass == ProcessSessionInformation)
888 {
889 /* Setting the Session ID needs a special mask */
890 Access |= PROCESS_SET_SESSIONID;
891 }
892 else if (ProcessInformationClass == ProcessExceptionPort)
893 {
894 /* Setting the exception port needs a special mask */
895 Access |= PROCESS_SUSPEND_RESUME;
896 }
897
898 /* Reference the process */
899 Status = ObReferenceObjectByHandle(ProcessHandle,
900 Access,
901 PsProcessType,
902 PreviousMode,
903 (PVOID*)&Process,
904 NULL);
905 if (!NT_SUCCESS(Status)) return Status;
906
907 /* Check what kind of information class this is */
908 switch (ProcessInformationClass)
909 {
910 /* Error/Exception Port */
911 case ProcessExceptionPort:
912
913 /* Check buffer length */
914 if (ProcessInformationLength != sizeof(HANDLE))
915 {
916 Status = STATUS_INFO_LENGTH_MISMATCH;
917 break;
918 }
919
920 /* Use SEH for capture */
921 _SEH2_TRY
922 {
923 /* Capture the handle */
924 PortHandle = *(PHANDLE)ProcessInformation;
925 }
926 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
927 {
928 /* Get the exception code */
929 Status = _SEH2_GetExceptionCode();
930 _SEH2_YIELD(break);
931 }
932 _SEH2_END;
933
934 /* Get the LPC Port */
935 Status = ObReferenceObjectByHandle(PortHandle,
936 0,
937 LpcPortObjectType,
938 PreviousMode,
939 (PVOID)&ExceptionPort,
940 NULL);
941 if (!NT_SUCCESS(Status)) break;
942
943 /* Change the pointer */
944 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
945 ExceptionPort,
946 NULL))
947 {
948 /* We already had one, fail */
949 ObDereferenceObject(ExceptionPort);
950 Status = STATUS_PORT_ALREADY_SET;
951 }
952 break;
953
954 /* Security Token */
955 case ProcessAccessToken:
956
957 /* Check buffer length */
958 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
959 {
960 Status = STATUS_INFO_LENGTH_MISMATCH;
961 break;
962 }
963
964 /* Use SEH for capture */
965 _SEH2_TRY
966 {
967 /* Save the token handle */
968 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
969 Token;
970 }
971 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
972 {
973 /* Get the exception code */
974 Status = _SEH2_GetExceptionCode();
975 _SEH2_YIELD(break);
976 }
977 _SEH2_END;
978
979 /* Assign the actual token */
980 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
981 break;
982
983 /* Hard error processing */
984 case ProcessDefaultHardErrorMode:
985
986 /* Check buffer length */
987 if (ProcessInformationLength != sizeof(ULONG))
988 {
989 Status = STATUS_INFO_LENGTH_MISMATCH;
990 break;
991 }
992
993 /* Enter SEH for direct buffer read */
994 _SEH2_TRY
995 {
996 /* Update the current mode abd return the previous one */
997 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
998 *(PLONG)ProcessInformation);
999 }
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1001 {
1002 /* Get exception code */
1003 Status = _SEH2_GetExceptionCode();
1004 }
1005 _SEH2_END;
1006 break;
1007
1008 /* Session ID */
1009 case ProcessSessionInformation:
1010
1011 /* Check buffer length */
1012 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
1013 {
1014 Status = STATUS_INFO_LENGTH_MISMATCH;
1015 break;
1016 }
1017
1018 /* Enter SEH for capture */
1019 _SEH2_TRY
1020 {
1021 /* Capture the caller's buffer */
1022 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1023 }
1024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1025 {
1026 /* Get the exception code */
1027 Status = _SEH2_GetExceptionCode();
1028 _SEH2_YIELD(break);
1029 }
1030 _SEH2_END;
1031
1032 /* Setting the session id requires the SeTcbPrivilege */
1033 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1034 {
1035 /* Can't set the session ID, bail out. */
1036 Status = STATUS_PRIVILEGE_NOT_HELD;
1037 break;
1038 }
1039
1040 /* FIXME - update the session id for the process token */
1041 //Status = PsLockProcess(Process, FALSE);
1042 if (!NT_SUCCESS(Status)) break;
1043
1044 /* Write the session ID in the EPROCESS */
1045 Process->Session = SessionInfo.SessionId;
1046
1047 /* Check if the process also has a PEB */
1048 if (Process->Peb)
1049 {
1050 /*
1051 * Attach to the process to make sure we're in the right
1052 * context to access the PEB structure
1053 */
1054 KeAttachProcess(&Process->Pcb);
1055
1056 /* Enter SEH for write to user-mode PEB */
1057 _SEH2_TRY
1058 {
1059 /* Write the session ID */
1060 Process->Peb->SessionId = SessionInfo.SessionId;
1061 }
1062 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1063 {
1064 /* Get exception code */
1065 Status = _SEH2_GetExceptionCode();
1066 }
1067 _SEH2_END;
1068
1069 /* Detach from the process */
1070 KeDetachProcess();
1071 }
1072
1073 /* Unlock the process */
1074 //PsUnlockProcess(Process);
1075 break;
1076
1077 case ProcessPriorityClass:
1078
1079 /* Check buffer length */
1080 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1081 {
1082 Status = STATUS_INFO_LENGTH_MISMATCH;
1083 break;
1084 }
1085
1086 /* Enter SEH for capture */
1087 _SEH2_TRY
1088 {
1089 /* Capture the caller's buffer */
1090 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1091 }
1092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1093 {
1094 /* Return the exception code */
1095 Status = _SEH2_GetExceptionCode();
1096 _SEH2_YIELD(break);
1097 }
1098 _SEH2_END;
1099
1100 /* Check for invalid PriorityClass value */
1101 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1102 {
1103 Status = STATUS_INVALID_PARAMETER;
1104 break;
1105 }
1106
1107 /* TODO: Check privileges */
1108
1109 /* Check if we have a job */
1110 if (Process->Job)
1111 {
1112 DPRINT1("Jobs not yet supported\n");
1113 }
1114
1115 /* Set process priority class */
1116 Process->PriorityClass = PriorityClass.PriorityClass;
1117
1118 /* Set process priority mode (foreground or background) */
1119 PsSetProcessPriorityByClass(Process,
1120 !PriorityClass.Foreground ? PsProcessPriorityBackground :
1121 PsProcessPriorityForeground);
1122
1123 Status = STATUS_SUCCESS;
1124 break;
1125
1126 case ProcessQuotaLimits:
1127
1128 /* Check buffer length */
1129 if (ProcessInformationLength != sizeof(QUOTA_LIMITS))
1130 {
1131 Status = STATUS_INFO_LENGTH_MISMATCH;
1132 break;
1133 }
1134
1135 DPRINT1("Not implemented: ProcessQuotaLimits\n");
1136 Status = STATUS_NOT_IMPLEMENTED;
1137 break;
1138
1139 case ProcessBasePriority:
1140
1141 /* Check buffer length */
1142 if (ProcessInformationLength != sizeof(KPRIORITY))
1143 {
1144 Status = STATUS_INFO_LENGTH_MISMATCH;
1145 break;
1146 }
1147
1148 DPRINT1("Not implemented: ProcessBasePriority\n");
1149 Status = STATUS_NOT_IMPLEMENTED;
1150 break;
1151
1152 case ProcessRaisePriority:
1153
1154 /* Check buffer length */
1155 if (ProcessInformationLength != sizeof(ULONG))
1156 {
1157 Status = STATUS_INFO_LENGTH_MISMATCH;
1158 break;
1159 }
1160
1161 DPRINT1("Not implemented: ProcessRaisePriority\n");
1162 Status = STATUS_NOT_IMPLEMENTED;
1163 break;
1164
1165 case ProcessWx86Information:
1166
1167 /* Check buffer length */
1168 if (ProcessInformationLength != sizeof(HANDLE))
1169 {
1170 Status = STATUS_INFO_LENGTH_MISMATCH;
1171 break;
1172 }
1173
1174 DPRINT1("Not implemented: ProcessWx86Information\n");
1175 Status = STATUS_NOT_IMPLEMENTED;
1176 break;
1177
1178 case ProcessDebugPort:
1179
1180 /* Check buffer length */
1181 if (ProcessInformationLength != sizeof(HANDLE))
1182 {
1183 Status = STATUS_INFO_LENGTH_MISMATCH;
1184 break;
1185 }
1186
1187 DPRINT1("Not implemented: ProcessDebugPort\n");
1188 Status = STATUS_NOT_IMPLEMENTED;
1189 break;
1190
1191 case ProcessBreakOnTermination:
1192
1193 /* Check buffer length */
1194 if (ProcessInformationLength != sizeof(ULONG))
1195 {
1196 Status = STATUS_INFO_LENGTH_MISMATCH;
1197 break;
1198 }
1199
1200 /* Enter SEH for direct buffer read */
1201 _SEH2_TRY
1202 {
1203 Break = *(PULONG)ProcessInformation;
1204 }
1205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1206 {
1207 /* Get exception code */
1208 Break = 0;
1209 Status = _SEH2_GetExceptionCode();
1210 _SEH2_YIELD(break);
1211 }
1212 _SEH2_END;
1213
1214 /* Setting 'break on termination' requires the SeDebugPrivilege */
1215 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1216 {
1217 Status = STATUS_PRIVILEGE_NOT_HELD;
1218 break;
1219 }
1220
1221 /* Set or clear the flag */
1222 if (Break)
1223 {
1224 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1225 }
1226 else
1227 {
1228 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1229 }
1230
1231 break;
1232
1233 /* We currently don't implement any of these */
1234 case ProcessLdtInformation:
1235 case ProcessLdtSize:
1236 case ProcessIoPortHandlers:
1237 case ProcessWorkingSetWatch:
1238 case ProcessUserModeIOPL:
1239 case ProcessEnableAlignmentFaultFixup:
1240 case ProcessAffinityMask:
1241 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
1242 Status = STATUS_NOT_IMPLEMENTED;
1243 break;
1244
1245 /* Supposedly these are invalid...!? verify! */
1246 case ProcessBasicInformation:
1247 case ProcessIoCounters:
1248 case ProcessTimes:
1249 case ProcessPooledUsageAndLimits:
1250 case ProcessHandleCount:
1251 case ProcessWow64Information:
1252 default:
1253 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
1254 Status = STATUS_INVALID_INFO_CLASS;
1255 }
1256
1257 /* Dereference and return status */
1258 ObDereferenceObject(Process);
1259 return Status;
1260 }
1261
1262 /*
1263 * @implemented
1264 */
1265 NTSTATUS
1266 NTAPI
1267 NtSetInformationThread(IN HANDLE ThreadHandle,
1268 IN THREADINFOCLASS ThreadInformationClass,
1269 IN PVOID ThreadInformation,
1270 IN ULONG ThreadInformationLength)
1271 {
1272 PETHREAD Thread;
1273 ULONG Access;
1274 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1275 NTSTATUS Status;
1276 HANDLE TokenHandle = NULL;
1277 KPRIORITY Priority = 0;
1278 KAFFINITY Affinity = 0, CombinedAffinity;
1279 PVOID Address = NULL;
1280 PEPROCESS Process;
1281 ULONG DisableBoost = 0;
1282 ULONG IdealProcessor = 0;
1283 PTEB Teb;
1284 ULONG TlsIndex = 0;
1285 PVOID *ExpansionSlots;
1286 PETHREAD ProcThread;
1287 PAGED_CODE();
1288
1289 /* Verify Information Class validity */
1290 #if 0
1291 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1292 PsThreadInfoClass,
1293 RTL_NUMBER_OF(PsThreadInfoClass),
1294 ThreadInformation,
1295 ThreadInformationLength,
1296 PreviousMode);
1297 if (!NT_SUCCESS(Status)) return Status;
1298 #endif
1299
1300 /* Check what class this is */
1301 Access = THREAD_SET_INFORMATION;
1302 if (ThreadInformationClass == ThreadImpersonationToken)
1303 {
1304 /* Setting the impersonation token needs a special mask */
1305 Access = THREAD_SET_THREAD_TOKEN;
1306 }
1307
1308 /* Reference the thread */
1309 Status = ObReferenceObjectByHandle(ThreadHandle,
1310 Access,
1311 PsThreadType,
1312 PreviousMode,
1313 (PVOID*)&Thread,
1314 NULL);
1315 if (!NT_SUCCESS(Status)) return Status;
1316
1317 /* Check what kind of information class this is */
1318 switch (ThreadInformationClass)
1319 {
1320 /* Thread priority */
1321 case ThreadPriority:
1322
1323 /* Check buffer length */
1324 if (ThreadInformationLength != sizeof(KPRIORITY))
1325 {
1326 Status = STATUS_INFO_LENGTH_MISMATCH;
1327 break;
1328 }
1329
1330 /* Use SEH for capture */
1331 _SEH2_TRY
1332 {
1333 /* Get the priority */
1334 Priority = *(PLONG)ThreadInformation;
1335 }
1336 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1337 {
1338 /* Get the exception code */
1339 Status = _SEH2_GetExceptionCode();
1340 _SEH2_YIELD(break);
1341 }
1342 _SEH2_END;
1343
1344 /* Validate it */
1345 if ((Priority > HIGH_PRIORITY) ||
1346 (Priority <= LOW_PRIORITY))
1347 {
1348 /* Fail */
1349 Status = STATUS_INVALID_PARAMETER;
1350 break;
1351 }
1352
1353 /* Set the priority */
1354 KeSetPriorityThread(&Thread->Tcb, Priority);
1355 break;
1356
1357 case ThreadBasePriority:
1358
1359 /* Check buffer length */
1360 if (ThreadInformationLength != sizeof(LONG))
1361 {
1362 Status = STATUS_INFO_LENGTH_MISMATCH;
1363 break;
1364 }
1365
1366 /* Use SEH for capture */
1367 _SEH2_TRY
1368 {
1369 /* Get the priority */
1370 Priority = *(PLONG)ThreadInformation;
1371 }
1372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1373 {
1374 /* Get the exception code */
1375 Status = _SEH2_GetExceptionCode();
1376 _SEH2_YIELD(break);
1377 }
1378 _SEH2_END;
1379
1380 /* Validate it */
1381 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
1382 (Priority < THREAD_BASE_PRIORITY_MIN))
1383 {
1384 /* These ones are OK */
1385 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
1386 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
1387 {
1388 /* Check if the process is real time */
1389 if (PsGetCurrentProcess()->PriorityClass !=
1390 PROCESS_PRIORITY_CLASS_REALTIME)
1391 {
1392 /* It isn't, fail */
1393 Status = STATUS_INVALID_PARAMETER;
1394 break;
1395 }
1396 }
1397 }
1398
1399 /* Set the base priority */
1400 KeSetBasePriorityThread(&Thread->Tcb, Priority);
1401 break;
1402
1403 case ThreadAffinityMask:
1404
1405 /* Check buffer length */
1406 if (ThreadInformationLength != sizeof(ULONG_PTR))
1407 {
1408 Status = STATUS_INFO_LENGTH_MISMATCH;
1409 break;
1410 }
1411
1412 /* Use SEH for capture */
1413 _SEH2_TRY
1414 {
1415 /* Get the priority */
1416 Affinity = *(PULONG_PTR)ThreadInformation;
1417 }
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1419 {
1420 /* Get the exception code */
1421 Status = _SEH2_GetExceptionCode();
1422 }
1423 _SEH2_END;
1424
1425 /* Validate it */
1426 if (!Affinity)
1427 {
1428 /* Fail */
1429 Status = STATUS_INVALID_PARAMETER;
1430 break;
1431 }
1432
1433 /* Get the process */
1434 Process = Thread->ThreadsProcess;
1435
1436 /* Try to acquire rundown */
1437 if (ExAcquireRundownProtection(&Process->RundownProtect))
1438 {
1439 /* Lock it */
1440 KeEnterCriticalRegion();
1441 ExAcquirePushLockShared(&Process->ProcessLock);
1442
1443 /* Combine masks */
1444 CombinedAffinity = Affinity & Process->Pcb.Affinity;
1445 if (CombinedAffinity != Affinity)
1446 {
1447 /* Fail */
1448 Status = STATUS_INVALID_PARAMETER;
1449 }
1450 else
1451 {
1452 /* Set the affinity */
1453 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
1454 }
1455
1456 /* Release the lock and rundown */
1457 ExReleasePushLockShared(&Process->ProcessLock);
1458 KeLeaveCriticalRegion();
1459 ExReleaseRundownProtection(&Process->RundownProtect);
1460 }
1461 else
1462 {
1463 /* Too late */
1464 Status = STATUS_PROCESS_IS_TERMINATING;
1465 }
1466
1467 /* Return status */
1468 break;
1469
1470 case ThreadImpersonationToken:
1471
1472 /* Check buffer length */
1473 if (ThreadInformationLength != sizeof(HANDLE))
1474 {
1475 Status = STATUS_INFO_LENGTH_MISMATCH;
1476 break;
1477 }
1478
1479 /* Use SEH for capture */
1480 _SEH2_TRY
1481 {
1482 /* Save the token handle */
1483 TokenHandle = *(PHANDLE)ThreadInformation;
1484 }
1485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1486 {
1487 /* Get the exception code */
1488 Status = _SEH2_GetExceptionCode();
1489 _SEH2_YIELD(break);
1490 }
1491 _SEH2_END;
1492
1493 /* Assign the actual token */
1494 Status = PsAssignImpersonationToken(Thread, TokenHandle);
1495 break;
1496
1497 case ThreadQuerySetWin32StartAddress:
1498
1499 /* Check buffer length */
1500 if (ThreadInformationLength != sizeof(ULONG_PTR))
1501 {
1502 Status = STATUS_INFO_LENGTH_MISMATCH;
1503 break;
1504 }
1505
1506 /* Use SEH for capture */
1507 _SEH2_TRY
1508 {
1509 /* Get the priority */
1510 Address = *(PVOID*)ThreadInformation;
1511 }
1512 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1513 {
1514 /* Get the exception code */
1515 Status = _SEH2_GetExceptionCode();
1516 _SEH2_YIELD(break);
1517 }
1518 _SEH2_END;
1519
1520 /* Set the address */
1521 Thread->Win32StartAddress = Address;
1522 break;
1523
1524 case ThreadIdealProcessor:
1525
1526 /* Check buffer length */
1527 if (ThreadInformationLength != sizeof(ULONG_PTR))
1528 {
1529 Status = STATUS_INFO_LENGTH_MISMATCH;
1530 break;
1531 }
1532
1533 /* Use SEH for capture */
1534 _SEH2_TRY
1535 {
1536 /* Get the priority */
1537 IdealProcessor = *(PULONG_PTR)ThreadInformation;
1538 }
1539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1540 {
1541 /* Get the exception code */
1542 Status = _SEH2_GetExceptionCode();
1543 _SEH2_YIELD(break);
1544 }
1545 _SEH2_END;
1546
1547 /* Validate it */
1548 if (IdealProcessor > MAXIMUM_PROCESSORS)
1549 {
1550 /* Fail */
1551 Status = STATUS_INVALID_PARAMETER;
1552 break;
1553 }
1554
1555 /* Set the ideal */
1556 Status = KeSetIdealProcessorThread(&Thread->Tcb,
1557 (CCHAR)IdealProcessor);
1558
1559 /* Get the TEB and protect the thread */
1560 Teb = Thread->Tcb.Teb;
1561 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
1562 {
1563 /* Save the ideal processor */
1564 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
1565
1566 /* Release rundown protection */
1567 ExReleaseRundownProtection(&Thread->RundownProtect);
1568 }
1569
1570 break;
1571
1572 case ThreadPriorityBoost:
1573
1574 /* Check buffer length */
1575 if (ThreadInformationLength != sizeof(ULONG_PTR))
1576 {
1577 Status = STATUS_INFO_LENGTH_MISMATCH;
1578 break;
1579 }
1580
1581 /* Use SEH for capture */
1582 _SEH2_TRY
1583 {
1584 /* Get the priority */
1585 DisableBoost = *(PULONG_PTR)ThreadInformation;
1586 }
1587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1588 {
1589 /* Get the exception code */
1590 Status = _SEH2_GetExceptionCode();
1591 _SEH2_YIELD(break);
1592 }
1593 _SEH2_END;
1594
1595 /* Call the kernel */
1596 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
1597 break;
1598
1599 case ThreadZeroTlsCell:
1600
1601 /* Check buffer length */
1602 if (ThreadInformationLength != sizeof(ULONG_PTR))
1603 {
1604 Status = STATUS_INFO_LENGTH_MISMATCH;
1605 break;
1606 }
1607
1608 /* Use SEH for capture */
1609 _SEH2_TRY
1610 {
1611 /* Get the priority */
1612 TlsIndex = *(PULONG_PTR)ThreadInformation;
1613 }
1614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1615 {
1616 /* Get the exception code */
1617 Status = _SEH2_GetExceptionCode();
1618 _SEH2_YIELD(break);
1619 }
1620 _SEH2_END;
1621
1622 /* This is only valid for the current thread */
1623 if (Thread != PsGetCurrentThread())
1624 {
1625 /* Fail */
1626 Status = STATUS_INVALID_PARAMETER;
1627 break;
1628 }
1629
1630 /* Get the process */
1631 Process = Thread->ThreadsProcess;
1632
1633 /* Loop the threads */
1634 ProcThread = PsGetNextProcessThread(Process, NULL);
1635 while (ProcThread)
1636 {
1637 /* Acquire rundown */
1638 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
1639 {
1640 /* Get the TEB */
1641 Teb = ProcThread->Tcb.Teb;
1642 if (Teb)
1643 {
1644 /* Check if we're in the expansion range */
1645 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
1646 {
1647 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
1648 TLS_EXPANSION_SLOTS) - 1)
1649 {
1650 /* Check if we have expansion slots */
1651 ExpansionSlots = Teb->TlsExpansionSlots;
1652 if (ExpansionSlots)
1653 {
1654 /* Clear the index */
1655 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
1656 }
1657 }
1658 }
1659 else
1660 {
1661 /* Clear the index */
1662 Teb->TlsSlots[TlsIndex] = NULL;
1663 }
1664 }
1665
1666 /* Release rundown */
1667 ExReleaseRundownProtection(&ProcThread->RundownProtect);
1668 }
1669
1670 /* Go to the next thread */
1671 ProcThread = PsGetNextProcessThread(Process, ProcThread);
1672 }
1673
1674 /* All done */
1675 break;
1676
1677 default:
1678 /* We don't implement it yet */
1679 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1680 Status = STATUS_NOT_IMPLEMENTED;
1681 }
1682
1683 /* Dereference and return status */
1684 ObDereferenceObject(Thread);
1685 return Status;
1686 }
1687
1688 /*
1689 * @implemented
1690 */
1691 NTSTATUS
1692 NTAPI
1693 NtQueryInformationThread(IN HANDLE ThreadHandle,
1694 IN THREADINFOCLASS ThreadInformationClass,
1695 OUT PVOID ThreadInformation,
1696 IN ULONG ThreadInformationLength,
1697 OUT PULONG ReturnLength OPTIONAL)
1698 {
1699 PETHREAD Thread;
1700 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1701 NTSTATUS Status;
1702 ULONG Access;
1703 ULONG Length = 0;
1704 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
1705 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
1706 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
1707 KIRQL OldIrql;
1708 PAGED_CODE();
1709
1710 /* Check if we were called from user mode */
1711 if (PreviousMode != KernelMode)
1712 {
1713 /* Enter SEH */
1714 _SEH2_TRY
1715 {
1716 /* Probe the buffer */
1717 ProbeForWrite(ThreadInformation,
1718 ThreadInformationLength,
1719 sizeof(ULONG));
1720
1721 /* Probe the return length if required */
1722 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
1723 }
1724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1725 {
1726 /* Return the exception code */
1727 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1728 }
1729 _SEH2_END;
1730 }
1731
1732 /* Check what class this is */
1733 Access = THREAD_QUERY_INFORMATION;
1734
1735 /* Reference the process */
1736 Status = ObReferenceObjectByHandle(ThreadHandle,
1737 Access,
1738 PsThreadType,
1739 PreviousMode,
1740 (PVOID*)&Thread,
1741 NULL);
1742 if (!NT_SUCCESS(Status)) return Status;
1743
1744 /* Check what kind of information class this is */
1745 switch (ThreadInformationClass)
1746 {
1747 /* Basic thread information */
1748 case ThreadBasicInformation:
1749
1750 /* Set return length */
1751 Length = sizeof(THREAD_BASIC_INFORMATION);
1752
1753 if (ThreadInformationLength != Length)
1754 {
1755 Status = STATUS_INFO_LENGTH_MISMATCH;
1756 break;
1757 }
1758 /* Protect writes with SEH */
1759 _SEH2_TRY
1760 {
1761 /* Write all the information from the ETHREAD/KTHREAD */
1762 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
1763 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1764 ThreadBasicInfo->ClientId = Thread->Cid;
1765 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
1766 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
1767 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1768 }
1769 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1770 {
1771 /* Get exception code */
1772 Status = _SEH2_GetExceptionCode();
1773 }
1774 _SEH2_END;
1775 break;
1776
1777 /* Thread time information */
1778 case ThreadTimes:
1779
1780 /* Set the return length */
1781 Length = sizeof(KERNEL_USER_TIMES);
1782
1783 if (ThreadInformationLength != Length)
1784 {
1785 Status = STATUS_INFO_LENGTH_MISMATCH;
1786 break;
1787 }
1788 /* Protect writes with SEH */
1789 _SEH2_TRY
1790 {
1791 /* Copy time information from ETHREAD/KTHREAD */
1792 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
1793 100000LL;
1794 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
1795 100000LL;
1796 ThreadTime->CreateTime = Thread->CreateTime;
1797 ThreadTime->ExitTime = Thread->ExitTime;
1798 }
1799 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1800 {
1801 /* Get exception code */
1802 Status = _SEH2_GetExceptionCode();
1803 }
1804 _SEH2_END;
1805 break;
1806
1807 case ThreadQuerySetWin32StartAddress:
1808
1809 /* Set the return length*/
1810 Length = sizeof(PVOID);
1811
1812 if (ThreadInformationLength != Length)
1813 {
1814 Status = STATUS_INFO_LENGTH_MISMATCH;
1815 break;
1816 }
1817 /* Protect write with SEH */
1818 _SEH2_TRY
1819 {
1820 /* Return the Win32 Start Address */
1821 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
1822 }
1823 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1824 {
1825 /* Get exception code */
1826 Status = _SEH2_GetExceptionCode();
1827 }
1828 _SEH2_END;
1829 break;
1830
1831 case ThreadPerformanceCount:
1832
1833 /* Set the return length*/
1834 Length = sizeof(LARGE_INTEGER);
1835
1836 if (ThreadInformationLength != Length)
1837 {
1838 Status = STATUS_INFO_LENGTH_MISMATCH;
1839 break;
1840 }
1841 /* Protect write with SEH */
1842 _SEH2_TRY
1843 {
1844 /* FIXME */
1845 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
1846 }
1847 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1848 {
1849 /* Get exception code */
1850 Status = _SEH2_GetExceptionCode();
1851 }
1852 _SEH2_END;
1853 break;
1854
1855 case ThreadAmILastThread:
1856
1857 /* Set the return length*/
1858 Length = sizeof(ULONG);
1859
1860 if (ThreadInformationLength != Length)
1861 {
1862 Status = STATUS_INFO_LENGTH_MISMATCH;
1863 break;
1864 }
1865 /* Protect write with SEH */
1866 _SEH2_TRY
1867 {
1868 /* Return whether or not we are the last thread */
1869 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1870 ThreadListHead.Flink->Flink ==
1871 &Thread->ThreadsProcess->
1872 ThreadListHead) ?
1873 TRUE : FALSE);
1874 }
1875 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1876 {
1877 /* Get exception code */
1878 Status = _SEH2_GetExceptionCode();
1879 }
1880 _SEH2_END;
1881 break;
1882
1883 case ThreadIsIoPending:
1884
1885 /* Set the return length*/
1886 Length = sizeof(ULONG);
1887
1888 if (ThreadInformationLength != Length)
1889 {
1890 Status = STATUS_INFO_LENGTH_MISMATCH;
1891 break;
1892 }
1893 /* Raise the IRQL to protect the IRP list */
1894 KeRaiseIrql(APC_LEVEL, &OldIrql);
1895
1896 /* Protect write with SEH */
1897 _SEH2_TRY
1898 {
1899 /* Check if the IRP list is empty or not */
1900 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1901 }
1902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1903 {
1904 /* Get exception code */
1905 Status = _SEH2_GetExceptionCode();
1906 }
1907 _SEH2_END;
1908
1909 /* Lower IRQL back */
1910 KeLowerIrql(OldIrql);
1911 break;
1912
1913 /* LDT and GDT information */
1914 case ThreadDescriptorTableEntry:
1915
1916 #if defined(_X86_)
1917 /* Call the worker routine */
1918 Status = PspQueryDescriptorThread(Thread,
1919 ThreadInformation,
1920 ThreadInformationLength,
1921 ReturnLength);
1922 #else
1923 /* Only implemented on x86 */
1924 Status = STATUS_NOT_IMPLEMENTED;
1925 #endif
1926 break;
1927
1928 case ThreadPriorityBoost:
1929
1930 /* Set the return length*/
1931 Length = sizeof(ULONG);
1932
1933 if (ThreadInformationLength != Length)
1934 {
1935 Status = STATUS_INFO_LENGTH_MISMATCH;
1936 break;
1937 }
1938
1939 _SEH2_TRY
1940 {
1941 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
1942 }
1943 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1944 {
1945 Status = _SEH2_GetExceptionCode();
1946 }
1947 _SEH2_END;
1948 break;
1949
1950 /* Anything else */
1951 default:
1952
1953 /* Not yet implemented */
1954 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1955 Status = STATUS_NOT_IMPLEMENTED;
1956 }
1957
1958 /* Protect write with SEH */
1959 _SEH2_TRY
1960 {
1961 /* Check if caller wanted return length */
1962 if (ReturnLength) *ReturnLength = Length;
1963 }
1964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1965 {
1966 /* Get exception code */
1967 Status = _SEH2_GetExceptionCode();
1968 }
1969 _SEH2_END;
1970
1971 /* Dereference the thread, and return */
1972 ObDereferenceObject(Thread);
1973 return Status;
1974 }
1975
1976 /* EOF */