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