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