Testers: Please pay attention to this build and test it fully:
[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 /* Return the exception code */
929 _SEH2_YIELD(return _SEH2_GetExceptionCode());
930 }
931 _SEH2_END;
932
933 /* Get the LPC Port */
934 Status = ObReferenceObjectByHandle(PortHandle,
935 0,
936 LpcPortObjectType,
937 PreviousMode,
938 (PVOID)&ExceptionPort,
939 NULL);
940 if (!NT_SUCCESS(Status)) break;
941
942 /* Change the pointer */
943 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
944 ExceptionPort,
945 NULL))
946 {
947 /* We already had one, fail */
948 ObDereferenceObject(ExceptionPort);
949 Status = STATUS_PORT_ALREADY_SET;
950 }
951 break;
952
953 /* Security Token */
954 case ProcessAccessToken:
955
956 /* Check buffer length */
957 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
958 {
959 Status = STATUS_INFO_LENGTH_MISMATCH;
960 break;
961 }
962
963 /* Use SEH for capture */
964 _SEH2_TRY
965 {
966 /* Save the token handle */
967 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
968 Token;
969 }
970 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
971 {
972 /* Return the exception code */
973 _SEH2_YIELD(return _SEH2_GetExceptionCode());
974 }
975 _SEH2_END;
976
977 /* Assign the actual token */
978 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
979 break;
980
981 /* Hard error processing */
982 case ProcessDefaultHardErrorMode:
983
984 /* Check buffer length */
985 if (ProcessInformationLength != sizeof(ULONG))
986 {
987 Status = STATUS_INFO_LENGTH_MISMATCH;
988 break;
989 }
990
991 /* Enter SEH for direct buffer read */
992 _SEH2_TRY
993 {
994 /* Update the current mode abd return the previous one */
995 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
996 *(PLONG)ProcessInformation);
997 }
998 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
999 {
1000 /* Get exception code */
1001 Status = _SEH2_GetExceptionCode();
1002 }
1003 _SEH2_END;
1004 break;
1005
1006 /* Session ID */
1007 case ProcessSessionInformation:
1008
1009 /* Check buffer length */
1010 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
1011 {
1012 Status = STATUS_INFO_LENGTH_MISMATCH;
1013 break;
1014 }
1015
1016 /* Enter SEH for capture */
1017 _SEH2_TRY
1018 {
1019 /* Capture the caller's buffer */
1020 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1021 }
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1023 {
1024 /* Return the exception code */
1025 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1026 }
1027 _SEH2_END;
1028
1029 /* Setting the session id requires the SeTcbPrivilege */
1030 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1031 {
1032 /* Can't set the session ID, bail out. */
1033 Status = STATUS_PRIVILEGE_NOT_HELD;
1034 break;
1035 }
1036
1037 /* FIXME - update the session id for the process token */
1038 //Status = PsLockProcess(Process, FALSE);
1039 if (!NT_SUCCESS(Status)) break;
1040
1041 /* Write the session ID in the EPROCESS */
1042 Process->Session = SessionInfo.SessionId;
1043
1044 /* Check if the process also has a PEB */
1045 if (Process->Peb)
1046 {
1047 /*
1048 * Attach to the process to make sure we're in the right
1049 * context to access the PEB structure
1050 */
1051 KeAttachProcess(&Process->Pcb);
1052
1053 /* Enter SEH for write to user-mode PEB */
1054 _SEH2_TRY
1055 {
1056 /* Write the session ID */
1057 Process->Peb->SessionId = SessionInfo.SessionId;
1058 }
1059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1060 {
1061 /* Get exception code */
1062 Status = _SEH2_GetExceptionCode();
1063 }
1064 _SEH2_END;
1065
1066 /* Detach from the process */
1067 KeDetachProcess();
1068 }
1069
1070 /* Unlock the process */
1071 //PsUnlockProcess(Process);
1072 break;
1073
1074 case ProcessPriorityClass:
1075
1076 /* Check buffer length */
1077 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1078 {
1079 Status = STATUS_INFO_LENGTH_MISMATCH;
1080 break;
1081 }
1082
1083 /* Enter SEH for capture */
1084 _SEH2_TRY
1085 {
1086 /* Capture the caller's buffer */
1087 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1088 }
1089 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1090 {
1091 /* Return the exception code */
1092 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1093 }
1094 _SEH2_END;
1095
1096 /* Check for invalid PriorityClass value */
1097 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1098 {
1099 Status = STATUS_INVALID_PARAMETER;
1100 break;
1101 }
1102
1103 /* TODO: Check privileges */
1104
1105 /* Check if we have a job */
1106 if (Process->Job)
1107 {
1108 DPRINT1("Jobs not yet supported\n");
1109 }
1110
1111 /* Set process priority class */
1112 Process->PriorityClass = PriorityClass.PriorityClass;
1113
1114 /* Set process priority mode (foreground or background) */
1115 PsSetProcessPriorityByClass(Process,
1116 !PriorityClass.Foreground ? PsProcessPriorityBackground :
1117 PsProcessPriorityForeground);
1118
1119 Status = STATUS_SUCCESS;
1120 break;
1121
1122 case ProcessQuotaLimits:
1123
1124 /* Check buffer length */
1125 if (ProcessInformationLength != sizeof(QUOTA_LIMITS))
1126 {
1127 Status = STATUS_INFO_LENGTH_MISMATCH;
1128 break;
1129 }
1130
1131 DPRINT1("Not implemented: ProcessQuotaLimits\n");
1132 Status = STATUS_NOT_IMPLEMENTED;
1133 break;
1134
1135 case ProcessBasePriority:
1136
1137 /* Check buffer length */
1138 if (ProcessInformationLength != sizeof(KPRIORITY))
1139 {
1140 Status = STATUS_INFO_LENGTH_MISMATCH;
1141 break;
1142 }
1143
1144 DPRINT1("Not implemented: ProcessBasePriority\n");
1145 Status = STATUS_NOT_IMPLEMENTED;
1146 break;
1147
1148 case ProcessRaisePriority:
1149
1150 /* Check buffer length */
1151 if (ProcessInformationLength != sizeof(ULONG))
1152 {
1153 Status = STATUS_INFO_LENGTH_MISMATCH;
1154 break;
1155 }
1156
1157 DPRINT1("Not implemented: ProcessRaisePriority\n");
1158 Status = STATUS_NOT_IMPLEMENTED;
1159 break;
1160
1161 case ProcessWx86Information:
1162
1163 /* Check buffer length */
1164 if (ProcessInformationLength != sizeof(HANDLE))
1165 {
1166 Status = STATUS_INFO_LENGTH_MISMATCH;
1167 break;
1168 }
1169
1170 DPRINT1("Not implemented: ProcessWx86Information\n");
1171 Status = STATUS_NOT_IMPLEMENTED;
1172 break;
1173
1174 case ProcessDebugPort:
1175
1176 /* Check buffer length */
1177 if (ProcessInformationLength != sizeof(HANDLE))
1178 {
1179 Status = STATUS_INFO_LENGTH_MISMATCH;
1180 break;
1181 }
1182
1183 DPRINT1("Not implemented: ProcessDebugPort\n");
1184 Status = STATUS_NOT_IMPLEMENTED;
1185 break;
1186
1187 case ProcessBreakOnTermination:
1188
1189 /* Check buffer length */
1190 if (ProcessInformationLength != sizeof(ULONG))
1191 {
1192 Status = STATUS_INFO_LENGTH_MISMATCH;
1193 break;
1194 }
1195
1196 /* Setting 'break on termination' requires the SeDebugPrivilege */
1197 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1198 {
1199 Status = STATUS_PRIVILEGE_NOT_HELD;
1200 break;
1201 }
1202
1203 /* Enter SEH for direct buffer read */
1204 _SEH2_TRY
1205 {
1206 Process->BreakOnTermination = *(PULONG)ProcessInformation;
1207 }
1208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1209 {
1210 /* Get exception code */
1211 Status = _SEH2_GetExceptionCode();
1212 }
1213 _SEH2_END;
1214 break;
1215
1216 /* We currently don't implement any of these */
1217 case ProcessLdtInformation:
1218 case ProcessLdtSize:
1219 case ProcessIoPortHandlers:
1220 case ProcessWorkingSetWatch:
1221 case ProcessUserModeIOPL:
1222 case ProcessEnableAlignmentFaultFixup:
1223 case ProcessAffinityMask:
1224 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
1225 Status = STATUS_NOT_IMPLEMENTED;
1226 break;
1227
1228 /* Supposedly these are invalid...!? verify! */
1229 case ProcessBasicInformation:
1230 case ProcessIoCounters:
1231 case ProcessTimes:
1232 case ProcessPooledUsageAndLimits:
1233 case ProcessHandleCount:
1234 case ProcessWow64Information:
1235 default:
1236 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
1237 Status = STATUS_INVALID_INFO_CLASS;
1238 }
1239
1240 /* Dereference and return status */
1241 ObDereferenceObject(Process);
1242 return Status;
1243 }
1244
1245 /*
1246 * @implemented
1247 */
1248 NTSTATUS
1249 NTAPI
1250 NtSetInformationThread(IN HANDLE ThreadHandle,
1251 IN THREADINFOCLASS ThreadInformationClass,
1252 IN PVOID ThreadInformation,
1253 IN ULONG ThreadInformationLength)
1254 {
1255 PETHREAD Thread;
1256 ULONG Access;
1257 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1258 NTSTATUS Status;
1259 HANDLE TokenHandle = NULL;
1260 KPRIORITY Priority = 0;
1261 KAFFINITY Affinity = 0, CombinedAffinity;
1262 PVOID Address = NULL;
1263 PEPROCESS Process;
1264 ULONG DisableBoost = 0;
1265 ULONG IdealProcessor = 0;
1266 PTEB Teb;
1267 ULONG TlsIndex = 0;
1268 PVOID *ExpansionSlots;
1269 PETHREAD ProcThread;
1270 PAGED_CODE();
1271
1272 /* Verify Information Class validity */
1273 #if 0
1274 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1275 PsThreadInfoClass,
1276 RTL_NUMBER_OF(PsThreadInfoClass),
1277 ThreadInformation,
1278 ThreadInformationLength,
1279 PreviousMode);
1280 if (!NT_SUCCESS(Status)) return Status;
1281 #endif
1282
1283 /* Check what class this is */
1284 Access = THREAD_SET_INFORMATION;
1285 if (ThreadInformationClass == ThreadImpersonationToken)
1286 {
1287 /* Setting the impersonation token needs a special mask */
1288 Access = THREAD_SET_THREAD_TOKEN;
1289 }
1290
1291 /* Reference the process */
1292 Status = ObReferenceObjectByHandle(ThreadHandle,
1293 Access,
1294 PsThreadType,
1295 PreviousMode,
1296 (PVOID*)&Thread,
1297 NULL);
1298 if (!NT_SUCCESS(Status)) return Status;
1299
1300 /* Check what kind of information class this is */
1301 switch (ThreadInformationClass)
1302 {
1303 /* Thread priority */
1304 case ThreadPriority:
1305
1306 /* Check buffer length */
1307 if (ThreadInformationLength != sizeof(KPRIORITY))
1308 {
1309 Status = STATUS_INFO_LENGTH_MISMATCH;
1310 break;
1311 }
1312
1313 /* Use SEH for capture */
1314 _SEH2_TRY
1315 {
1316 /* Get the priority */
1317 Priority = *(PLONG)ThreadInformation;
1318 }
1319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1320 {
1321 /* Return the exception code */
1322 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1323 }
1324 _SEH2_END;
1325
1326 /* Validate it */
1327 if ((Priority > HIGH_PRIORITY) ||
1328 (Priority <= LOW_PRIORITY))
1329 {
1330 /* Fail */
1331 Status = STATUS_INVALID_PARAMETER;
1332 break;
1333 }
1334
1335 /* Set the priority */
1336 KeSetPriorityThread(&Thread->Tcb, Priority);
1337 break;
1338
1339 case ThreadBasePriority:
1340
1341 /* Check buffer length */
1342 if (ThreadInformationLength != sizeof(LONG))
1343 {
1344 Status = STATUS_INFO_LENGTH_MISMATCH;
1345 break;
1346 }
1347
1348 /* Use SEH for capture */
1349 _SEH2_TRY
1350 {
1351 /* Get the priority */
1352 Priority = *(PLONG)ThreadInformation;
1353 }
1354 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1355 {
1356 /* Return the exception code */
1357 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1358 }
1359 _SEH2_END;
1360
1361 /* Validate it */
1362 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
1363 (Priority < THREAD_BASE_PRIORITY_MIN))
1364 {
1365 /* These ones are OK */
1366 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
1367 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
1368 {
1369 /* Check if the process is real time */
1370 if (PsGetCurrentProcess()->PriorityClass !=
1371 PROCESS_PRIORITY_CLASS_REALTIME)
1372 {
1373 /* It isn't, fail */
1374 Status = STATUS_INVALID_PARAMETER;
1375 break;
1376 }
1377 }
1378 }
1379
1380 /* Set the base priority */
1381 KeSetBasePriorityThread(&Thread->Tcb, Priority);
1382 break;
1383
1384 case ThreadAffinityMask:
1385
1386 /* Check buffer length */
1387 if (ThreadInformationLength != sizeof(ULONG_PTR))
1388 {
1389 Status = STATUS_INFO_LENGTH_MISMATCH;
1390 break;
1391 }
1392
1393 /* Use SEH for capture */
1394 _SEH2_TRY
1395 {
1396 /* Get the priority */
1397 Affinity = *(PULONG_PTR)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 /* Validate it */
1407 if (!Affinity)
1408 {
1409 /* Fail */
1410 Status = STATUS_INVALID_PARAMETER;
1411 break;
1412 }
1413
1414 /* Get the process */
1415 Process = Thread->ThreadsProcess;
1416
1417 /* Try to acquire rundown */
1418 if (ExAcquireRundownProtection(&Process->RundownProtect))
1419 {
1420 /* Lock it */
1421 KeEnterCriticalRegion();
1422 ExAcquirePushLockShared(&Process->ProcessLock);
1423
1424 /* Combine masks */
1425 CombinedAffinity = Affinity & Process->Pcb.Affinity;
1426 if (CombinedAffinity != Affinity)
1427 {
1428 /* Fail */
1429 Status = STATUS_INVALID_PARAMETER;
1430 }
1431 else
1432 {
1433 /* Set the affinity */
1434 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
1435 }
1436
1437 /* Release the lock and rundown */
1438 ExReleasePushLockShared(&Process->ProcessLock);
1439 KeLeaveCriticalRegion();
1440 ExReleaseRundownProtection(&Process->RundownProtect);
1441 }
1442 else
1443 {
1444 /* Too late */
1445 Status = STATUS_PROCESS_IS_TERMINATING;
1446 }
1447
1448 /* Return status */
1449 break;
1450
1451 case ThreadImpersonationToken:
1452
1453 /* Check buffer length */
1454 if (ThreadInformationLength != sizeof(HANDLE))
1455 {
1456 Status = STATUS_INFO_LENGTH_MISMATCH;
1457 break;
1458 }
1459
1460 /* Use SEH for capture */
1461 _SEH2_TRY
1462 {
1463 /* Save the token handle */
1464 TokenHandle = *(PHANDLE)ThreadInformation;
1465 }
1466 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1467 {
1468 /* Return the exception code */
1469 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1470 }
1471 _SEH2_END;
1472
1473 /* Assign the actual token */
1474 Status = PsAssignImpersonationToken(Thread, TokenHandle);
1475 break;
1476
1477 case ThreadQuerySetWin32StartAddress:
1478
1479 /* Check buffer length */
1480 if (ThreadInformationLength != sizeof(ULONG_PTR))
1481 {
1482 Status = STATUS_INFO_LENGTH_MISMATCH;
1483 break;
1484 }
1485
1486 /* Use SEH for capture */
1487 _SEH2_TRY
1488 {
1489 /* Get the priority */
1490 Address = *(PVOID*)ThreadInformation;
1491 }
1492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1493 {
1494 /* Return the exception code */
1495 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1496 }
1497 _SEH2_END;
1498
1499 /* Set the address */
1500 Thread->Win32StartAddress = Address;
1501 break;
1502
1503 case ThreadIdealProcessor:
1504
1505 /* Check buffer length */
1506 if (ThreadInformationLength != sizeof(ULONG_PTR))
1507 {
1508 Status = STATUS_INFO_LENGTH_MISMATCH;
1509 break;
1510 }
1511
1512 /* Use SEH for capture */
1513 _SEH2_TRY
1514 {
1515 /* Get the priority */
1516 IdealProcessor = *(PULONG_PTR)ThreadInformation;
1517 }
1518 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1519 {
1520 /* Return the exception code */
1521 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1522 }
1523 _SEH2_END;
1524
1525 /* Validate it */
1526 if (IdealProcessor > MAXIMUM_PROCESSORS)
1527 {
1528 /* Fail */
1529 Status = STATUS_INVALID_PARAMETER;
1530 break;
1531 }
1532
1533 /* Set the ideal */
1534 Status = KeSetIdealProcessorThread(&Thread->Tcb,
1535 (CCHAR)IdealProcessor);
1536
1537 /* Get the TEB and protect the thread */
1538 Teb = Thread->Tcb.Teb;
1539 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
1540 {
1541 /* Save the ideal processor */
1542 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
1543
1544 /* Release rundown protection */
1545 ExReleaseRundownProtection(&Thread->RundownProtect);
1546 }
1547
1548 break;
1549
1550 case ThreadPriorityBoost:
1551
1552 /* Check buffer length */
1553 if (ThreadInformationLength != sizeof(ULONG_PTR))
1554 {
1555 Status = STATUS_INFO_LENGTH_MISMATCH;
1556 break;
1557 }
1558
1559 /* Use SEH for capture */
1560 _SEH2_TRY
1561 {
1562 /* Get the priority */
1563 DisableBoost = *(PULONG_PTR)ThreadInformation;
1564 }
1565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1566 {
1567 /* Return the exception code */
1568 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1569 }
1570 _SEH2_END;
1571
1572 /* Call the kernel */
1573 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
1574 break;
1575
1576 case ThreadZeroTlsCell:
1577
1578 /* Check buffer length */
1579 if (ThreadInformationLength != sizeof(ULONG_PTR))
1580 {
1581 Status = STATUS_INFO_LENGTH_MISMATCH;
1582 break;
1583 }
1584
1585 /* Use SEH for capture */
1586 _SEH2_TRY
1587 {
1588 /* Get the priority */
1589 TlsIndex = *(PULONG_PTR)ThreadInformation;
1590 }
1591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1592 {
1593 /* Return the exception code */
1594 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1595 }
1596 _SEH2_END;
1597
1598 /* This is only valid for the current thread */
1599 if (Thread != PsGetCurrentThread())
1600 {
1601 /* Fail */
1602 Status = STATUS_INVALID_PARAMETER;
1603 break;
1604 }
1605
1606 /* Get the process */
1607 Process = Thread->ThreadsProcess;
1608
1609 /* Loop the threads */
1610 ProcThread = PsGetNextProcessThread(Process, NULL);
1611 while (ProcThread)
1612 {
1613 /* Acquire rundown */
1614 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
1615 {
1616 /* Get the TEB */
1617 Teb = ProcThread->Tcb.Teb;
1618 if (Teb)
1619 {
1620 /* Check if we're in the expansion range */
1621 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
1622 {
1623 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
1624 TLS_EXPANSION_SLOTS) - 1)
1625 {
1626 /* Check if we have expansion slots */
1627 ExpansionSlots = Teb->TlsExpansionSlots;
1628 if (ExpansionSlots)
1629 {
1630 /* Clear the index */
1631 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
1632 }
1633 }
1634 }
1635 else
1636 {
1637 /* Clear the index */
1638 Teb->TlsSlots[TlsIndex] = NULL;
1639 }
1640 }
1641
1642 /* Release rundown */
1643 ExReleaseRundownProtection(&ProcThread->RundownProtect);
1644 }
1645
1646 /* Go to the next thread */
1647 ProcThread = PsGetNextProcessThread(Process, ProcThread);
1648 }
1649
1650 /* All done */
1651 break;
1652
1653 default:
1654 /* We don't implement it yet */
1655 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1656 Status = STATUS_NOT_IMPLEMENTED;
1657 }
1658
1659 /* Dereference and return status */
1660 ObDereferenceObject(Thread);
1661 return Status;
1662 }
1663
1664 /*
1665 * @implemented
1666 */
1667 NTSTATUS
1668 NTAPI
1669 NtQueryInformationThread(IN HANDLE ThreadHandle,
1670 IN THREADINFOCLASS ThreadInformationClass,
1671 OUT PVOID ThreadInformation,
1672 IN ULONG ThreadInformationLength,
1673 OUT PULONG ReturnLength OPTIONAL)
1674 {
1675 PETHREAD Thread;
1676 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1677 NTSTATUS Status;
1678 ULONG Access;
1679 ULONG Length = 0;
1680 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
1681 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
1682 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
1683 KIRQL OldIrql;
1684 PAGED_CODE();
1685
1686 /* Check if we were called from user mode */
1687 if (PreviousMode != KernelMode)
1688 {
1689 /* Enter SEH */
1690 _SEH2_TRY
1691 {
1692 /* Probe the buffer */
1693 ProbeForWrite(ThreadInformation,
1694 ThreadInformationLength,
1695 sizeof(ULONG));
1696
1697 /* Probe the return length if required */
1698 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
1699 }
1700 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1701 {
1702 /* Return the exception code */
1703 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1704 }
1705 _SEH2_END;
1706 }
1707
1708 /* Check what class this is */
1709 Access = THREAD_QUERY_INFORMATION;
1710
1711 /* Reference the process */
1712 Status = ObReferenceObjectByHandle(ThreadHandle,
1713 Access,
1714 PsThreadType,
1715 PreviousMode,
1716 (PVOID*)&Thread,
1717 NULL);
1718 if (!NT_SUCCESS(Status)) return Status;
1719
1720 /* Check what kind of information class this is */
1721 switch (ThreadInformationClass)
1722 {
1723 /* Basic thread information */
1724 case ThreadBasicInformation:
1725
1726 /* Set return length */
1727 Length = sizeof(THREAD_BASIC_INFORMATION);
1728
1729 if (ThreadInformationLength != Length)
1730 {
1731 Status = STATUS_INFO_LENGTH_MISMATCH;
1732 break;
1733 }
1734 /* Protect writes with SEH */
1735 _SEH2_TRY
1736 {
1737 /* Write all the information from the ETHREAD/KTHREAD */
1738 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
1739 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1740 ThreadBasicInfo->ClientId = Thread->Cid;
1741 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
1742 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
1743 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1744 }
1745 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1746 {
1747 /* Get exception code */
1748 Status = _SEH2_GetExceptionCode();
1749 }
1750 _SEH2_END;
1751 break;
1752
1753 /* Thread time information */
1754 case ThreadTimes:
1755
1756 /* Set the return length */
1757 Length = sizeof(KERNEL_USER_TIMES);
1758
1759 if (ThreadInformationLength != Length)
1760 {
1761 Status = STATUS_INFO_LENGTH_MISMATCH;
1762 break;
1763 }
1764 /* Protect writes with SEH */
1765 _SEH2_TRY
1766 {
1767 /* Copy time information from ETHREAD/KTHREAD */
1768 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
1769 100000LL;
1770 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
1771 100000LL;
1772 ThreadTime->CreateTime = Thread->CreateTime;
1773 ThreadTime->ExitTime = Thread->ExitTime;
1774 }
1775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1776 {
1777 /* Get exception code */
1778 Status = _SEH2_GetExceptionCode();
1779 }
1780 _SEH2_END;
1781 break;
1782
1783 case ThreadQuerySetWin32StartAddress:
1784
1785 /* Set the return length*/
1786 Length = sizeof(PVOID);
1787
1788 if (ThreadInformationLength != Length)
1789 {
1790 Status = STATUS_INFO_LENGTH_MISMATCH;
1791 break;
1792 }
1793 /* Protect write with SEH */
1794 _SEH2_TRY
1795 {
1796 /* Return the Win32 Start Address */
1797 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
1798 }
1799 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1800 {
1801 /* Get exception code */
1802 Status = _SEH2_GetExceptionCode();
1803 }
1804 _SEH2_END;
1805 break;
1806
1807 case ThreadPerformanceCount:
1808
1809 /* Set the return length*/
1810 Length = sizeof(LARGE_INTEGER);
1811
1812 if (ThreadInformationLength != Length)
1813 {
1814 Status = STATUS_INFO_LENGTH_MISMATCH;
1815 break;
1816 }
1817 /* Protect write with SEH */
1818 _SEH2_TRY
1819 {
1820 /* FIXME */
1821 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
1822 }
1823 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1824 {
1825 /* Get exception code */
1826 Status = _SEH2_GetExceptionCode();
1827 }
1828 _SEH2_END;
1829 break;
1830
1831 case ThreadAmILastThread:
1832
1833 /* Set the return length*/
1834 Length = sizeof(ULONG);
1835
1836 if (ThreadInformationLength != Length)
1837 {
1838 Status = STATUS_INFO_LENGTH_MISMATCH;
1839 break;
1840 }
1841 /* Protect write with SEH */
1842 _SEH2_TRY
1843 {
1844 /* Return whether or not we are the last thread */
1845 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1846 ThreadListHead.Flink->Flink ==
1847 &Thread->ThreadsProcess->
1848 ThreadListHead) ?
1849 TRUE : FALSE);
1850 }
1851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1852 {
1853 /* Get exception code */
1854 Status = _SEH2_GetExceptionCode();
1855 }
1856 _SEH2_END;
1857 break;
1858
1859 case ThreadIsIoPending:
1860
1861 /* Set the return length*/
1862 Length = sizeof(ULONG);
1863
1864 if (ThreadInformationLength != Length)
1865 {
1866 Status = STATUS_INFO_LENGTH_MISMATCH;
1867 break;
1868 }
1869 /* Raise the IRQL to protect the IRP list */
1870 KeRaiseIrql(APC_LEVEL, &OldIrql);
1871
1872 /* Protect write with SEH */
1873 _SEH2_TRY
1874 {
1875 /* Check if the IRP list is empty or not */
1876 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1877 }
1878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1879 {
1880 /* Get exception code */
1881 Status = _SEH2_GetExceptionCode();
1882 }
1883 _SEH2_END;
1884
1885 /* Lower IRQL back */
1886 KeLowerIrql(OldIrql);
1887 break;
1888
1889 /* LDT and GDT information */
1890 case ThreadDescriptorTableEntry:
1891
1892 #if defined(_X86_)
1893 /* Call the worker routine */
1894 Status = PspQueryDescriptorThread(Thread,
1895 ThreadInformation,
1896 ThreadInformationLength,
1897 ReturnLength);
1898 #else
1899 /* Only implemented on x86 */
1900 Status = STATUS_NOT_IMPLEMENTED;
1901 #endif
1902 break;
1903
1904 case ThreadPriorityBoost:
1905
1906 /* Set the return length*/
1907 Length = sizeof(ULONG);
1908
1909 if (ThreadInformationLength != Length)
1910 {
1911 Status = STATUS_INFO_LENGTH_MISMATCH;
1912 break;
1913 }
1914
1915 _SEH2_TRY
1916 {
1917 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
1918 }
1919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1920 {
1921 Status = _SEH2_GetExceptionCode();
1922 }
1923 _SEH2_END;
1924 break;
1925
1926 /* Anything else */
1927 default:
1928
1929 /* Not yet implemented */
1930 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1931 Status = STATUS_NOT_IMPLEMENTED;
1932 }
1933
1934 /* Protect write with SEH */
1935 _SEH2_TRY
1936 {
1937 /* Check if caller wanted return length */
1938 if (ReturnLength) *ReturnLength = Length;
1939 }
1940 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1941 {
1942 /* Get exception code */
1943 Status = _SEH2_GetExceptionCode();
1944 }
1945 _SEH2_END;
1946
1947 /* Dereference the thread, and return */
1948 ObDereferenceObject(Thread);
1949 return Status;
1950 }
1951
1952 /* EOF */