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