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