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