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