xref: /reactos/ntoskrnl/ps/query.c (revision 205eadcb)
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