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