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