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