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 /* Debugging Level */
18 ULONG PspTraceLevel = 0;
19
20 /* PRIVATE FUNCTIONS *********************************************************/
21
22 NTSTATUS
23 NTAPI
PsReferenceProcessFilePointer(IN PEPROCESS Process,OUT PFILE_OBJECT * FileObject)24 PsReferenceProcessFilePointer(IN PEPROCESS Process,
25 OUT PFILE_OBJECT *FileObject)
26 {
27 PSECTION Section;
28 PAGED_CODE();
29
30 /* Lock the process */
31 if (!ExAcquireRundownProtection(&Process->RundownProtect))
32 {
33 return STATUS_PROCESS_IS_TERMINATING;
34 }
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
NtQueryInformationProcess(_In_ HANDLE ProcessHandle,_In_ PROCESSINFOCLASS ProcessInformationClass,_Out_ PVOID ProcessInformation,_In_ ULONG ProcessInformationLength,_Out_opt_ PULONG ReturnLength)59 NtQueryInformationProcess(
60 _In_ HANDLE ProcessHandle,
61 _In_ PROCESSINFOCLASS ProcessInformationClass,
62 _Out_ PVOID ProcessInformation,
63 _In_ ULONG ProcessInformationLength,
64 _Out_opt_ PULONG ReturnLength)
65 {
66 PEPROCESS Process;
67 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
68 NTSTATUS Status;
69 ULONG Length = 0;
70
71 PAGED_CODE();
72
73 /* Verify Information Class validity */
74 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
75 PsProcessInfoClass,
76 RTL_NUMBER_OF(PsProcessInfoClass),
77 ICIF_PROBE_READ,
78 ProcessInformation,
79 ProcessInformationLength,
80 ReturnLength,
81 NULL,
82 PreviousMode);
83 if (!NT_SUCCESS(Status))
84 {
85 DPRINT1("NtQueryInformationProcess(): Information verification class failed! (Status -> 0x%lx, ProcessInformationClass -> %lx)\n", Status, ProcessInformationClass);
86 return Status;
87 }
88
89 if (((ProcessInformationClass == ProcessCookie) ||
90 (ProcessInformationClass == ProcessImageInformation)) &&
91 (ProcessHandle != NtCurrentProcess()))
92 {
93 /*
94 * Retrieving the process cookie is only allowed for the calling process
95 * itself! XP only allows NtCurrentProcess() as process handles even if
96 * a real handle actually represents the current process.
97 */
98 return STATUS_INVALID_PARAMETER;
99 }
100
101 /* Check the information class */
102 switch (ProcessInformationClass)
103 {
104 /* Basic process information */
105 case ProcessBasicInformation:
106 {
107 PPROCESS_BASIC_INFORMATION ProcessBasicInfo = (PPROCESS_BASIC_INFORMATION)ProcessInformation;
108
109 if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION))
110 {
111 Status = STATUS_INFO_LENGTH_MISMATCH;
112 break;
113 }
114
115 /* Set return length */
116 Length = sizeof(PROCESS_BASIC_INFORMATION);
117
118 /* Reference the process */
119 Status = ObReferenceObjectByHandle(ProcessHandle,
120 PROCESS_QUERY_INFORMATION,
121 PsProcessType,
122 PreviousMode,
123 (PVOID*)&Process,
124 NULL);
125 if (!NT_SUCCESS(Status)) break;
126
127 /* Protect writes with SEH */
128 _SEH2_TRY
129 {
130 /* Write all the information from the EPROCESS/KPROCESS */
131 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
132 ProcessBasicInfo->PebBaseAddress = Process->Peb;
133 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
134 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
135 UniqueProcessId;
136 ProcessBasicInfo->InheritedFromUniqueProcessId =
137 (ULONG_PTR)Process->InheritedFromUniqueProcessId;
138 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
139
140 }
141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
142 {
143 /* Get exception code */
144 Status = _SEH2_GetExceptionCode();
145 }
146 _SEH2_END;
147
148 /* Dereference the process */
149 ObDereferenceObject(Process);
150 break;
151 }
152
153 /* Process quota limits */
154 case ProcessQuotaLimits:
155 {
156 QUOTA_LIMITS_EX QuotaLimits;
157 BOOLEAN Extended;
158
159 if (ProcessInformationLength != sizeof(QUOTA_LIMITS) &&
160 ProcessInformationLength != sizeof(QUOTA_LIMITS_EX))
161 {
162 Status = STATUS_INFO_LENGTH_MISMATCH;
163 break;
164 }
165
166 /* Set return length */
167 Length = ProcessInformationLength;
168 Extended = (Length == sizeof(QUOTA_LIMITS_EX));
169
170 /* Reference the process */
171 Status = ObReferenceObjectByHandle(ProcessHandle,
172 PROCESS_QUERY_INFORMATION,
173 PsProcessType,
174 PreviousMode,
175 (PVOID*)&Process,
176 NULL);
177 if (!NT_SUCCESS(Status)) break;
178
179 /* Indicate success */
180 Status = STATUS_SUCCESS;
181
182 RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits));
183
184 /* Get max/min working set sizes */
185 QuotaLimits.MaximumWorkingSetSize =
186 Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
187 QuotaLimits.MinimumWorkingSetSize =
188 Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
189
190 /* Get default time limits */
191 QuotaLimits.TimeLimit.QuadPart = -1LL;
192
193 /* Is quota block a default one? */
194 if (Process->QuotaBlock == &PspDefaultQuotaBlock)
195 {
196 /* Get default pools and pagefile limits */
197 QuotaLimits.PagedPoolLimit = (SIZE_T)-1;
198 QuotaLimits.NonPagedPoolLimit = (SIZE_T)-1;
199 QuotaLimits.PagefileLimit = (SIZE_T)-1;
200 }
201 else
202 {
203 /* Get limits from non-default quota block */
204 QuotaLimits.PagedPoolLimit =
205 Process->QuotaBlock->QuotaEntry[PsPagedPool].Limit;
206 QuotaLimits.NonPagedPoolLimit =
207 Process->QuotaBlock->QuotaEntry[PsNonPagedPool].Limit;
208 QuotaLimits.PagefileLimit =
209 Process->QuotaBlock->QuotaEntry[PsPageFile].Limit;
210 }
211
212 /* Get additional information, if needed */
213 if (Extended)
214 {
215 QuotaLimits.Flags |= (Process->Vm.Flags.MaximumWorkingSetHard ?
216 QUOTA_LIMITS_HARDWS_MAX_ENABLE : QUOTA_LIMITS_HARDWS_MAX_DISABLE);
217 QuotaLimits.Flags |= (Process->Vm.Flags.MinimumWorkingSetHard ?
218 QUOTA_LIMITS_HARDWS_MIN_ENABLE : QUOTA_LIMITS_HARDWS_MIN_DISABLE);
219
220 /* FIXME: Get the correct information */
221 //QuotaLimits.WorkingSetLimit = (SIZE_T)-1; // Not used on Win2k3, it is set to 0
222 QuotaLimits.CpuRateLimit.RateData = 0;
223 }
224
225 /* Protect writes with SEH */
226 _SEH2_TRY
227 {
228 RtlCopyMemory(ProcessInformation, &QuotaLimits, Length);
229 }
230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
231 {
232 /* Get exception code */
233 Status = _SEH2_GetExceptionCode();
234 }
235 _SEH2_END;
236
237 /* Dereference the process */
238 ObDereferenceObject(Process);
239 break;
240 }
241
242 case ProcessIoCounters:
243 {
244 PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
245 PROCESS_VALUES ProcessValues;
246
247 if (ProcessInformationLength != sizeof(IO_COUNTERS))
248 {
249 Status = STATUS_INFO_LENGTH_MISMATCH;
250 break;
251 }
252
253 Length = sizeof(IO_COUNTERS);
254
255 /* Reference the process */
256 Status = ObReferenceObjectByHandle(ProcessHandle,
257 PROCESS_QUERY_INFORMATION,
258 PsProcessType,
259 PreviousMode,
260 (PVOID*)&Process,
261 NULL);
262 if (!NT_SUCCESS(Status)) break;
263
264 /* Query IO counters from the process */
265 KeQueryValuesProcess(&Process->Pcb, &ProcessValues);
266
267 _SEH2_TRY
268 {
269 RtlCopyMemory(IoCounters, &ProcessValues.IoInfo, sizeof(IO_COUNTERS));
270 }
271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
272 {
273 /* Ignore exception */
274 }
275 _SEH2_END;
276
277 /* Set status to success in any case */
278 Status = STATUS_SUCCESS;
279
280 /* Dereference the process */
281 ObDereferenceObject(Process);
282 break;
283 }
284
285 /* Timing */
286 case ProcessTimes:
287 {
288 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
289 ULONG UserTime, KernelTime;
290
291 /* Set the return length */
292 if (ProcessInformationLength != sizeof(KERNEL_USER_TIMES))
293 {
294 Status = STATUS_INFO_LENGTH_MISMATCH;
295 break;
296 }
297
298 Length = sizeof(KERNEL_USER_TIMES);
299
300 /* Reference the process */
301 Status = ObReferenceObjectByHandle(ProcessHandle,
302 PROCESS_QUERY_INFORMATION,
303 PsProcessType,
304 PreviousMode,
305 (PVOID*)&Process,
306 NULL);
307 if (!NT_SUCCESS(Status)) break;
308
309 /* Protect writes with SEH */
310 _SEH2_TRY
311 {
312 /* Copy time information from EPROCESS/KPROCESS */
313 KernelTime = KeQueryRuntimeProcess(&Process->Pcb, &UserTime);
314 ProcessTime->CreateTime = Process->CreateTime;
315 ProcessTime->UserTime.QuadPart = (LONGLONG)UserTime * KeMaximumIncrement;
316 ProcessTime->KernelTime.QuadPart = (LONGLONG)KernelTime * KeMaximumIncrement;
317 ProcessTime->ExitTime = Process->ExitTime;
318 }
319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
320 {
321 /* Get exception code */
322 Status = _SEH2_GetExceptionCode();
323 }
324 _SEH2_END;
325
326 /* Dereference the process */
327 ObDereferenceObject(Process);
328 break;
329 }
330
331 /* Process Debug Port */
332 case ProcessDebugPort:
333
334 if (ProcessInformationLength != sizeof(HANDLE))
335 {
336 Status = STATUS_INFO_LENGTH_MISMATCH;
337 break;
338 }
339
340 /* Set return length */
341 Length = sizeof(HANDLE);
342
343 /* Reference the process */
344 Status = ObReferenceObjectByHandle(ProcessHandle,
345 PROCESS_QUERY_INFORMATION,
346 PsProcessType,
347 PreviousMode,
348 (PVOID*)&Process,
349 NULL);
350 if (!NT_SUCCESS(Status)) break;
351
352 /* Protect write with SEH */
353 _SEH2_TRY
354 {
355 /* Return whether or not we have a debug port */
356 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
357 (HANDLE)-1 : NULL);
358 }
359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
360 {
361 /* Get exception code */
362 Status = _SEH2_GetExceptionCode();
363 }
364 _SEH2_END;
365
366 /* Dereference the process */
367 ObDereferenceObject(Process);
368 break;
369
370 case ProcessHandleCount:
371 {
372 ULONG HandleCount;
373
374 if (ProcessInformationLength != sizeof(ULONG))
375 {
376 Status = STATUS_INFO_LENGTH_MISMATCH;
377 break;
378 }
379
380 /* Set the return length*/
381 Length = sizeof(ULONG);
382
383 /* Reference the process */
384 Status = ObReferenceObjectByHandle(ProcessHandle,
385 PROCESS_QUERY_INFORMATION,
386 PsProcessType,
387 PreviousMode,
388 (PVOID*)&Process,
389 NULL);
390 if (!NT_SUCCESS(Status)) break;
391
392 /* Count the number of handles this process has */
393 HandleCount = ObGetProcessHandleCount(Process);
394
395 /* Protect write in SEH */
396 _SEH2_TRY
397 {
398 /* Return the count of handles */
399 *(PULONG)ProcessInformation = HandleCount;
400 }
401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
402 {
403 /* Get the exception code */
404 Status = _SEH2_GetExceptionCode();
405 }
406 _SEH2_END;
407
408 /* Dereference the process */
409 ObDereferenceObject(Process);
410 break;
411 }
412
413 /* Session ID for the process */
414 case ProcessSessionInformation:
415 {
416 PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
417
418 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
419 {
420 Status = STATUS_INFO_LENGTH_MISMATCH;
421 break;
422 }
423
424 /* Set the return length*/
425 Length = sizeof(PROCESS_SESSION_INFORMATION);
426
427 /* Reference the process */
428 Status = ObReferenceObjectByHandle(ProcessHandle,
429 PROCESS_QUERY_INFORMATION,
430 PsProcessType,
431 PreviousMode,
432 (PVOID*)&Process,
433 NULL);
434 if (!NT_SUCCESS(Status)) break;
435
436 /* Enter SEH for write safety */
437 _SEH2_TRY
438 {
439 /* Write back the Session ID */
440 SessionInfo->SessionId = PsGetProcessSessionId(Process);
441 }
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
443 {
444 /* Get the exception code */
445 Status = _SEH2_GetExceptionCode();
446 }
447 _SEH2_END;
448
449 /* Dereference the process */
450 ObDereferenceObject(Process);
451 break;
452 }
453
454 /* Virtual Memory Statistics */
455 case ProcessVmCounters:
456 {
457 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
458
459 /* Validate the input length */
460 if ((ProcessInformationLength != sizeof(VM_COUNTERS)) &&
461 (ProcessInformationLength != sizeof(VM_COUNTERS_EX)))
462 {
463 Status = STATUS_INFO_LENGTH_MISMATCH;
464 break;
465 }
466
467 /* Reference the process */
468 Status = ObReferenceObjectByHandle(ProcessHandle,
469 PROCESS_QUERY_INFORMATION,
470 PsProcessType,
471 PreviousMode,
472 (PVOID*)&Process,
473 NULL);
474 if (!NT_SUCCESS(Status)) break;
475
476 /* Enter SEH for write safety */
477 _SEH2_TRY
478 {
479 /* Return data from EPROCESS */
480 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
481 VmCounters->VirtualSize = Process->VirtualSize;
482 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
483 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
484 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
485 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool];
486 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool];
487 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool];
488 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool];
489 VmCounters->PagefileUsage = Process->QuotaUsage[PsPageFile] << PAGE_SHIFT;
490 VmCounters->PeakPagefileUsage = Process->QuotaPeak[PsPageFile] << PAGE_SHIFT;
491 //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT;
492 //
493
494 /* Set the return length */
495 Length = ProcessInformationLength;
496 }
497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
498 {
499 /* Get the exception code */
500 Status = _SEH2_GetExceptionCode();
501 }
502 _SEH2_END;
503
504 /* Dereference the process */
505 ObDereferenceObject(Process);
506 break;
507 }
508
509 /* Hard Error Processing Mode */
510 case ProcessDefaultHardErrorMode:
511
512 if (ProcessInformationLength != sizeof(ULONG))
513 {
514 Status = STATUS_INFO_LENGTH_MISMATCH;
515 break;
516 }
517
518 /* Set the return length*/
519 Length = sizeof(ULONG);
520
521 /* Reference the process */
522 Status = ObReferenceObjectByHandle(ProcessHandle,
523 PROCESS_QUERY_INFORMATION,
524 PsProcessType,
525 PreviousMode,
526 (PVOID*)&Process,
527 NULL);
528 if (!NT_SUCCESS(Status)) break;
529
530 /* Enter SEH for writing back data */
531 _SEH2_TRY
532 {
533 /* Write the current processing mode */
534 *(PULONG)ProcessInformation = Process->
535 DefaultHardErrorProcessing;
536 }
537 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
538 {
539 /* Get the exception code */
540 Status = _SEH2_GetExceptionCode();
541 }
542 _SEH2_END;
543
544 /* Dereference the process */
545 ObDereferenceObject(Process);
546 break;
547
548 /* Priority Boosting status */
549 case ProcessPriorityBoost:
550
551 if (ProcessInformationLength != sizeof(ULONG))
552 {
553 Status = STATUS_INFO_LENGTH_MISMATCH;
554 break;
555 }
556
557 /* Set the return length */
558 Length = sizeof(ULONG);
559
560 /* Reference the process */
561 Status = ObReferenceObjectByHandle(ProcessHandle,
562 PROCESS_QUERY_INFORMATION,
563 PsProcessType,
564 PreviousMode,
565 (PVOID*)&Process,
566 NULL);
567 if (!NT_SUCCESS(Status)) break;
568
569 /* Enter SEH for writing back data */
570 _SEH2_TRY
571 {
572 /* Return boost status */
573 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
574 TRUE : FALSE;
575 }
576 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
577 {
578 /* Get the exception code */
579 Status = _SEH2_GetExceptionCode();
580 }
581 _SEH2_END;
582
583 /* Dereference the process */
584 ObDereferenceObject(Process);
585 break;
586
587 /* DOS Device Map */
588 case ProcessDeviceMap:
589 {
590 ULONG Flags;
591
592 if (ProcessInformationLength == sizeof(PROCESS_DEVICEMAP_INFORMATION_EX))
593 {
594 /* Protect read in SEH */
595 _SEH2_TRY
596 {
597 PPROCESS_DEVICEMAP_INFORMATION_EX DeviceMapEx = ProcessInformation;
598
599 Flags = DeviceMapEx->Flags;
600 }
601 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
602 {
603 /* Get the exception code */
604 Status = _SEH2_GetExceptionCode();
605 _SEH2_YIELD(break);
606 }
607 _SEH2_END;
608
609 /* Only one flag is supported and it needs LUID mappings */
610 if ((Flags & ~PROCESS_LUID_DOSDEVICES_ONLY) != 0 ||
611 !ObIsLUIDDeviceMapsEnabled())
612 {
613 Status = STATUS_INVALID_PARAMETER;
614 break;
615 }
616 }
617 else
618 {
619 /* This has to be the size of the Query union field for x64 compatibility! */
620 if (ProcessInformationLength != RTL_FIELD_SIZE(PROCESS_DEVICEMAP_INFORMATION, Query))
621 {
622 Status = STATUS_INFO_LENGTH_MISMATCH;
623 break;
624 }
625
626 /* No flags for standard call */
627 Flags = 0;
628 }
629
630 /* Set the return length */
631 Length = ProcessInformationLength;
632
633 /* Reference the process */
634 Status = ObReferenceObjectByHandle(ProcessHandle,
635 PROCESS_QUERY_INFORMATION,
636 PsProcessType,
637 PreviousMode,
638 (PVOID*)&Process,
639 NULL);
640 if (!NT_SUCCESS(Status)) break;
641
642 /* Query the device map information */
643 Status = ObQueryDeviceMapInformation(Process,
644 ProcessInformation,
645 Flags);
646
647 /* Dereference the process */
648 ObDereferenceObject(Process);
649 break;
650 }
651
652 /* Priority class */
653 case ProcessPriorityClass:
654 {
655 PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
656
657 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
658 {
659 Status = STATUS_INFO_LENGTH_MISMATCH;
660 break;
661 }
662
663 /* Set the return length*/
664 Length = sizeof(PROCESS_PRIORITY_CLASS);
665
666 /* Reference the process */
667 Status = ObReferenceObjectByHandle(ProcessHandle,
668 PROCESS_QUERY_INFORMATION,
669 PsProcessType,
670 PreviousMode,
671 (PVOID*)&Process,
672 NULL);
673 if (!NT_SUCCESS(Status)) break;
674
675 /* Enter SEH for writing back data */
676 _SEH2_TRY
677 {
678 /* Return current priority class */
679 PsPriorityClass->PriorityClass = Process->PriorityClass;
680 PsPriorityClass->Foreground = FALSE;
681 }
682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
683 {
684 /* Get the exception code */
685 Status = _SEH2_GetExceptionCode();
686 }
687 _SEH2_END;
688
689 /* Dereference the process */
690 ObDereferenceObject(Process);
691 break;
692 }
693
694 case ProcessImageFileName:
695 {
696 PUNICODE_STRING ImageName;
697
698 /* Reference the process */
699 Status = ObReferenceObjectByHandle(ProcessHandle,
700 PROCESS_QUERY_INFORMATION,
701 PsProcessType,
702 PreviousMode,
703 (PVOID*)&Process,
704 NULL);
705 if (!NT_SUCCESS(Status)) break;
706
707 /* Get the image path */
708 Status = SeLocateProcessImageName(Process, &ImageName);
709 if (NT_SUCCESS(Status))
710 {
711 /* Set return length */
712 Length = ImageName->MaximumLength +
713 sizeof(OBJECT_NAME_INFORMATION);
714
715 /* Make sure it's large enough */
716 if (Length <= ProcessInformationLength)
717 {
718 /* Enter SEH to protect write */
719 _SEH2_TRY
720 {
721 /* Copy it */
722 RtlCopyMemory(ProcessInformation,
723 ImageName,
724 Length);
725
726 /* Update pointer */
727 ((PUNICODE_STRING)ProcessInformation)->Buffer =
728 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
729 }
730 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
731 {
732 /* Get the exception code */
733 Status = _SEH2_GetExceptionCode();
734 }
735 _SEH2_END;
736 }
737 else
738 {
739 /* Buffer too small */
740 Status = STATUS_INFO_LENGTH_MISMATCH;
741 }
742
743 /* Free the image path */
744 ExFreePoolWithTag(ImageName, TAG_SEPA);
745 }
746 /* Dereference the process */
747 ObDereferenceObject(Process);
748 break;
749 }
750
751 case ProcessDebugFlags:
752
753 if (ProcessInformationLength != sizeof(ULONG))
754 {
755 Status = STATUS_INFO_LENGTH_MISMATCH;
756 break;
757 }
758
759 /* Set the return length*/
760 Length = sizeof(ULONG);
761
762 /* Reference the process */
763 Status = ObReferenceObjectByHandle(ProcessHandle,
764 PROCESS_QUERY_INFORMATION,
765 PsProcessType,
766 PreviousMode,
767 (PVOID*)&Process,
768 NULL);
769 if (!NT_SUCCESS(Status)) break;
770
771 /* Enter SEH for writing back data */
772 _SEH2_TRY
773 {
774 /* Return the debug flag state */
775 *(PULONG)ProcessInformation = Process->NoDebugInherit ? 0 : 1;
776 }
777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
778 {
779 /* Get the exception code */
780 Status = _SEH2_GetExceptionCode();
781 }
782 _SEH2_END;
783
784 /* Dereference the process */
785 ObDereferenceObject(Process);
786 break;
787
788 case ProcessBreakOnTermination:
789
790 if (ProcessInformationLength != sizeof(ULONG))
791 {
792 Status = STATUS_INFO_LENGTH_MISMATCH;
793 break;
794 }
795
796 /* Set the return length */
797 Length = sizeof(ULONG);
798
799 /* Reference the process */
800 Status = ObReferenceObjectByHandle(ProcessHandle,
801 PROCESS_QUERY_INFORMATION,
802 PsProcessType,
803 PreviousMode,
804 (PVOID*)&Process,
805 NULL);
806 if (!NT_SUCCESS(Status)) break;
807
808 /* Enter SEH for writing back data */
809 _SEH2_TRY
810 {
811 /* Return the BreakOnTermination state */
812 *(PULONG)ProcessInformation = Process->BreakOnTermination;
813 }
814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
815 {
816 /* Get the exception code */
817 Status = _SEH2_GetExceptionCode();
818 }
819 _SEH2_END;
820
821 /* Dereference the process */
822 ObDereferenceObject(Process);
823 break;
824
825 /* Per-process security cookie */
826 case ProcessCookie:
827 {
828 ULONG Cookie;
829
830 if (ProcessInformationLength != sizeof(ULONG))
831 {
832 /* Length size wrong, bail out */
833 Status = STATUS_INFO_LENGTH_MISMATCH;
834 break;
835 }
836
837 /* Get the current process and cookie */
838 Process = PsGetCurrentProcess();
839 Cookie = Process->Cookie;
840 if (!Cookie)
841 {
842 LARGE_INTEGER SystemTime;
843 ULONG NewCookie;
844 PKPRCB Prcb;
845
846 /* Generate a new cookie */
847 KeQuerySystemTime(&SystemTime);
848 Prcb = KeGetCurrentPrcb();
849 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
850 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
851
852 /* Set the new cookie or return the current one */
853 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
854 NewCookie,
855 Cookie);
856 if (!Cookie) Cookie = NewCookie;
857
858 /* Set return length */
859 Length = sizeof(ULONG);
860 }
861
862 /* Indicate success */
863 Status = STATUS_SUCCESS;
864
865 /* Enter SEH to protect write */
866 _SEH2_TRY
867 {
868 /* Write back the cookie */
869 *(PULONG)ProcessInformation = Cookie;
870 }
871 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
872 {
873 /* Get the exception code */
874 Status = _SEH2_GetExceptionCode();
875 }
876 _SEH2_END;
877 break;
878 }
879
880 case ProcessImageInformation:
881
882 if (ProcessInformationLength != sizeof(SECTION_IMAGE_INFORMATION))
883 {
884 /* Break out */
885 Status = STATUS_INFO_LENGTH_MISMATCH;
886 break;
887 }
888
889 /* Set the length required and validate it */
890 Length = sizeof(SECTION_IMAGE_INFORMATION);
891
892 /* Enter SEH to protect write */
893 _SEH2_TRY
894 {
895 MmGetImageInformation((PSECTION_IMAGE_INFORMATION)ProcessInformation);
896 }
897 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
898 {
899 /* Get the exception code */
900 Status = _SEH2_GetExceptionCode();
901 }
902 _SEH2_END;
903
904 /* Indicate success */
905 Status = STATUS_SUCCESS;
906 break;
907
908 case ProcessDebugObjectHandle:
909 {
910 HANDLE DebugPort = 0;
911
912 if (ProcessInformationLength != sizeof(HANDLE))
913 {
914 Status = STATUS_INFO_LENGTH_MISMATCH;
915 break;
916 }
917
918 /* Set the return length */
919 Length = sizeof(HANDLE);
920
921 /* Reference the process */
922 Status = ObReferenceObjectByHandle(ProcessHandle,
923 PROCESS_QUERY_INFORMATION,
924 PsProcessType,
925 PreviousMode,
926 (PVOID*)&Process,
927 NULL);
928 if (!NT_SUCCESS(Status)) break;
929
930 /* Get the debug port */
931 Status = DbgkOpenProcessDebugPort(Process, PreviousMode, &DebugPort);
932
933 /* Let go of the process */
934 ObDereferenceObject(Process);
935
936 /* Protect write in SEH */
937 _SEH2_TRY
938 {
939 /* Return debug port's handle */
940 *(PHANDLE)ProcessInformation = DebugPort;
941 }
942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
943 {
944 /* Get the exception code */
945 Status = _SEH2_GetExceptionCode();
946 }
947 _SEH2_END;
948 break;
949 }
950
951 case ProcessHandleTracing:
952 DPRINT1("Handle tracing Not implemented: %lx\n", ProcessInformationClass);
953 Status = STATUS_NOT_IMPLEMENTED;
954 break;
955
956 case ProcessLUIDDeviceMapsEnabled:
957
958 if (ProcessInformationLength != sizeof(ULONG))
959 {
960 Status = STATUS_INFO_LENGTH_MISMATCH;
961 break;
962 }
963
964 /* Set the return length */
965 Length = sizeof(ULONG);
966
967 /* Indicate success */
968 Status = STATUS_SUCCESS;
969
970 /* Protect write in SEH */
971 _SEH2_TRY
972 {
973 /* Query Ob */
974 *(PULONG)ProcessInformation = ObIsLUIDDeviceMapsEnabled();
975 }
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
977 {
978 /* Get the exception code */
979 Status = _SEH2_GetExceptionCode();
980 }
981 _SEH2_END;
982 break;
983
984 case ProcessWx86Information:
985
986 if (ProcessInformationLength != sizeof(ULONG))
987 {
988 Status = STATUS_INFO_LENGTH_MISMATCH;
989 break;
990 }
991
992 /* Set the return length */
993 Length = sizeof(ULONG);
994
995 /* Reference the process */
996 Status = ObReferenceObjectByHandle(ProcessHandle,
997 PROCESS_QUERY_INFORMATION,
998 PsProcessType,
999 PreviousMode,
1000 (PVOID*)&Process,
1001 NULL);
1002 if (!NT_SUCCESS(Status)) break;
1003
1004 /* Protect write in SEH */
1005 _SEH2_TRY
1006 {
1007 /* Return if the flag is set */
1008 *(PULONG)ProcessInformation = (ULONG)Process->VdmAllowed;
1009 }
1010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1011 {
1012 /* Get the exception code */
1013 Status = _SEH2_GetExceptionCode();
1014 }
1015 _SEH2_END;
1016
1017 /* Dereference the process */
1018 ObDereferenceObject(Process);
1019 break;
1020
1021 case ProcessWow64Information:
1022 {
1023 ULONG_PTR Wow64 = 0;
1024
1025 if (ProcessInformationLength != sizeof(ULONG_PTR))
1026 {
1027 Status = STATUS_INFO_LENGTH_MISMATCH;
1028 break;
1029 }
1030
1031 /* Set return length */
1032 Length = sizeof(ULONG_PTR);
1033
1034 /* Reference the process */
1035 Status = ObReferenceObjectByHandle(ProcessHandle,
1036 PROCESS_QUERY_INFORMATION,
1037 PsProcessType,
1038 PreviousMode,
1039 (PVOID*)&Process,
1040 NULL);
1041 if (!NT_SUCCESS(Status)) break;
1042
1043 /* Make sure the process isn't dying */
1044 if (ExAcquireRundownProtection(&Process->RundownProtect))
1045 {
1046 /* Get the WOW64 process structure */
1047 #ifdef _WIN64
1048 Wow64 = (ULONG_PTR)Process->Wow64Process;
1049 #else
1050 Wow64 = 0;
1051 #endif
1052 /* Release the lock */
1053 ExReleaseRundownProtection(&Process->RundownProtect);
1054 }
1055
1056 /* Protect write with SEH */
1057 _SEH2_TRY
1058 {
1059 /* Return whether or not we have a debug port */
1060 *(PULONG_PTR)ProcessInformation = Wow64;
1061 }
1062 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1063 {
1064 /* Get exception code */
1065 Status = _SEH2_GetExceptionCode();
1066 }
1067 _SEH2_END;
1068
1069 /* Dereference the process */
1070 ObDereferenceObject(Process);
1071 break;
1072 }
1073
1074 case ProcessExecuteFlags:
1075 {
1076 ULONG ExecuteOptions = 0;
1077
1078 if (ProcessInformationLength != sizeof(ULONG))
1079 {
1080 Status = STATUS_INFO_LENGTH_MISMATCH;
1081 break;
1082 }
1083
1084 /* Set return length */
1085 Length = sizeof(ULONG);
1086
1087 if (ProcessHandle != NtCurrentProcess())
1088 {
1089 return STATUS_INVALID_PARAMETER;
1090 }
1091
1092 /* Get the options */
1093 Status = MmGetExecuteOptions(&ExecuteOptions);
1094 if (NT_SUCCESS(Status))
1095 {
1096 /* Protect write with SEH */
1097 _SEH2_TRY
1098 {
1099 /* Return them */
1100 *(PULONG)ProcessInformation = ExecuteOptions;
1101 }
1102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1103 {
1104 /* Get exception code */
1105 Status = _SEH2_GetExceptionCode();
1106 }
1107 _SEH2_END;
1108 }
1109 break;
1110 }
1111
1112 case ProcessLdtInformation:
1113 DPRINT1("VDM/16-bit not implemented: %lx\n", ProcessInformationClass);
1114 Status = STATUS_NOT_IMPLEMENTED;
1115 break;
1116
1117 case ProcessWorkingSetWatch:
1118 DPRINT1("WS Watch Not implemented: %lx\n", ProcessInformationClass);
1119 Status = STATUS_NOT_IMPLEMENTED;
1120 break;
1121
1122 case ProcessPooledUsageAndLimits:
1123 DPRINT1("Pool limits Not implemented: %lx\n", ProcessInformationClass);
1124 Status = STATUS_NOT_IMPLEMENTED;
1125 break;
1126
1127 /* Not supported by Server 2003 */
1128 default:
1129 DPRINT1("Unsupported info class: %lx\n", ProcessInformationClass);
1130 Status = STATUS_INVALID_INFO_CLASS;
1131 }
1132
1133 /* Protect write with SEH */
1134 _SEH2_TRY
1135 {
1136 /* Check if caller wanted return length */
1137 if ((ReturnLength) && (Length)) *ReturnLength = Length;
1138 }
1139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1140 {
1141 /* Get exception code */
1142 Status = _SEH2_GetExceptionCode();
1143 }
1144 _SEH2_END;
1145
1146 return Status;
1147 }
1148
1149 /*
1150 * @implemented
1151 */
1152 NTSTATUS
1153 NTAPI
NtSetInformationProcess(IN HANDLE ProcessHandle,IN PROCESSINFOCLASS ProcessInformationClass,IN PVOID ProcessInformation,IN ULONG ProcessInformationLength)1154 NtSetInformationProcess(IN HANDLE ProcessHandle,
1155 IN PROCESSINFOCLASS ProcessInformationClass,
1156 IN PVOID ProcessInformation,
1157 IN ULONG ProcessInformationLength)
1158 {
1159 PEPROCESS Process;
1160 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1161 ACCESS_MASK Access;
1162 NTSTATUS Status;
1163 HANDLE PortHandle = NULL;
1164 HANDLE TokenHandle = NULL;
1165 HANDLE DirectoryHandle = NULL;
1166 PROCESS_SESSION_INFORMATION SessionInfo = {0};
1167 PROCESS_PRIORITY_CLASS PriorityClass = {0};
1168 PROCESS_FOREGROUND_BACKGROUND Foreground = {0};
1169 PVOID ExceptionPort;
1170 ULONG Break;
1171 KAFFINITY ValidAffinity, Affinity = 0;
1172 KPRIORITY BasePriority = 0;
1173 UCHAR MemoryPriority = 0;
1174 BOOLEAN DisableBoost = 0;
1175 ULONG DefaultHardErrorMode = 0;
1176 ULONG DebugFlags = 0, EnableFixup = 0, Boost = 0;
1177 ULONG NoExecute = 0, VdmPower = 0;
1178 BOOLEAN HasPrivilege;
1179 PLIST_ENTRY Next;
1180 PETHREAD Thread;
1181 PAGED_CODE();
1182
1183 /* Verify Information Class validity */
1184 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
1185 PsProcessInfoClass,
1186 RTL_NUMBER_OF(PsProcessInfoClass),
1187 ProcessInformation,
1188 ProcessInformationLength,
1189 PreviousMode);
1190 if (!NT_SUCCESS(Status))
1191 {
1192 DPRINT1("NtSetInformationProcess(): Information verification class failed! (Status -> 0x%lx, ProcessInformationClass -> %lx)\n", Status, ProcessInformationClass);
1193 return Status;
1194 }
1195
1196 /* Check what class this is */
1197 Access = PROCESS_SET_INFORMATION;
1198 if (ProcessInformationClass == ProcessSessionInformation)
1199 {
1200 /* Setting the Session ID needs a special mask */
1201 Access |= PROCESS_SET_SESSIONID;
1202 }
1203 else if (ProcessInformationClass == ProcessExceptionPort)
1204 {
1205 /* Setting the exception port needs a special mask */
1206 Access |= PROCESS_SUSPEND_RESUME;
1207 }
1208
1209 /* Reference the process */
1210 Status = ObReferenceObjectByHandle(ProcessHandle,
1211 Access,
1212 PsProcessType,
1213 PreviousMode,
1214 (PVOID*)&Process,
1215 NULL);
1216 if (!NT_SUCCESS(Status)) return Status;
1217
1218 /* Check what kind of information class this is */
1219 switch (ProcessInformationClass)
1220 {
1221 case ProcessWx86Information:
1222
1223 /* Check buffer length */
1224 if (ProcessInformationLength != sizeof(ULONG))
1225 {
1226 Status = STATUS_INFO_LENGTH_MISMATCH;
1227 break;
1228 }
1229
1230 /* Use SEH for capture */
1231 _SEH2_TRY
1232 {
1233 /* Capture the boolean */
1234 VdmPower = *(PULONG)ProcessInformation;
1235 }
1236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1237 {
1238 /* Get the exception code */
1239 Status = _SEH2_GetExceptionCode();
1240 _SEH2_YIELD(break);
1241 }
1242 _SEH2_END;
1243
1244 /* Getting VDM powers requires the SeTcbPrivilege */
1245 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1246 {
1247 /* We don't hold the privilege, bail out */
1248 Status = STATUS_PRIVILEGE_NOT_HELD;
1249 DPRINT1("Need TCB privilege\n");
1250 break;
1251 }
1252
1253 /* Set or clear the flag */
1254 if (VdmPower)
1255 {
1256 PspSetProcessFlag(Process, PSF_VDM_ALLOWED_BIT);
1257 }
1258 else
1259 {
1260 PspClearProcessFlag(Process, PSF_VDM_ALLOWED_BIT);
1261 }
1262 break;
1263
1264 /* Error/Exception Port */
1265 case ProcessExceptionPort:
1266
1267 /* Check buffer length */
1268 if (ProcessInformationLength != sizeof(HANDLE))
1269 {
1270 Status = STATUS_INFO_LENGTH_MISMATCH;
1271 break;
1272 }
1273
1274 /* Use SEH for capture */
1275 _SEH2_TRY
1276 {
1277 /* Capture the handle */
1278 PortHandle = *(PHANDLE)ProcessInformation;
1279 }
1280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1281 {
1282 /* Get the exception code */
1283 Status = _SEH2_GetExceptionCode();
1284 _SEH2_YIELD(break);
1285 }
1286 _SEH2_END;
1287
1288 /* Setting the error port requires the SeTcbPrivilege */
1289 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1290 {
1291 /* We don't hold the privilege, bail out */
1292 Status = STATUS_PRIVILEGE_NOT_HELD;
1293 break;
1294 }
1295
1296 /* Get the LPC Port */
1297 Status = ObReferenceObjectByHandle(PortHandle,
1298 0,
1299 LpcPortObjectType,
1300 PreviousMode,
1301 (PVOID)&ExceptionPort,
1302 NULL);
1303 if (!NT_SUCCESS(Status)) break;
1304
1305 /* Change the pointer */
1306 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
1307 ExceptionPort,
1308 NULL))
1309 {
1310 /* We already had one, fail */
1311 ObDereferenceObject(ExceptionPort);
1312 Status = STATUS_PORT_ALREADY_SET;
1313 }
1314 break;
1315
1316 /* Security Token */
1317 case ProcessAccessToken:
1318
1319 /* Check buffer length */
1320 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
1321 {
1322 Status = STATUS_INFO_LENGTH_MISMATCH;
1323 break;
1324 }
1325
1326 /* Use SEH for capture */
1327 _SEH2_TRY
1328 {
1329 /* Save the token handle */
1330 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
1331 Token;
1332 }
1333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1334 {
1335 /* Get the exception code */
1336 Status = _SEH2_GetExceptionCode();
1337 _SEH2_YIELD(break);
1338 }
1339 _SEH2_END;
1340
1341 /* Assign the actual token */
1342 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
1343 break;
1344
1345 /* Hard error processing */
1346 case ProcessDefaultHardErrorMode:
1347
1348 /* Check buffer length */
1349 if (ProcessInformationLength != sizeof(ULONG))
1350 {
1351 Status = STATUS_INFO_LENGTH_MISMATCH;
1352 break;
1353 }
1354
1355 /* Enter SEH for direct buffer read */
1356 _SEH2_TRY
1357 {
1358 DefaultHardErrorMode = *(PULONG)ProcessInformation;
1359 }
1360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1361 {
1362 /* Get exception code */
1363 Status = _SEH2_GetExceptionCode();
1364 _SEH2_YIELD(break);
1365 }
1366 _SEH2_END;
1367
1368 /* Set the mode */
1369 Process->DefaultHardErrorProcessing = DefaultHardErrorMode;
1370
1371 /* Call Ke for the update */
1372 if (DefaultHardErrorMode & SEM_NOALIGNMENTFAULTEXCEPT)
1373 {
1374 KeSetAutoAlignmentProcess(&Process->Pcb, TRUE);
1375 }
1376 else
1377 {
1378 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE);
1379 }
1380 Status = STATUS_SUCCESS;
1381 break;
1382
1383 /* Session ID */
1384 case ProcessSessionInformation:
1385
1386 /* Check buffer length */
1387 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
1388 {
1389 Status = STATUS_INFO_LENGTH_MISMATCH;
1390 break;
1391 }
1392
1393 /* Enter SEH for capture */
1394 _SEH2_TRY
1395 {
1396 /* Capture the caller's buffer */
1397 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1398 }
1399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1400 {
1401 /* Get the exception code */
1402 Status = _SEH2_GetExceptionCode();
1403 _SEH2_YIELD(break);
1404 }
1405 _SEH2_END;
1406
1407 /* Setting the session id requires the SeTcbPrivilege */
1408 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1409 {
1410 /* We don't hold the privilege, bail out */
1411 Status = STATUS_PRIVILEGE_NOT_HELD;
1412 break;
1413 }
1414
1415 #if 0 // OLD AND DEPRECATED CODE!!!!
1416
1417 /* FIXME - update the session id for the process token */
1418 //Status = PsLockProcess(Process, FALSE);
1419 if (!NT_SUCCESS(Status)) break;
1420
1421 /* Write the session ID in the EPROCESS */
1422 Process->Session = UlongToPtr(SessionInfo.SessionId); // HACK!!!
1423
1424 /* Check if the process also has a PEB */
1425 if (Process->Peb)
1426 {
1427 /*
1428 * Attach to the process to make sure we're in the right
1429 * context to access the PEB structure
1430 */
1431 KeAttachProcess(&Process->Pcb);
1432
1433 /* Enter SEH for write to user-mode PEB */
1434 _SEH2_TRY
1435 {
1436 /* Write the session ID */
1437 Process->Peb->SessionId = SessionInfo.SessionId;
1438 }
1439 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1440 {
1441 /* Get exception code */
1442 Status = _SEH2_GetExceptionCode();
1443 }
1444 _SEH2_END;
1445
1446 /* Detach from the process */
1447 KeDetachProcess();
1448 }
1449
1450 /* Unlock the process */
1451 //PsUnlockProcess(Process);
1452
1453 #endif
1454
1455 /*
1456 * Since we cannot change the session ID of the given
1457 * process anymore because it is set once and for all
1458 * at process creation time and because it is stored
1459 * inside the Process->Session structure managed by MM,
1460 * we fake changing it: we just return success if the
1461 * user-defined value is the same as the session ID of
1462 * the process, and otherwise we fail.
1463 */
1464 if (SessionInfo.SessionId == PsGetProcessSessionId(Process))
1465 {
1466 Status = STATUS_SUCCESS;
1467 }
1468 else
1469 {
1470 Status = STATUS_ACCESS_DENIED;
1471 }
1472
1473 break;
1474
1475 case ProcessPriorityClass:
1476
1477 /* Check buffer length */
1478 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1479 {
1480 Status = STATUS_INFO_LENGTH_MISMATCH;
1481 break;
1482 }
1483
1484 /* Enter SEH for capture */
1485 _SEH2_TRY
1486 {
1487 /* Capture the caller's buffer */
1488 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1489 }
1490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1491 {
1492 /* Return the exception code */
1493 Status = _SEH2_GetExceptionCode();
1494 _SEH2_YIELD(break);
1495 }
1496 _SEH2_END;
1497
1498 /* Check for invalid PriorityClass value */
1499 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1500 {
1501 Status = STATUS_INVALID_PARAMETER;
1502 break;
1503 }
1504
1505 if ((PriorityClass.PriorityClass != Process->PriorityClass) &&
1506 (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME))
1507 {
1508 /* Check the privilege */
1509 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1510 ProcessHandle,
1511 PROCESS_SET_INFORMATION,
1512 PreviousMode);
1513 if (!HasPrivilege)
1514 {
1515 ObDereferenceObject(Process);
1516 DPRINT1("Privilege to change priority to realtime lacking\n");
1517 return STATUS_PRIVILEGE_NOT_HELD;
1518 }
1519 }
1520
1521 /* Check if we have a job */
1522 if (Process->Job)
1523 {
1524 DPRINT1("Jobs not yet supported\n");
1525 }
1526
1527 /* Set process priority class */
1528 Process->PriorityClass = PriorityClass.PriorityClass;
1529
1530 /* Set process priority mode (foreground or background) */
1531 PsSetProcessPriorityByClass(Process,
1532 PriorityClass.Foreground ?
1533 PsProcessPriorityForeground :
1534 PsProcessPriorityBackground);
1535 Status = STATUS_SUCCESS;
1536 break;
1537
1538 case ProcessForegroundInformation:
1539
1540 /* Check buffer length */
1541 if (ProcessInformationLength != sizeof(PROCESS_FOREGROUND_BACKGROUND))
1542 {
1543 Status = STATUS_INFO_LENGTH_MISMATCH;
1544 break;
1545 }
1546
1547 /* Enter SEH for capture */
1548 _SEH2_TRY
1549 {
1550 /* Capture the caller's buffer */
1551 Foreground = *(PPROCESS_FOREGROUND_BACKGROUND)ProcessInformation;
1552 }
1553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1554 {
1555 /* Return the exception code */
1556 Status = _SEH2_GetExceptionCode();
1557 _SEH2_YIELD(break);
1558 }
1559 _SEH2_END;
1560
1561 /* Set process priority mode (foreground or background) */
1562 PsSetProcessPriorityByClass(Process,
1563 Foreground.Foreground ?
1564 PsProcessPriorityForeground :
1565 PsProcessPriorityBackground);
1566 Status = STATUS_SUCCESS;
1567 break;
1568
1569 case ProcessBasePriority:
1570
1571 /* Validate input length */
1572 if (ProcessInformationLength != sizeof(KPRIORITY))
1573 {
1574 Status = STATUS_INFO_LENGTH_MISMATCH;
1575 break;
1576 }
1577
1578 /* Enter SEH for direct buffer read */
1579 _SEH2_TRY
1580 {
1581 BasePriority = *(KPRIORITY*)ProcessInformation;
1582 }
1583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1584 {
1585 /* Get exception code */
1586 Break = 0;
1587 Status = _SEH2_GetExceptionCode();
1588 _SEH2_YIELD(break);
1589 }
1590 _SEH2_END;
1591
1592 /* Extract the memory priority out of there */
1593 if (BasePriority & 0x80000000)
1594 {
1595 MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
1596 BasePriority &= ~0x80000000;
1597 }
1598 else
1599 {
1600 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
1601 }
1602
1603 /* Validate the number */
1604 if ((BasePriority > HIGH_PRIORITY) || (BasePriority <= LOW_PRIORITY))
1605 {
1606 ObDereferenceObject(Process);
1607 return STATUS_INVALID_PARAMETER;
1608 }
1609
1610 /* Check if the new base is higher */
1611 if (BasePriority > Process->Pcb.BasePriority)
1612 {
1613 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1614 ProcessHandle,
1615 PROCESS_SET_INFORMATION,
1616 PreviousMode);
1617 if (!HasPrivilege)
1618 {
1619 ObDereferenceObject(Process);
1620 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority, Process->Pcb.BasePriority);
1621 return STATUS_PRIVILEGE_NOT_HELD;
1622 }
1623 }
1624
1625 /* Call Ke */
1626 KeSetPriorityAndQuantumProcess(&Process->Pcb, BasePriority, 0);
1627
1628 /* Now set the memory priority */
1629 MmSetMemoryPriorityProcess(Process, MemoryPriority);
1630 Status = STATUS_SUCCESS;
1631 break;
1632
1633 case ProcessRaisePriority:
1634
1635 /* Validate input length */
1636 if (ProcessInformationLength != sizeof(ULONG))
1637 {
1638 Status = STATUS_INFO_LENGTH_MISMATCH;
1639 break;
1640 }
1641
1642 /* Enter SEH for direct buffer read */
1643 _SEH2_TRY
1644 {
1645 Boost = *(PULONG)ProcessInformation;
1646 }
1647 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1648 {
1649 /* Get exception code */
1650 Break = 0;
1651 Status = _SEH2_GetExceptionCode();
1652 _SEH2_YIELD(break);
1653 }
1654 _SEH2_END;
1655
1656 /* Make sure the process isn't dying */
1657 if (ExAcquireRundownProtection(&Process->RundownProtect))
1658 {
1659 /* Lock it */
1660 KeEnterCriticalRegion();
1661 ExAcquirePushLockShared(&Process->ProcessLock);
1662
1663 /* Loop the threads */
1664 for (Next = Process->ThreadListHead.Flink;
1665 Next != &Process->ThreadListHead;
1666 Next = Next->Flink)
1667 {
1668 /* Call Ke for the thread */
1669 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1670 KeBoostPriorityThread(&Thread->Tcb, Boost);
1671 }
1672
1673 /* Release the lock and rundown */
1674 ExReleasePushLockShared(&Process->ProcessLock);
1675 KeLeaveCriticalRegion();
1676 ExReleaseRundownProtection(&Process->RundownProtect);
1677
1678 /* Set success code */
1679 Status = STATUS_SUCCESS;
1680 }
1681 else
1682 {
1683 /* Avoid race conditions */
1684 Status = STATUS_PROCESS_IS_TERMINATING;
1685 }
1686 break;
1687
1688 case ProcessBreakOnTermination:
1689
1690 /* Check buffer length */
1691 if (ProcessInformationLength != sizeof(ULONG))
1692 {
1693 Status = STATUS_INFO_LENGTH_MISMATCH;
1694 break;
1695 }
1696
1697 /* Enter SEH for direct buffer read */
1698 _SEH2_TRY
1699 {
1700 Break = *(PULONG)ProcessInformation;
1701 }
1702 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1703 {
1704 /* Get exception code */
1705 Break = 0;
1706 Status = _SEH2_GetExceptionCode();
1707 _SEH2_YIELD(break);
1708 }
1709 _SEH2_END;
1710
1711 /* Setting 'break on termination' requires the SeDebugPrivilege */
1712 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1713 {
1714 /* We don't hold the privilege, bail out */
1715 Status = STATUS_PRIVILEGE_NOT_HELD;
1716 break;
1717 }
1718
1719 /* Set or clear the flag */
1720 if (Break)
1721 {
1722 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1723 }
1724 else
1725 {
1726 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1727 }
1728
1729 break;
1730
1731 case ProcessAffinityMask:
1732
1733 /* Check buffer length */
1734 if (ProcessInformationLength != sizeof(KAFFINITY))
1735 {
1736 Status = STATUS_INFO_LENGTH_MISMATCH;
1737 break;
1738 }
1739
1740 /* Enter SEH for direct buffer read */
1741 _SEH2_TRY
1742 {
1743 Affinity = *(PKAFFINITY)ProcessInformation;
1744 }
1745 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1746 {
1747 /* Get exception code */
1748 Break = 0;
1749 Status = _SEH2_GetExceptionCode();
1750 _SEH2_YIELD(break);
1751 }
1752 _SEH2_END;
1753
1754 /* Make sure it's valid for the CPUs present */
1755 ValidAffinity = Affinity & KeActiveProcessors;
1756 if (!Affinity || (ValidAffinity != Affinity))
1757 {
1758 Status = STATUS_INVALID_PARAMETER;
1759 break;
1760 }
1761
1762 /* Check if it's within job affinity limits */
1763 if (Process->Job)
1764 {
1765 /* Not yet implemented */
1766 UNIMPLEMENTED;
1767 Status = STATUS_NOT_IMPLEMENTED;
1768 break;
1769 }
1770
1771 /* Make sure the process isn't dying */
1772 if (ExAcquireRundownProtection(&Process->RundownProtect))
1773 {
1774 /* Lock it */
1775 KeEnterCriticalRegion();
1776 ExAcquirePushLockShared(&Process->ProcessLock);
1777
1778 /* Call Ke to do the work */
1779 KeSetAffinityProcess(&Process->Pcb, ValidAffinity);
1780
1781 /* Release the lock and rundown */
1782 ExReleasePushLockShared(&Process->ProcessLock);
1783 KeLeaveCriticalRegion();
1784 ExReleaseRundownProtection(&Process->RundownProtect);
1785
1786 /* Set success code */
1787 Status = STATUS_SUCCESS;
1788 }
1789 else
1790 {
1791 /* Avoid race conditions */
1792 Status = STATUS_PROCESS_IS_TERMINATING;
1793 }
1794 break;
1795
1796 /* Priority Boosting status */
1797 case ProcessPriorityBoost:
1798
1799 /* Validate input length */
1800 if (ProcessInformationLength != sizeof(ULONG))
1801 {
1802 Status = STATUS_INFO_LENGTH_MISMATCH;
1803 break;
1804 }
1805
1806 /* Enter SEH for direct buffer read */
1807 _SEH2_TRY
1808 {
1809 DisableBoost = *(PBOOLEAN)ProcessInformation;
1810 }
1811 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1812 {
1813 /* Get exception code */
1814 Break = 0;
1815 Status = _SEH2_GetExceptionCode();
1816 _SEH2_YIELD(break);
1817 }
1818 _SEH2_END;
1819
1820 /* Make sure the process isn't dying */
1821 if (ExAcquireRundownProtection(&Process->RundownProtect))
1822 {
1823 /* Lock it */
1824 KeEnterCriticalRegion();
1825 ExAcquirePushLockShared(&Process->ProcessLock);
1826
1827 /* Call Ke to do the work */
1828 KeSetDisableBoostProcess(&Process->Pcb, DisableBoost);
1829
1830 /* Loop the threads too */
1831 for (Next = Process->ThreadListHead.Flink;
1832 Next != &Process->ThreadListHead;
1833 Next = Next->Flink)
1834 {
1835 /* Call Ke for the thread */
1836 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1837 KeSetDisableBoostThread(&Thread->Tcb, DisableBoost);
1838 }
1839
1840 /* Release the lock and rundown */
1841 ExReleasePushLockShared(&Process->ProcessLock);
1842 KeLeaveCriticalRegion();
1843 ExReleaseRundownProtection(&Process->RundownProtect);
1844
1845 /* Set success code */
1846 Status = STATUS_SUCCESS;
1847 }
1848 else
1849 {
1850 /* Avoid race conditions */
1851 Status = STATUS_PROCESS_IS_TERMINATING;
1852 }
1853 break;
1854
1855 case ProcessDebugFlags:
1856
1857 /* Check buffer length */
1858 if (ProcessInformationLength != sizeof(ULONG))
1859 {
1860 Status = STATUS_INFO_LENGTH_MISMATCH;
1861 break;
1862 }
1863
1864 /* Enter SEH for direct buffer read */
1865 _SEH2_TRY
1866 {
1867 DebugFlags = *(PULONG)ProcessInformation;
1868 }
1869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1870 {
1871 /* Get exception code */
1872 Status = _SEH2_GetExceptionCode();
1873 _SEH2_YIELD(break);
1874 }
1875 _SEH2_END;
1876
1877 /* Set the mode */
1878 if (DebugFlags & ~1)
1879 {
1880 Status = STATUS_INVALID_PARAMETER;
1881 }
1882 else
1883 {
1884 if (DebugFlags & 1)
1885 {
1886 PspClearProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1887 }
1888 else
1889 {
1890 PspSetProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1891 }
1892 }
1893
1894 /* Done */
1895 Status = STATUS_SUCCESS;
1896 break;
1897
1898 case ProcessEnableAlignmentFaultFixup:
1899
1900 /* Check buffer length */
1901 if (ProcessInformationLength != sizeof(BOOLEAN))
1902 {
1903 Status = STATUS_INFO_LENGTH_MISMATCH;
1904 break;
1905 }
1906
1907 /* Enter SEH for direct buffer read */
1908 _SEH2_TRY
1909 {
1910 EnableFixup = *(PULONG)ProcessInformation;
1911 }
1912 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1913 {
1914 /* Get exception code */
1915 Status = _SEH2_GetExceptionCode();
1916 _SEH2_YIELD(break);
1917 }
1918 _SEH2_END;
1919
1920 /* Set the mode */
1921 if (EnableFixup)
1922 {
1923 Process->DefaultHardErrorProcessing |= SEM_NOALIGNMENTFAULTEXCEPT;
1924 }
1925 else
1926 {
1927 Process->DefaultHardErrorProcessing &= ~SEM_NOALIGNMENTFAULTEXCEPT;
1928 }
1929
1930 /* Call Ke for the update */
1931 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE);
1932 Status = STATUS_SUCCESS;
1933 break;
1934
1935 case ProcessUserModeIOPL:
1936
1937 /* Only TCB can do this */
1938 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1939 {
1940 /* We don't hold the privilege, bail out */
1941 DPRINT1("Need TCB to set IOPL\n");
1942 Status = STATUS_PRIVILEGE_NOT_HELD;
1943 break;
1944 }
1945
1946 /* Only supported on x86 */
1947 #if defined (_X86_)
1948 Ke386SetIOPL();
1949 #elif defined(_M_AMD64)
1950 /* On x64 this function isn't implemented.
1951 On Windows 2003 it returns success.
1952 On Vista+ it returns STATUS_NOT_IMPLEMENTED. */
1953 if ((ExGetPreviousMode() != KernelMode) &&
1954 (RtlRosGetAppcompatVersion() > _WIN32_WINNT_WS03))
1955 {
1956 Status = STATUS_NOT_IMPLEMENTED;
1957 }
1958 #else
1959 Status = STATUS_NOT_IMPLEMENTED;
1960 #endif
1961 /* Done */
1962 break;
1963
1964 case ProcessExecuteFlags:
1965
1966 /* Check buffer length */
1967 if (ProcessInformationLength != sizeof(ULONG))
1968 {
1969 Status = STATUS_INFO_LENGTH_MISMATCH;
1970 break;
1971 }
1972
1973 if (ProcessHandle != NtCurrentProcess())
1974 {
1975 Status = STATUS_INVALID_PARAMETER;
1976 break;
1977 }
1978
1979 /* Enter SEH for direct buffer read */
1980 _SEH2_TRY
1981 {
1982 NoExecute = *(PULONG)ProcessInformation;
1983 }
1984 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1985 {
1986 /* Get exception code */
1987 Status = _SEH2_GetExceptionCode();
1988 _SEH2_YIELD(break);
1989 }
1990 _SEH2_END;
1991
1992 /* Call Mm for the update */
1993 Status = MmSetExecuteOptions(NoExecute);
1994 break;
1995
1996 case ProcessDeviceMap:
1997
1998 /* Check buffer length */
1999 if (ProcessInformationLength != sizeof(HANDLE))
2000 {
2001 Status = STATUS_INFO_LENGTH_MISMATCH;
2002 break;
2003 }
2004
2005 /* Use SEH for capture */
2006 _SEH2_TRY
2007 {
2008 /* Capture the handle */
2009 DirectoryHandle = *(PHANDLE)ProcessInformation;
2010 }
2011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2012 {
2013 /* Get the exception code */
2014 Status = _SEH2_GetExceptionCode();
2015 _SEH2_YIELD(break);
2016 }
2017 _SEH2_END;
2018
2019 /* Call Ob to set the device map */
2020 Status = ObSetDeviceMap(Process, DirectoryHandle);
2021 break;
2022
2023
2024 /* We currently don't implement any of these */
2025 case ProcessLdtInformation:
2026 case ProcessLdtSize:
2027 case ProcessIoPortHandlers:
2028 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass);
2029 Status = STATUS_NOT_IMPLEMENTED;
2030 break;
2031
2032 case ProcessQuotaLimits:
2033
2034 Status = PspSetQuotaLimits(Process,
2035 1,
2036 ProcessInformation,
2037 ProcessInformationLength,
2038 PreviousMode);
2039 break;
2040
2041 case ProcessWorkingSetWatch:
2042 DPRINT1("WS watch not implemented\n");
2043 Status = STATUS_NOT_IMPLEMENTED;
2044 break;
2045
2046 case ProcessHandleTracing:
2047 DPRINT1("Handle tracing not implemented\n");
2048 Status = STATUS_NOT_IMPLEMENTED;
2049 break;
2050
2051 /* Anything else is invalid */
2052 default:
2053 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass);
2054 Status = STATUS_INVALID_INFO_CLASS;
2055 }
2056
2057 /* Dereference and return status */
2058 ObDereferenceObject(Process);
2059 return Status;
2060 }
2061
2062 /*
2063 * @implemented
2064 */
2065 NTSTATUS
2066 NTAPI
NtSetInformationThread(IN HANDLE ThreadHandle,IN THREADINFOCLASS ThreadInformationClass,IN PVOID ThreadInformation,IN ULONG ThreadInformationLength)2067 NtSetInformationThread(IN HANDLE ThreadHandle,
2068 IN THREADINFOCLASS ThreadInformationClass,
2069 IN PVOID ThreadInformation,
2070 IN ULONG ThreadInformationLength)
2071 {
2072 PETHREAD Thread;
2073 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2074 NTSTATUS Status;
2075 HANDLE TokenHandle = NULL;
2076 KPRIORITY Priority = 0;
2077 KAFFINITY Affinity = 0, CombinedAffinity;
2078 PVOID Address = NULL;
2079 PEPROCESS Process;
2080 ULONG_PTR DisableBoost = 0;
2081 ULONG_PTR IdealProcessor = 0;
2082 ULONG_PTR Break = 0;
2083 PTEB Teb;
2084 ULONG_PTR TlsIndex = 0;
2085 PVOID *ExpansionSlots;
2086 PETHREAD ProcThread;
2087 BOOLEAN HasPrivilege;
2088 PAGED_CODE();
2089
2090 /* Verify Information Class validity */
2091 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
2092 PsThreadInfoClass,
2093 RTL_NUMBER_OF(PsThreadInfoClass),
2094 ThreadInformation,
2095 ThreadInformationLength,
2096 PreviousMode);
2097 if (!NT_SUCCESS(Status))
2098 {
2099 DPRINT1("NtSetInformationThread(): Information verification class failed! (Status -> 0x%lx, ThreadInformationClass -> %lx)\n", Status, ThreadInformationClass);
2100 return Status;
2101 }
2102
2103 /* Check what kind of information class this is */
2104 switch (ThreadInformationClass)
2105 {
2106 /* Thread priority */
2107 case ThreadPriority:
2108
2109 /* Check buffer length */
2110 if (ThreadInformationLength != sizeof(KPRIORITY))
2111 {
2112 Status = STATUS_INFO_LENGTH_MISMATCH;
2113 break;
2114 }
2115
2116 /* Use SEH for capture */
2117 _SEH2_TRY
2118 {
2119 /* Get the priority */
2120 Priority = *(PLONG)ThreadInformation;
2121 }
2122 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2123 {
2124 /* Get the exception code */
2125 Status = _SEH2_GetExceptionCode();
2126 _SEH2_YIELD(break);
2127 }
2128 _SEH2_END;
2129
2130 /* Validate it */
2131 if ((Priority > HIGH_PRIORITY) ||
2132 (Priority <= LOW_PRIORITY))
2133 {
2134 /* Fail */
2135 Status = STATUS_INVALID_PARAMETER;
2136 break;
2137 }
2138
2139 /* Check for the required privilege */
2140 if (Priority >= LOW_REALTIME_PRIORITY)
2141 {
2142 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
2143 ThreadHandle,
2144 THREAD_SET_INFORMATION,
2145 PreviousMode);
2146 if (!HasPrivilege)
2147 {
2148 DPRINT1("Privilege to change priority to %lx lacking\n", Priority);
2149 return STATUS_PRIVILEGE_NOT_HELD;
2150 }
2151 }
2152
2153 /* Reference the thread */
2154 Status = ObReferenceObjectByHandle(ThreadHandle,
2155 THREAD_SET_INFORMATION,
2156 PsThreadType,
2157 PreviousMode,
2158 (PVOID*)&Thread,
2159 NULL);
2160 if (!NT_SUCCESS(Status))
2161 break;
2162
2163 /* Set the priority */
2164 KeSetPriorityThread(&Thread->Tcb, Priority);
2165
2166 /* Dereference the thread */
2167 ObDereferenceObject(Thread);
2168 break;
2169
2170 case ThreadBasePriority:
2171
2172 /* Check buffer length */
2173 if (ThreadInformationLength != sizeof(LONG))
2174 {
2175 Status = STATUS_INFO_LENGTH_MISMATCH;
2176 break;
2177 }
2178
2179 /* Use SEH for capture */
2180 _SEH2_TRY
2181 {
2182 /* Get the priority */
2183 Priority = *(PLONG)ThreadInformation;
2184 }
2185 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2186 {
2187 /* Get the exception code */
2188 Status = _SEH2_GetExceptionCode();
2189 _SEH2_YIELD(break);
2190 }
2191 _SEH2_END;
2192
2193 /* Validate it */
2194 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
2195 (Priority < THREAD_BASE_PRIORITY_MIN))
2196 {
2197 /* These ones are OK */
2198 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
2199 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
2200 {
2201 /* Check if the process is real time */
2202 if (PsGetCurrentProcess()->PriorityClass !=
2203 PROCESS_PRIORITY_CLASS_REALTIME)
2204 {
2205 /* It isn't, fail */
2206 Status = STATUS_INVALID_PARAMETER;
2207 break;
2208 }
2209 }
2210 }
2211
2212 /* Reference the thread */
2213 Status = ObReferenceObjectByHandle(ThreadHandle,
2214 THREAD_SET_INFORMATION,
2215 PsThreadType,
2216 PreviousMode,
2217 (PVOID*)&Thread,
2218 NULL);
2219 if (!NT_SUCCESS(Status))
2220 break;
2221
2222 /* Set the base priority */
2223 KeSetBasePriorityThread(&Thread->Tcb, Priority);
2224
2225 /* Dereference the thread */
2226 ObDereferenceObject(Thread);
2227 break;
2228
2229 case ThreadAffinityMask:
2230
2231 /* Check buffer length */
2232 if (ThreadInformationLength != sizeof(ULONG_PTR))
2233 {
2234 Status = STATUS_INFO_LENGTH_MISMATCH;
2235 break;
2236 }
2237
2238 /* Use SEH for capture */
2239 _SEH2_TRY
2240 {
2241 /* Get the priority */
2242 Affinity = *(PULONG_PTR)ThreadInformation;
2243 }
2244 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2245 {
2246 /* Get the exception code */
2247 Status = _SEH2_GetExceptionCode();
2248 _SEH2_YIELD(break);
2249 }
2250 _SEH2_END;
2251
2252 /* Validate it */
2253 if (!Affinity)
2254 {
2255 /* Fail */
2256 Status = STATUS_INVALID_PARAMETER;
2257 break;
2258 }
2259
2260 /* Reference the thread */
2261 Status = ObReferenceObjectByHandle(ThreadHandle,
2262 THREAD_SET_INFORMATION,
2263 PsThreadType,
2264 PreviousMode,
2265 (PVOID*)&Thread,
2266 NULL);
2267 if (!NT_SUCCESS(Status))
2268 break;
2269
2270 /* Get the process */
2271 Process = Thread->ThreadsProcess;
2272
2273 /* Try to acquire rundown */
2274 if (ExAcquireRundownProtection(&Process->RundownProtect))
2275 {
2276 /* Lock it */
2277 KeEnterCriticalRegion();
2278 ExAcquirePushLockShared(&Process->ProcessLock);
2279
2280 /* Combine masks */
2281 CombinedAffinity = Affinity & Process->Pcb.Affinity;
2282 if (CombinedAffinity != Affinity)
2283 {
2284 /* Fail */
2285 Status = STATUS_INVALID_PARAMETER;
2286 }
2287 else
2288 {
2289 /* Set the affinity */
2290 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
2291 }
2292
2293 /* Release the lock and rundown */
2294 ExReleasePushLockShared(&Process->ProcessLock);
2295 KeLeaveCriticalRegion();
2296 ExReleaseRundownProtection(&Process->RundownProtect);
2297 }
2298 else
2299 {
2300 /* Too late */
2301 Status = STATUS_PROCESS_IS_TERMINATING;
2302 }
2303
2304 /* Dereference the thread */
2305 ObDereferenceObject(Thread);
2306 break;
2307
2308 case ThreadImpersonationToken:
2309
2310 /* Check buffer length */
2311 if (ThreadInformationLength != sizeof(HANDLE))
2312 {
2313 Status = STATUS_INFO_LENGTH_MISMATCH;
2314 break;
2315 }
2316
2317 /* Use SEH for capture */
2318 _SEH2_TRY
2319 {
2320 /* Save the token handle */
2321 TokenHandle = *(PHANDLE)ThreadInformation;
2322 }
2323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2324 {
2325 /* Get the exception code */
2326 Status = _SEH2_GetExceptionCode();
2327 _SEH2_YIELD(break);
2328 }
2329 _SEH2_END;
2330
2331 /* Reference the thread */
2332 Status = ObReferenceObjectByHandle(ThreadHandle,
2333 THREAD_SET_THREAD_TOKEN,
2334 PsThreadType,
2335 PreviousMode,
2336 (PVOID*)&Thread,
2337 NULL);
2338 if (!NT_SUCCESS(Status))
2339 break;
2340
2341 /* Assign the actual token */
2342 Status = PsAssignImpersonationToken(Thread, TokenHandle);
2343
2344 /* Dereference the thread */
2345 ObDereferenceObject(Thread);
2346 break;
2347
2348 case ThreadQuerySetWin32StartAddress:
2349
2350 /* Check buffer length */
2351 if (ThreadInformationLength != sizeof(ULONG_PTR))
2352 {
2353 Status = STATUS_INFO_LENGTH_MISMATCH;
2354 break;
2355 }
2356
2357 /* Use SEH for capture */
2358 _SEH2_TRY
2359 {
2360 /* Get the priority */
2361 Address = *(PVOID*)ThreadInformation;
2362 }
2363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2364 {
2365 /* Get the exception code */
2366 Status = _SEH2_GetExceptionCode();
2367 _SEH2_YIELD(break);
2368 }
2369 _SEH2_END;
2370
2371 /* Reference the thread */
2372 Status = ObReferenceObjectByHandle(ThreadHandle,
2373 THREAD_SET_INFORMATION,
2374 PsThreadType,
2375 PreviousMode,
2376 (PVOID*)&Thread,
2377 NULL);
2378 if (!NT_SUCCESS(Status))
2379 break;
2380
2381 /* Set the address */
2382 Thread->Win32StartAddress = Address;
2383
2384 /* Dereference the thread */
2385 ObDereferenceObject(Thread);
2386 break;
2387
2388 case ThreadIdealProcessor:
2389
2390 /* Check buffer length */
2391 if (ThreadInformationLength != sizeof(ULONG_PTR))
2392 {
2393 Status = STATUS_INFO_LENGTH_MISMATCH;
2394 break;
2395 }
2396
2397 /* Use SEH for capture */
2398 _SEH2_TRY
2399 {
2400 /* Get the priority */
2401 IdealProcessor = *(PULONG_PTR)ThreadInformation;
2402 }
2403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2404 {
2405 /* Get the exception code */
2406 Status = _SEH2_GetExceptionCode();
2407 _SEH2_YIELD(break);
2408 }
2409 _SEH2_END;
2410
2411 /* Validate it */
2412 if (IdealProcessor > MAXIMUM_PROCESSORS)
2413 {
2414 /* Fail */
2415 Status = STATUS_INVALID_PARAMETER;
2416 break;
2417 }
2418
2419 /* Reference the thread */
2420 Status = ObReferenceObjectByHandle(ThreadHandle,
2421 THREAD_SET_INFORMATION,
2422 PsThreadType,
2423 PreviousMode,
2424 (PVOID*)&Thread,
2425 NULL);
2426 if (!NT_SUCCESS(Status))
2427 break;
2428
2429 /* Set the ideal */
2430 Status = KeSetIdealProcessorThread(&Thread->Tcb,
2431 (CCHAR)IdealProcessor);
2432
2433 /* Get the TEB and protect the thread */
2434 Teb = Thread->Tcb.Teb;
2435 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
2436 {
2437 /* Save the ideal processor */
2438 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
2439
2440 /* Release rundown protection */
2441 ExReleaseRundownProtection(&Thread->RundownProtect);
2442 }
2443
2444 /* Dereference the thread */
2445 ObDereferenceObject(Thread);
2446 break;
2447
2448 case ThreadPriorityBoost:
2449
2450 /* Check buffer length */
2451 if (ThreadInformationLength != sizeof(ULONG_PTR))
2452 {
2453 Status = STATUS_INFO_LENGTH_MISMATCH;
2454 break;
2455 }
2456
2457 /* Use SEH for capture */
2458 _SEH2_TRY
2459 {
2460 /* Get the priority */
2461 DisableBoost = *(PULONG_PTR)ThreadInformation;
2462 }
2463 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2464 {
2465 /* Get the exception code */
2466 Status = _SEH2_GetExceptionCode();
2467 _SEH2_YIELD(break);
2468 }
2469 _SEH2_END;
2470
2471 /* Reference the thread */
2472 Status = ObReferenceObjectByHandle(ThreadHandle,
2473 THREAD_SET_INFORMATION,
2474 PsThreadType,
2475 PreviousMode,
2476 (PVOID*)&Thread,
2477 NULL);
2478 if (!NT_SUCCESS(Status))
2479 break;
2480
2481 /* Call the kernel */
2482 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
2483
2484 /* Dereference the thread */
2485 ObDereferenceObject(Thread);
2486 break;
2487
2488 case ThreadZeroTlsCell:
2489
2490 /* Check buffer length */
2491 if (ThreadInformationLength != sizeof(ULONG))
2492 {
2493 Status = STATUS_INFO_LENGTH_MISMATCH;
2494 break;
2495 }
2496
2497 /* Use SEH for capture */
2498 _SEH2_TRY
2499 {
2500 /* Get the priority */
2501 TlsIndex = *(PULONG)ThreadInformation;
2502 }
2503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2504 {
2505 /* Get the exception code */
2506 Status = _SEH2_GetExceptionCode();
2507 _SEH2_YIELD(break);
2508 }
2509 _SEH2_END;
2510
2511 /* Reference the thread */
2512 Status = ObReferenceObjectByHandle(ThreadHandle,
2513 THREAD_SET_INFORMATION,
2514 PsThreadType,
2515 PreviousMode,
2516 (PVOID*)&Thread,
2517 NULL);
2518 if (!NT_SUCCESS(Status))
2519 break;
2520
2521 /* This is only valid for the current thread */
2522 if (Thread != PsGetCurrentThread())
2523 {
2524 /* Fail */
2525 Status = STATUS_INVALID_PARAMETER;
2526 ObDereferenceObject(Thread);
2527 break;
2528 }
2529
2530 /* Get the process */
2531 Process = Thread->ThreadsProcess;
2532
2533 /* Loop the threads */
2534 ProcThread = PsGetNextProcessThread(Process, NULL);
2535 while (ProcThread)
2536 {
2537 /* Acquire rundown */
2538 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
2539 {
2540 /* Get the TEB */
2541 Teb = ProcThread->Tcb.Teb;
2542 if (Teb)
2543 {
2544 /* Check if we're in the expansion range */
2545 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
2546 {
2547 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
2548 TLS_EXPANSION_SLOTS) - 1)
2549 {
2550 /* Check if we have expansion slots */
2551 ExpansionSlots = Teb->TlsExpansionSlots;
2552 if (ExpansionSlots)
2553 {
2554 /* Clear the index */
2555 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
2556 }
2557 }
2558 }
2559 else
2560 {
2561 /* Clear the index */
2562 Teb->TlsSlots[TlsIndex] = NULL;
2563 }
2564 }
2565
2566 /* Release rundown */
2567 ExReleaseRundownProtection(&ProcThread->RundownProtect);
2568 }
2569
2570 /* Go to the next thread */
2571 ProcThread = PsGetNextProcessThread(Process, ProcThread);
2572 }
2573
2574 /* Dereference the thread */
2575 ObDereferenceObject(Thread);
2576 break;
2577
2578 case ThreadBreakOnTermination:
2579
2580 /* Check buffer length */
2581 if (ThreadInformationLength != sizeof(ULONG))
2582 {
2583 Status = STATUS_INFO_LENGTH_MISMATCH;
2584 break;
2585 }
2586
2587 /* Enter SEH for direct buffer read */
2588 _SEH2_TRY
2589 {
2590 Break = *(PULONG)ThreadInformation;
2591 }
2592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2593 {
2594 /* Get exception code */
2595 Break = 0;
2596 Status = _SEH2_GetExceptionCode();
2597 _SEH2_YIELD(break);
2598 }
2599 _SEH2_END;
2600
2601 /* Setting 'break on termination' requires the SeDebugPrivilege */
2602 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
2603 {
2604 /* We don't hold the privilege, bail out */
2605 Status = STATUS_PRIVILEGE_NOT_HELD;
2606 break;
2607 }
2608
2609 /* Reference the thread */
2610 Status = ObReferenceObjectByHandle(ThreadHandle,
2611 THREAD_SET_INFORMATION,
2612 PsThreadType,
2613 PreviousMode,
2614 (PVOID*)&Thread,
2615 NULL);
2616 if (!NT_SUCCESS(Status))
2617 break;
2618
2619 /* Set or clear the flag */
2620 if (Break)
2621 {
2622 PspSetCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2623 }
2624 else
2625 {
2626 PspClearCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2627 }
2628
2629 /* Dereference the thread */
2630 ObDereferenceObject(Thread);
2631 break;
2632
2633 case ThreadHideFromDebugger:
2634
2635 /* Check buffer length */
2636 if (ThreadInformationLength != 0)
2637 {
2638 Status = STATUS_INFO_LENGTH_MISMATCH;
2639 break;
2640 }
2641
2642 /* Reference the thread */
2643 Status = ObReferenceObjectByHandle(ThreadHandle,
2644 THREAD_SET_INFORMATION,
2645 PsThreadType,
2646 PreviousMode,
2647 (PVOID*)&Thread,
2648 NULL);
2649 if (!NT_SUCCESS(Status))
2650 break;
2651
2652 /* Set the flag */
2653 PspSetCrossThreadFlag(Thread, CT_HIDE_FROM_DEBUGGER_BIT);
2654
2655 /* Dereference the thread */
2656 ObDereferenceObject(Thread);
2657 break;
2658
2659 default:
2660 /* We don't implement it yet */
2661 DPRINT1("Not implemented: %d\n", ThreadInformationClass);
2662 Status = STATUS_NOT_IMPLEMENTED;
2663 }
2664
2665 return Status;
2666 }
2667
2668 /*
2669 * @implemented
2670 */
2671 NTSTATUS
2672 NTAPI
NtQueryInformationThread(IN HANDLE ThreadHandle,IN THREADINFOCLASS ThreadInformationClass,OUT PVOID ThreadInformation,IN ULONG ThreadInformationLength,OUT PULONG ReturnLength OPTIONAL)2673 NtQueryInformationThread(IN HANDLE ThreadHandle,
2674 IN THREADINFOCLASS ThreadInformationClass,
2675 OUT PVOID ThreadInformation,
2676 IN ULONG ThreadInformationLength,
2677 OUT PULONG ReturnLength OPTIONAL)
2678 {
2679 PETHREAD Thread;
2680 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2681 NTSTATUS Status;
2682 ULONG Access;
2683 ULONG Length = 0;
2684 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
2685 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
2686 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
2687 KIRQL OldIrql;
2688 ULONG ThreadTerminated;
2689 PAGED_CODE();
2690
2691 /* Verify Information Class validity */
2692 Status = DefaultQueryInfoBufferCheck(ThreadInformationClass,
2693 PsThreadInfoClass,
2694 RTL_NUMBER_OF(PsThreadInfoClass),
2695 ICIF_PROBE_READ,
2696 ThreadInformation,
2697 ThreadInformationLength,
2698 ReturnLength,
2699 NULL,
2700 PreviousMode);
2701 if (!NT_SUCCESS(Status))
2702 {
2703 DPRINT1("NtQueryInformationThread(): Information verification class failed! (Status -> 0x%lx , ThreadInformationClass -> %lx)\n", Status, ThreadInformationClass);
2704 return Status;
2705 }
2706
2707 /* Check what class this is */
2708 Access = THREAD_QUERY_INFORMATION;
2709
2710 /* Check what kind of information class this is */
2711 switch (ThreadInformationClass)
2712 {
2713 /* Basic thread information */
2714 case ThreadBasicInformation:
2715
2716 /* Set return length */
2717 Length = sizeof(THREAD_BASIC_INFORMATION);
2718
2719 if (ThreadInformationLength != Length)
2720 {
2721 Status = STATUS_INFO_LENGTH_MISMATCH;
2722 break;
2723 }
2724
2725 /* Reference the process */
2726 Status = ObReferenceObjectByHandle(ThreadHandle,
2727 Access,
2728 PsThreadType,
2729 PreviousMode,
2730 (PVOID*)&Thread,
2731 NULL);
2732 if (!NT_SUCCESS(Status))
2733 break;
2734
2735 /* Protect writes with SEH */
2736 _SEH2_TRY
2737 {
2738 /* Write all the information from the ETHREAD/KTHREAD */
2739 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
2740 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
2741 ThreadBasicInfo->ClientId = Thread->Cid;
2742 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
2743 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
2744 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
2745 }
2746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2747 {
2748 /* Get exception code */
2749 Status = _SEH2_GetExceptionCode();
2750 }
2751 _SEH2_END;
2752
2753 /* Dereference the thread */
2754 ObDereferenceObject(Thread);
2755 break;
2756
2757 /* Thread time information */
2758 case ThreadTimes:
2759
2760 /* Set the return length */
2761 Length = sizeof(KERNEL_USER_TIMES);
2762
2763 if (ThreadInformationLength != Length)
2764 {
2765 Status = STATUS_INFO_LENGTH_MISMATCH;
2766 break;
2767 }
2768
2769 /* Reference the process */
2770 Status = ObReferenceObjectByHandle(ThreadHandle,
2771 Access,
2772 PsThreadType,
2773 PreviousMode,
2774 (PVOID*)&Thread,
2775 NULL);
2776 if (!NT_SUCCESS(Status))
2777 break;
2778
2779 /* Protect writes with SEH */
2780 _SEH2_TRY
2781 {
2782 /* Copy time information from ETHREAD/KTHREAD */
2783 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime * KeMaximumIncrement;
2784 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime * KeMaximumIncrement;
2785 ThreadTime->CreateTime = Thread->CreateTime;
2786
2787 /* Exit time is in a union and only valid on actual exit! */
2788 if (KeReadStateThread(&Thread->Tcb))
2789 {
2790 ThreadTime->ExitTime = Thread->ExitTime;
2791 }
2792 else
2793 {
2794 ThreadTime->ExitTime.QuadPart = 0;
2795 }
2796 }
2797 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2798 {
2799 /* Get exception code */
2800 Status = _SEH2_GetExceptionCode();
2801 }
2802 _SEH2_END;
2803
2804 /* Dereference the thread */
2805 ObDereferenceObject(Thread);
2806 break;
2807
2808 case ThreadQuerySetWin32StartAddress:
2809
2810 /* Set the return length*/
2811 Length = sizeof(PVOID);
2812
2813 if (ThreadInformationLength != Length)
2814 {
2815 Status = STATUS_INFO_LENGTH_MISMATCH;
2816 break;
2817 }
2818
2819 /* Reference the process */
2820 Status = ObReferenceObjectByHandle(ThreadHandle,
2821 Access,
2822 PsThreadType,
2823 PreviousMode,
2824 (PVOID*)&Thread,
2825 NULL);
2826 if (!NT_SUCCESS(Status))
2827 break;
2828
2829 /* Protect write with SEH */
2830 _SEH2_TRY
2831 {
2832 /* Return the Win32 Start Address */
2833 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
2834 }
2835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2836 {
2837 /* Get exception code */
2838 Status = _SEH2_GetExceptionCode();
2839 }
2840 _SEH2_END;
2841
2842 /* Dereference the thread */
2843 ObDereferenceObject(Thread);
2844 break;
2845
2846 case ThreadPerformanceCount:
2847
2848 /* Set the return length*/
2849 Length = sizeof(LARGE_INTEGER);
2850
2851 if (ThreadInformationLength != Length)
2852 {
2853 Status = STATUS_INFO_LENGTH_MISMATCH;
2854 break;
2855 }
2856
2857 /* Reference the process */
2858 Status = ObReferenceObjectByHandle(ThreadHandle,
2859 Access,
2860 PsThreadType,
2861 PreviousMode,
2862 (PVOID*)&Thread,
2863 NULL);
2864 if (!NT_SUCCESS(Status))
2865 break;
2866
2867 /* Protect write with SEH */
2868 _SEH2_TRY
2869 {
2870 /* FIXME */
2871 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
2872 }
2873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2874 {
2875 /* Get exception code */
2876 Status = _SEH2_GetExceptionCode();
2877 }
2878 _SEH2_END;
2879
2880 /* Dereference the thread */
2881 ObDereferenceObject(Thread);
2882 break;
2883
2884 case ThreadAmILastThread:
2885
2886 /* Set the return length*/
2887 Length = sizeof(ULONG);
2888
2889 if (ThreadInformationLength != Length)
2890 {
2891 Status = STATUS_INFO_LENGTH_MISMATCH;
2892 break;
2893 }
2894
2895 /* Reference the process */
2896 Status = ObReferenceObjectByHandle(ThreadHandle,
2897 Access,
2898 PsThreadType,
2899 PreviousMode,
2900 (PVOID*)&Thread,
2901 NULL);
2902 if (!NT_SUCCESS(Status))
2903 break;
2904
2905 /* Protect write with SEH */
2906 _SEH2_TRY
2907 {
2908 /* Return whether or not we are the last thread */
2909 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
2910 ThreadListHead.Flink->Flink ==
2911 &Thread->ThreadsProcess->
2912 ThreadListHead) ?
2913 TRUE : FALSE);
2914 }
2915 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2916 {
2917 /* Get exception code */
2918 Status = _SEH2_GetExceptionCode();
2919 }
2920 _SEH2_END;
2921
2922 /* Dereference the thread */
2923 ObDereferenceObject(Thread);
2924 break;
2925
2926 case ThreadIsIoPending:
2927
2928 /* Set the return length*/
2929 Length = sizeof(ULONG);
2930
2931 if (ThreadInformationLength != Length)
2932 {
2933 Status = STATUS_INFO_LENGTH_MISMATCH;
2934 break;
2935 }
2936
2937 /* Reference the process */
2938 Status = ObReferenceObjectByHandle(ThreadHandle,
2939 Access,
2940 PsThreadType,
2941 PreviousMode,
2942 (PVOID*)&Thread,
2943 NULL);
2944 if (!NT_SUCCESS(Status))
2945 break;
2946
2947 /* Raise the IRQL to protect the IRP list */
2948 KeRaiseIrql(APC_LEVEL, &OldIrql);
2949
2950 /* Protect write with SEH */
2951 _SEH2_TRY
2952 {
2953 /* Check if the IRP list is empty or not */
2954 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
2955 }
2956 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2957 {
2958 /* Get exception code */
2959 Status = _SEH2_GetExceptionCode();
2960 }
2961 _SEH2_END;
2962
2963 /* Lower IRQL back */
2964 KeLowerIrql(OldIrql);
2965
2966 /* Dereference the thread */
2967 ObDereferenceObject(Thread);
2968 break;
2969
2970 /* LDT and GDT information */
2971 case ThreadDescriptorTableEntry:
2972
2973 #if defined(_X86_)
2974 /* Reference the process */
2975 Status = ObReferenceObjectByHandle(ThreadHandle,
2976 Access,
2977 PsThreadType,
2978 PreviousMode,
2979 (PVOID*)&Thread,
2980 NULL);
2981 if (!NT_SUCCESS(Status))
2982 break;
2983
2984 /* Call the worker routine */
2985 Status = PspQueryDescriptorThread(Thread,
2986 ThreadInformation,
2987 ThreadInformationLength,
2988 ReturnLength);
2989
2990 /* Dereference the thread */
2991 ObDereferenceObject(Thread);
2992 #else
2993 /* Only implemented on x86 */
2994 Status = STATUS_NOT_IMPLEMENTED;
2995 #endif
2996 break;
2997
2998 case ThreadPriorityBoost:
2999
3000 /* Set the return length*/
3001 Length = sizeof(ULONG);
3002
3003 if (ThreadInformationLength != Length)
3004 {
3005 Status = STATUS_INFO_LENGTH_MISMATCH;
3006 break;
3007 }
3008
3009 /* Reference the process */
3010 Status = ObReferenceObjectByHandle(ThreadHandle,
3011 Access,
3012 PsThreadType,
3013 PreviousMode,
3014 (PVOID*)&Thread,
3015 NULL);
3016 if (!NT_SUCCESS(Status))
3017 break;
3018
3019 _SEH2_TRY
3020 {
3021 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
3022 }
3023 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3024 {
3025 Status = _SEH2_GetExceptionCode();
3026 }
3027 _SEH2_END;
3028
3029 /* Dereference the thread */
3030 ObDereferenceObject(Thread);
3031 break;
3032
3033 case ThreadIsTerminated:
3034
3035 /* Set the return length*/
3036 Length = sizeof(ThreadTerminated);
3037
3038 if (ThreadInformationLength != Length)
3039 {
3040 Status = STATUS_INFO_LENGTH_MISMATCH;
3041 break;
3042 }
3043
3044 /* Reference the process */
3045 Status = ObReferenceObjectByHandle(ThreadHandle,
3046 Access,
3047 PsThreadType,
3048 PreviousMode,
3049 (PVOID*)&Thread,
3050 NULL);
3051 if (!NT_SUCCESS(Status))
3052 break;
3053
3054 ThreadTerminated = PsIsThreadTerminating(Thread);
3055
3056 _SEH2_TRY
3057 {
3058 *(PULONG)ThreadInformation = ThreadTerminated ? 1 : 0;
3059 }
3060 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3061 {
3062 Status = _SEH2_GetExceptionCode();
3063 }
3064 _SEH2_END;
3065
3066 /* Dereference the thread */
3067 ObDereferenceObject(Thread);
3068 break;
3069
3070 /* Anything else */
3071 default:
3072
3073 /* Not yet implemented */
3074 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
3075 Status = STATUS_NOT_IMPLEMENTED;
3076 }
3077
3078 /* Protect write with SEH */
3079 _SEH2_TRY
3080 {
3081 /* Check if caller wanted return length */
3082 if (ReturnLength) *ReturnLength = Length;
3083 }
3084 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3085 {
3086 /* Get exception code */
3087 Status = _SEH2_GetExceptionCode();
3088 }
3089 _SEH2_END;
3090
3091 return Status;
3092 }
3093
3094 /* EOF */
3095