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)
11 /* INCLUDES ******************************************************************/
18 ULONG PspTraceLevel
= 0;
20 /* PRIVATE FUNCTIONS *********************************************************/
24 PsReferenceProcessFilePointer(IN PEPROCESS Process
,
25 OUT PFILE_OBJECT
*FileObject
)
30 /* Lock the process */
31 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
33 return STATUS_PROCESS_IS_TERMINATING
;
37 Section
= Process
->SectionObject
;
40 /* Get the file object and reference it */
41 *FileObject
= MmGetFileObjectForSection((PVOID
)Section
);
42 ObReferenceObject(*FileObject
);
45 /* Release the protection */
46 ExReleaseRundownProtection(&Process
->RundownProtect
);
49 return Section
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
52 /* PUBLIC FUNCTIONS **********************************************************/
59 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
60 IN PROCESSINFOCLASS ProcessInformationClass
,
61 OUT PVOID ProcessInformation
,
62 IN ULONG ProcessInformationLength
,
63 OUT PULONG ReturnLength OPTIONAL
)
66 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
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
;
76 PPROCESS_SESSION_INFORMATION SessionInfo
=
77 (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
78 PVM_COUNTERS VmCounters
= (PVM_COUNTERS
)ProcessInformation
;
79 PIO_COUNTERS IoCounters
= (PIO_COUNTERS
)ProcessInformation
;
80 PQUOTA_LIMITS QuotaLimits
= (PQUOTA_LIMITS
)ProcessInformation
;
81 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
82 PUNICODE_STRING ImageName
;
83 ULONG Cookie
, ExecuteOptions
= 0;
85 PROCESS_VALUES ProcessValues
;
88 /* Check for user-mode caller */
89 if (PreviousMode
!= KernelMode
)
91 /* Prepare to probe parameters */
94 /* Probe the buffer */
95 ProbeForRead(ProcessInformation
,
96 ProcessInformationLength
,
99 /* Probe the return length if required */
100 if (ReturnLength
) ProbeForWriteUlong(ReturnLength
);
102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
104 /* Return the exception code */
105 _SEH2_YIELD(return _SEH2_GetExceptionCode());
110 if (((ProcessInformationClass
== ProcessCookie
) ||
111 (ProcessInformationClass
== ProcessImageInformation
)) &&
112 (ProcessHandle
!= NtCurrentProcess()))
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.
119 return STATUS_INVALID_PARAMETER
;
122 /* Check the information class */
123 switch (ProcessInformationClass
)
125 /* Basic process information */
126 case ProcessBasicInformation
:
128 if (ProcessInformationLength
!= sizeof(PROCESS_BASIC_INFORMATION
))
130 Status
= STATUS_INFO_LENGTH_MISMATCH
;
134 /* Set return length */
135 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
137 /* Reference the process */
138 Status
= ObReferenceObjectByHandle(ProcessHandle
,
139 PROCESS_QUERY_INFORMATION
,
144 if (!NT_SUCCESS(Status
)) break;
146 /* Protect writes with SEH */
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
->
155 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
156 (ULONG_PTR
)Process
->InheritedFromUniqueProcessId
;
157 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
162 /* Get exception code */
163 Status
= _SEH2_GetExceptionCode();
167 /* Dereference the process */
168 ObDereferenceObject(Process
);
171 /* Process quota limits */
172 case ProcessQuotaLimits
:
174 if (ProcessInformationLength
!= sizeof(QUOTA_LIMITS
))
176 Status
= STATUS_INFO_LENGTH_MISMATCH
;
180 Length
= sizeof(QUOTA_LIMITS
);
182 /* Reference the process */
183 Status
= ObReferenceObjectByHandle(ProcessHandle
,
184 PROCESS_QUERY_INFORMATION
,
189 if (!NT_SUCCESS(Status
)) break;
191 /* Indicate success */
192 Status
= STATUS_SUCCESS
;
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
;
202 /* Set default time limits */
203 QuotaLimits
->TimeLimit
.LowPart
= MAXULONG
;
204 QuotaLimits
->TimeLimit
.HighPart
= MAXULONG
;
206 /* Is quota block a default one? */
207 if (Process
->QuotaBlock
== &PspDefaultQuotaBlock
)
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;
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
;
225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
227 /* Get exception code */
228 Status
= _SEH2_GetExceptionCode();
232 /* Dereference the process */
233 ObDereferenceObject(Process
);
236 case ProcessIoCounters
:
238 if (ProcessInformationLength
!= sizeof(IO_COUNTERS
))
240 Status
= STATUS_INFO_LENGTH_MISMATCH
;
244 Length
= sizeof(IO_COUNTERS
);
246 /* Reference the process */
247 Status
= ObReferenceObjectByHandle(ProcessHandle
,
248 PROCESS_QUERY_INFORMATION
,
253 if (!NT_SUCCESS(Status
)) break;
255 /* Query IO counters from the process */
256 KeQueryValuesProcess(&Process
->Pcb
, &ProcessValues
);
260 RtlCopyMemory(IoCounters
, &ProcessValues
.IoInfo
, sizeof(IO_COUNTERS
));
262 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
264 /* Ignore exception */
268 /* Set status to success in any case */
269 Status
= STATUS_SUCCESS
;
271 /* Dereference the process */
272 ObDereferenceObject(Process
);
278 /* Set the return length */
279 if (ProcessInformationLength
!= sizeof(KERNEL_USER_TIMES
))
281 Status
= STATUS_INFO_LENGTH_MISMATCH
;
285 Length
= sizeof(KERNEL_USER_TIMES
);
287 /* Reference the process */
288 Status
= ObReferenceObjectByHandle(ProcessHandle
,
289 PROCESS_QUERY_INFORMATION
,
294 if (!NT_SUCCESS(Status
)) break;
296 /* Protect writes with SEH */
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
;
306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
308 /* Get exception code */
309 Status
= _SEH2_GetExceptionCode();
313 /* Dereference the process */
314 ObDereferenceObject(Process
);
317 /* Process Debug Port */
318 case ProcessDebugPort
:
320 if (ProcessInformationLength
!= sizeof(HANDLE
))
322 Status
= STATUS_INFO_LENGTH_MISMATCH
;
326 /* Set return length */
327 Length
= sizeof(HANDLE
);
329 /* Reference the process */
330 Status
= ObReferenceObjectByHandle(ProcessHandle
,
331 PROCESS_QUERY_INFORMATION
,
336 if (!NT_SUCCESS(Status
)) break;
338 /* Protect write with SEH */
341 /* Return whether or not we have a debug port */
342 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
?
345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
347 /* Get exception code */
348 Status
= _SEH2_GetExceptionCode();
352 /* Dereference the process */
353 ObDereferenceObject(Process
);
356 case ProcessHandleCount
:
358 if (ProcessInformationLength
!= sizeof(ULONG
))
360 Status
= STATUS_INFO_LENGTH_MISMATCH
;
364 /* Set the return length*/
365 Length
= sizeof(ULONG
);
367 /* Reference the process */
368 Status
= ObReferenceObjectByHandle(ProcessHandle
,
369 PROCESS_QUERY_INFORMATION
,
374 if (!NT_SUCCESS(Status
)) break;
376 /* Count the number of handles this process has */
377 HandleCount
= ObGetProcessHandleCount(Process
);
379 /* Protect write in SEH */
382 /* Return the count of handles */
383 *(PULONG
)ProcessInformation
= HandleCount
;
385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
387 /* Get the exception code */
388 Status
= _SEH2_GetExceptionCode();
392 /* Dereference the process */
393 ObDereferenceObject(Process
);
396 /* Session ID for the process */
397 case ProcessSessionInformation
:
399 if (ProcessInformationLength
!= sizeof(PROCESS_SESSION_INFORMATION
))
401 Status
= STATUS_INFO_LENGTH_MISMATCH
;
405 /* Set the return length*/
406 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
408 /* Reference the process */
409 Status
= ObReferenceObjectByHandle(ProcessHandle
,
410 PROCESS_QUERY_INFORMATION
,
415 if (!NT_SUCCESS(Status
)) break;
417 /* Enter SEH for write safety */
420 /* Write back the Session ID */
421 SessionInfo
->SessionId
= PsGetProcessSessionId(Process
);
423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
425 /* Get the exception code */
426 Status
= _SEH2_GetExceptionCode();
430 /* Dereference the process */
431 ObDereferenceObject(Process
);
434 /* Virtual Memory Statistics */
435 case ProcessVmCounters
:
437 /* Validate the input length */
438 if ((ProcessInformationLength
!= sizeof(VM_COUNTERS
)) &&
439 (ProcessInformationLength
!= sizeof(VM_COUNTERS_EX
)))
441 Status
= STATUS_INFO_LENGTH_MISMATCH
;
445 /* Reference the process */
446 Status
= ObReferenceObjectByHandle(ProcessHandle
,
447 PROCESS_QUERY_INFORMATION
,
452 if (!NT_SUCCESS(Status
)) break;
454 /* Enter SEH for write safety */
457 /* Return data from EPROCESS */
458 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
459 VmCounters
->VirtualSize
= Process
->VirtualSize
;
460 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
461 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
462 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
463 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
464 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
465 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
466 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
467 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2] << PAGE_SHIFT
;
468 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2] << PAGE_SHIFT
;
469 //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT;
472 /* Set the return length */
473 Length
= ProcessInformationLength
;
475 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
477 /* Get the exception code */
478 Status
= _SEH2_GetExceptionCode();
482 /* Dereference the process */
483 ObDereferenceObject(Process
);
486 /* Hard Error Processing Mode */
487 case ProcessDefaultHardErrorMode
:
489 if (ProcessInformationLength
!= sizeof(ULONG
))
491 Status
= STATUS_INFO_LENGTH_MISMATCH
;
495 /* Set the return length*/
496 Length
= sizeof(ULONG
);
498 /* Reference the process */
499 Status
= ObReferenceObjectByHandle(ProcessHandle
,
500 PROCESS_QUERY_INFORMATION
,
505 if (!NT_SUCCESS(Status
)) break;
507 /* Enter SEH for writing back data */
510 /* Write the current processing mode */
511 *(PULONG
)ProcessInformation
= Process
->
512 DefaultHardErrorProcessing
;
514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
516 /* Get the exception code */
517 Status
= _SEH2_GetExceptionCode();
521 /* Dereference the process */
522 ObDereferenceObject(Process
);
525 /* Priority Boosting status */
526 case ProcessPriorityBoost
:
528 if (ProcessInformationLength
!= sizeof(ULONG
))
530 Status
= STATUS_INFO_LENGTH_MISMATCH
;
534 /* Set the return length */
535 Length
= sizeof(ULONG
);
537 /* Reference the process */
538 Status
= ObReferenceObjectByHandle(ProcessHandle
,
539 PROCESS_QUERY_INFORMATION
,
544 if (!NT_SUCCESS(Status
)) break;
546 /* Enter SEH for writing back data */
549 /* Return boost status */
550 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
555 /* Get the exception code */
556 Status
= _SEH2_GetExceptionCode();
560 /* Dereference the process */
561 ObDereferenceObject(Process
);
565 case ProcessDeviceMap
:
567 if (ProcessInformationLength
!= RTL_FIELD_SIZE(PROCESS_DEVICEMAP_INFORMATION
, Query
))
569 if (ProcessInformationLength
== sizeof(PROCESS_DEVICEMAP_INFORMATION_EX
))
571 DPRINT1("PROCESS_DEVICEMAP_INFORMATION_EX not supported!\n");
572 Status
= STATUS_NOT_IMPLEMENTED
;
576 Status
= STATUS_INFO_LENGTH_MISMATCH
;
581 /* Set the return length */
582 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
584 /* Reference the process */
585 Status
= ObReferenceObjectByHandle(ProcessHandle
,
586 PROCESS_QUERY_INFORMATION
,
591 if (!NT_SUCCESS(Status
)) break;
593 /* Query the device map information */
594 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
596 /* Enter SEH for writing back data */
599 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
601 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
603 /* Get the exception code */
604 Status
= _SEH2_GetExceptionCode();
608 /* Dereference the process */
609 ObDereferenceObject(Process
);
613 case ProcessPriorityClass
:
615 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
617 Status
= STATUS_INFO_LENGTH_MISMATCH
;
621 /* Set the return length*/
622 Length
= sizeof(PROCESS_PRIORITY_CLASS
);
624 /* Reference the process */
625 Status
= ObReferenceObjectByHandle(ProcessHandle
,
626 PROCESS_QUERY_INFORMATION
,
631 if (!NT_SUCCESS(Status
)) break;
633 /* Enter SEH for writing back data */
636 /* Return current priority class */
637 PsPriorityClass
->PriorityClass
= Process
->PriorityClass
;
638 PsPriorityClass
->Foreground
= FALSE
;
640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
642 /* Get the exception code */
643 Status
= _SEH2_GetExceptionCode();
647 /* Dereference the process */
648 ObDereferenceObject(Process
);
651 case ProcessImageFileName
:
653 /* Reference the process */
654 Status
= ObReferenceObjectByHandle(ProcessHandle
,
655 PROCESS_QUERY_INFORMATION
,
660 if (!NT_SUCCESS(Status
)) break;
662 /* Get the image path */
663 Status
= SeLocateProcessImageName(Process
, &ImageName
);
664 if (NT_SUCCESS(Status
))
666 /* Set return length */
667 Length
= ImageName
->MaximumLength
+
668 sizeof(OBJECT_NAME_INFORMATION
);
670 /* Make sure it's large enough */
671 if (Length
<= ProcessInformationLength
)
673 /* Enter SEH to protect write */
677 RtlCopyMemory(ProcessInformation
,
682 ((PUNICODE_STRING
)ProcessInformation
)->Buffer
=
683 (PWSTR
)((PUNICODE_STRING
)ProcessInformation
+ 1);
685 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
687 /* Get the exception code */
688 Status
= _SEH2_GetExceptionCode();
694 /* Buffer too small */
695 Status
= STATUS_INFO_LENGTH_MISMATCH
;
698 /* Free the image path */
699 ExFreePoolWithTag(ImageName
, TAG_SEPA
);
701 /* Dereference the process */
702 ObDereferenceObject(Process
);
705 case ProcessDebugFlags
:
707 if (ProcessInformationLength
!= sizeof(ULONG
))
709 Status
= STATUS_INFO_LENGTH_MISMATCH
;
713 /* Set the return length*/
714 Length
= sizeof(ULONG
);
716 /* Reference the process */
717 Status
= ObReferenceObjectByHandle(ProcessHandle
,
718 PROCESS_QUERY_INFORMATION
,
723 if (!NT_SUCCESS(Status
)) break;
725 /* Enter SEH for writing back data */
728 /* Return the debug flag state */
729 *(PULONG
)ProcessInformation
= Process
->NoDebugInherit
? 0 : 1;
731 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
733 /* Get the exception code */
734 Status
= _SEH2_GetExceptionCode();
738 /* Dereference the process */
739 ObDereferenceObject(Process
);
742 case ProcessBreakOnTermination
:
744 if (ProcessInformationLength
!= sizeof(ULONG
))
746 Status
= STATUS_INFO_LENGTH_MISMATCH
;
750 /* Set the return length */
751 Length
= sizeof(ULONG
);
753 /* Reference the process */
754 Status
= ObReferenceObjectByHandle(ProcessHandle
,
755 PROCESS_QUERY_INFORMATION
,
760 if (!NT_SUCCESS(Status
)) break;
762 /* Enter SEH for writing back data */
765 /* Return the BreakOnTermination state */
766 *(PULONG
)ProcessInformation
= Process
->BreakOnTermination
;
768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
770 /* Get the exception code */
771 Status
= _SEH2_GetExceptionCode();
775 /* Dereference the process */
776 ObDereferenceObject(Process
);
779 /* Per-process security cookie */
782 /* Get the current process and cookie */
783 Process
= PsGetCurrentProcess();
784 Cookie
= Process
->Cookie
;
787 LARGE_INTEGER SystemTime
;
791 /* Generate a new cookie */
792 KeQuerySystemTime(&SystemTime
);
793 Prcb
= KeGetCurrentPrcb();
794 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
795 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
797 /* Set the new cookie or return the current one */
798 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
801 if (!Cookie
) Cookie
= NewCookie
;
803 /* Set return length */
804 Length
= sizeof(ULONG
);
807 /* Indicate success */
808 Status
= STATUS_SUCCESS
;
810 /* Enter SEH to protect write */
813 /* Write back the cookie */
814 *(PULONG
)ProcessInformation
= Cookie
;
816 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
818 /* Get the exception code */
819 Status
= _SEH2_GetExceptionCode();
824 case ProcessImageInformation
:
826 if (ProcessInformationLength
!= sizeof(SECTION_IMAGE_INFORMATION
))
829 Status
= STATUS_INFO_LENGTH_MISMATCH
;
833 /* Set the length required and validate it */
834 Length
= sizeof(SECTION_IMAGE_INFORMATION
);
836 /* Enter SEH to protect write */
839 MmGetImageInformation((PSECTION_IMAGE_INFORMATION
)ProcessInformation
);
841 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
843 /* Get the exception code */
844 Status
= _SEH2_GetExceptionCode();
848 /* Indicate success */
849 Status
= STATUS_SUCCESS
;
852 case ProcessDebugObjectHandle
:
854 if (ProcessInformationLength
!= sizeof(HANDLE
))
856 Status
= STATUS_INFO_LENGTH_MISMATCH
;
860 /* Set the return length */
861 Length
= sizeof(HANDLE
);
863 /* Reference the process */
864 Status
= ObReferenceObjectByHandle(ProcessHandle
,
865 PROCESS_QUERY_INFORMATION
,
870 if (!NT_SUCCESS(Status
)) break;
872 /* Get the debug port */
873 Status
= DbgkOpenProcessDebugPort(Process
, PreviousMode
, &DebugPort
);
875 /* Let go of the process */
876 ObDereferenceObject(Process
);
878 /* Protect write in SEH */
881 /* Return debug port's handle */
882 *(PHANDLE
)ProcessInformation
= DebugPort
;
884 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
886 /* Get the exception code */
887 Status
= _SEH2_GetExceptionCode();
892 case ProcessHandleTracing
:
893 DPRINT1("Handle tracing Not implemented: %lx\n", ProcessInformationClass
);
894 Status
= STATUS_NOT_IMPLEMENTED
;
897 case ProcessLUIDDeviceMapsEnabled
:
899 if (ProcessInformationLength
!= sizeof(ULONG
))
901 Status
= STATUS_INFO_LENGTH_MISMATCH
;
905 /* Set the return length */
906 Length
= sizeof(ULONG
);
908 /* Indicate success */
909 Status
= STATUS_SUCCESS
;
911 /* Protect write in SEH */
915 *(PULONG
)ProcessInformation
= ObIsLUIDDeviceMapsEnabled();
917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
919 /* Get the exception code */
920 Status
= _SEH2_GetExceptionCode();
925 case ProcessWx86Information
:
927 if (ProcessInformationLength
!= sizeof(ULONG
))
929 Status
= STATUS_INFO_LENGTH_MISMATCH
;
933 /* Set the return length */
934 Length
= sizeof(ULONG
);
936 /* Reference the process */
937 Status
= ObReferenceObjectByHandle(ProcessHandle
,
938 PROCESS_QUERY_INFORMATION
,
943 if (!NT_SUCCESS(Status
)) break;
945 /* Protect write in SEH */
948 /* Return if the flag is set */
949 *(PULONG
)ProcessInformation
= (ULONG
)Process
->VdmAllowed
;
951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
953 /* Get the exception code */
954 Status
= _SEH2_GetExceptionCode();
958 /* Dereference the process */
959 ObDereferenceObject(Process
);
962 case ProcessWow64Information
:
964 if (ProcessInformationLength
!= sizeof(ULONG_PTR
))
966 Status
= STATUS_INFO_LENGTH_MISMATCH
;
970 /* Set return length */
971 Length
= sizeof(ULONG_PTR
);
973 /* Reference the process */
974 Status
= ObReferenceObjectByHandle(ProcessHandle
,
975 PROCESS_QUERY_INFORMATION
,
980 if (!NT_SUCCESS(Status
)) break;
982 /* Make sure the process isn't dying */
983 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
985 /* Get the WOW64 process structure */
987 Wow64
= (ULONG_PTR
)Process
->Wow64Process
;
991 /* Release the lock */
992 ExReleaseRundownProtection(&Process
->RundownProtect
);
995 /* Protect write with SEH */
998 /* Return whether or not we have a debug port */
999 *(PULONG_PTR
)ProcessInformation
= Wow64
;
1001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1003 /* Get exception code */
1004 Status
= _SEH2_GetExceptionCode();
1008 /* Dereference the process */
1009 ObDereferenceObject(Process
);
1012 case ProcessExecuteFlags
:
1014 if (ProcessInformationLength
!= sizeof(ULONG
))
1016 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1020 /* Set return length */
1021 Length
= sizeof(ULONG
);
1023 if (ProcessHandle
!= NtCurrentProcess())
1025 return STATUS_INVALID_PARAMETER
;
1028 /* Get the options */
1029 Status
= MmGetExecuteOptions(&ExecuteOptions
);
1030 if (NT_SUCCESS(Status
))
1032 /* Protect write with SEH */
1036 *(PULONG
)ProcessInformation
= ExecuteOptions
;
1038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1040 /* Get exception code */
1041 Status
= _SEH2_GetExceptionCode();
1047 case ProcessLdtInformation
:
1048 DPRINT1("VDM/16-bit not implemented: %lx\n", ProcessInformationClass
);
1049 Status
= STATUS_NOT_IMPLEMENTED
;
1052 case ProcessWorkingSetWatch
:
1053 DPRINT1("WS Watch Not implemented: %lx\n", ProcessInformationClass
);
1054 Status
= STATUS_NOT_IMPLEMENTED
;
1057 case ProcessPooledUsageAndLimits
:
1058 DPRINT1("Pool limits Not implemented: %lx\n", ProcessInformationClass
);
1059 Status
= STATUS_NOT_IMPLEMENTED
;
1062 /* Not supported by Server 2003 */
1064 DPRINT1("Unsupported info class: %lx\n", ProcessInformationClass
);
1065 Status
= STATUS_INVALID_INFO_CLASS
;
1068 /* Protect write with SEH */
1071 /* Check if caller wanted return length */
1072 if ((ReturnLength
) && (Length
)) *ReturnLength
= Length
;
1074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1076 /* Get exception code */
1077 Status
= _SEH2_GetExceptionCode();
1089 NtSetInformationProcess(IN HANDLE ProcessHandle
,
1090 IN PROCESSINFOCLASS ProcessInformationClass
,
1091 IN PVOID ProcessInformation
,
1092 IN ULONG ProcessInformationLength
)
1095 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1098 HANDLE PortHandle
= NULL
;
1099 HANDLE TokenHandle
= NULL
;
1100 PROCESS_SESSION_INFORMATION SessionInfo
= {0};
1101 PROCESS_PRIORITY_CLASS PriorityClass
= {0};
1102 PROCESS_FOREGROUND_BACKGROUND Foreground
= {0};
1103 PVOID ExceptionPort
;
1105 KAFFINITY ValidAffinity
, Affinity
= 0;
1106 KPRIORITY BasePriority
= 0;
1107 UCHAR MemoryPriority
= 0;
1108 BOOLEAN DisableBoost
= 0;
1109 ULONG DefaultHardErrorMode
= 0;
1110 ULONG DebugFlags
= 0, EnableFixup
= 0, Boost
= 0;
1111 ULONG NoExecute
= 0, VdmPower
= 0;
1112 BOOLEAN HasPrivilege
;
1117 /* Verify Information Class validity */
1119 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
1121 RTL_NUMBER_OF(PsProcessInfoClass
),
1123 ProcessInformationLength
,
1125 if (!NT_SUCCESS(Status
)) return Status
;
1128 /* Check what class this is */
1129 Access
= PROCESS_SET_INFORMATION
;
1130 if (ProcessInformationClass
== ProcessSessionInformation
)
1132 /* Setting the Session ID needs a special mask */
1133 Access
|= PROCESS_SET_SESSIONID
;
1135 else if (ProcessInformationClass
== ProcessExceptionPort
)
1137 /* Setting the exception port needs a special mask */
1138 Access
|= PROCESS_SUSPEND_RESUME
;
1141 /* Reference the process */
1142 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1148 if (!NT_SUCCESS(Status
)) return Status
;
1150 /* Check what kind of information class this is */
1151 switch (ProcessInformationClass
)
1153 case ProcessWx86Information
:
1155 /* Check buffer length */
1156 if (ProcessInformationLength
!= sizeof(HANDLE
))
1158 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1162 /* Use SEH for capture */
1165 /* Capture the boolean */
1166 VdmPower
= *(PULONG
)ProcessInformation
;
1168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1170 /* Get the exception code */
1171 Status
= _SEH2_GetExceptionCode();
1176 /* Getting VDM powers requires the SeTcbPrivilege */
1177 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1179 /* We don't hold the privilege, bail out */
1180 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1181 DPRINT1("Need TCB privilege\n");
1185 /* Set or clear the flag */
1188 PspSetProcessFlag(Process
, PSF_VDM_ALLOWED_BIT
);
1192 PspClearProcessFlag(Process
, PSF_VDM_ALLOWED_BIT
);
1196 /* Error/Exception Port */
1197 case ProcessExceptionPort
:
1199 /* Check buffer length */
1200 if (ProcessInformationLength
!= sizeof(HANDLE
))
1202 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1206 /* Use SEH for capture */
1209 /* Capture the handle */
1210 PortHandle
= *(PHANDLE
)ProcessInformation
;
1212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1214 /* Get the exception code */
1215 Status
= _SEH2_GetExceptionCode();
1220 /* Setting the error port requires the SeTcbPrivilege */
1221 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1223 /* We don't hold the privilege, bail out */
1224 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1228 /* Get the LPC Port */
1229 Status
= ObReferenceObjectByHandle(PortHandle
,
1233 (PVOID
)&ExceptionPort
,
1235 if (!NT_SUCCESS(Status
)) break;
1237 /* Change the pointer */
1238 if (InterlockedCompareExchangePointer(&Process
->ExceptionPort
,
1242 /* We already had one, fail */
1243 ObDereferenceObject(ExceptionPort
);
1244 Status
= STATUS_PORT_ALREADY_SET
;
1248 /* Security Token */
1249 case ProcessAccessToken
:
1251 /* Check buffer length */
1252 if (ProcessInformationLength
!= sizeof(PROCESS_ACCESS_TOKEN
))
1254 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1258 /* Use SEH for capture */
1261 /* Save the token handle */
1262 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->
1265 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1267 /* Get the exception code */
1268 Status
= _SEH2_GetExceptionCode();
1273 /* Assign the actual token */
1274 Status
= PspSetPrimaryToken(Process
, TokenHandle
, NULL
);
1277 /* Hard error processing */
1278 case ProcessDefaultHardErrorMode
:
1280 /* Check buffer length */
1281 if (ProcessInformationLength
!= sizeof(ULONG
))
1283 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1287 /* Enter SEH for direct buffer read */
1290 DefaultHardErrorMode
= *(PULONG
)ProcessInformation
;
1292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1294 /* Get exception code */
1295 Status
= _SEH2_GetExceptionCode();
1301 Process
->DefaultHardErrorProcessing
= DefaultHardErrorMode
;
1303 /* Call Ke for the update */
1304 if (DefaultHardErrorMode
& SEM_NOALIGNMENTFAULTEXCEPT
)
1306 KeSetAutoAlignmentProcess(&Process
->Pcb
, TRUE
);
1310 KeSetAutoAlignmentProcess(&Process
->Pcb
, FALSE
);
1312 Status
= STATUS_SUCCESS
;
1316 case ProcessSessionInformation
:
1318 /* Check buffer length */
1319 if (ProcessInformationLength
!= sizeof(PROCESS_SESSION_INFORMATION
))
1321 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1325 /* Enter SEH for capture */
1328 /* Capture the caller's buffer */
1329 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
1331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1333 /* Get the exception code */
1334 Status
= _SEH2_GetExceptionCode();
1339 /* Setting the session id requires the SeTcbPrivilege */
1340 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1342 /* We don't hold the privilege, bail out */
1343 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1347 #if 0 // OLD AND DEPRECATED CODE!!!!
1349 /* FIXME - update the session id for the process token */
1350 //Status = PsLockProcess(Process, FALSE);
1351 if (!NT_SUCCESS(Status
)) break;
1353 /* Write the session ID in the EPROCESS */
1354 Process
->Session
= UlongToPtr(SessionInfo
.SessionId
); // HACK!!!
1356 /* Check if the process also has a PEB */
1360 * Attach to the process to make sure we're in the right
1361 * context to access the PEB structure
1363 KeAttachProcess(&Process
->Pcb
);
1365 /* Enter SEH for write to user-mode PEB */
1368 /* Write the session ID */
1369 Process
->Peb
->SessionId
= SessionInfo
.SessionId
;
1371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1373 /* Get exception code */
1374 Status
= _SEH2_GetExceptionCode();
1378 /* Detach from the process */
1382 /* Unlock the process */
1383 //PsUnlockProcess(Process);
1388 * Since we cannot change the session ID of the given
1389 * process anymore because it is set once and for all
1390 * at process creation time and because it is stored
1391 * inside the Process->Session structure managed by MM,
1392 * we fake changing it: we just return success if the
1393 * user-defined value is the same as the session ID of
1394 * the process, and otherwise we fail.
1396 if (SessionInfo
.SessionId
== PsGetProcessSessionId(Process
))
1398 Status
= STATUS_SUCCESS
;
1402 Status
= STATUS_ACCESS_DENIED
;
1407 case ProcessPriorityClass
:
1409 /* Check buffer length */
1410 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
1412 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1416 /* Enter SEH for capture */
1419 /* Capture the caller's buffer */
1420 PriorityClass
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
1422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1424 /* Return the exception code */
1425 Status
= _SEH2_GetExceptionCode();
1430 /* Check for invalid PriorityClass value */
1431 if (PriorityClass
.PriorityClass
> PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
)
1433 Status
= STATUS_INVALID_PARAMETER
;
1437 if ((PriorityClass
.PriorityClass
!= Process
->PriorityClass
) &&
1438 (PriorityClass
.PriorityClass
== PROCESS_PRIORITY_CLASS_REALTIME
))
1440 /* Check the privilege */
1441 HasPrivilege
= SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege
,
1443 PROCESS_SET_INFORMATION
,
1447 ObDereferenceObject(Process
);
1448 DPRINT1("Privilege to change priority to realtime lacking\n");
1449 return STATUS_PRIVILEGE_NOT_HELD
;
1453 /* Check if we have a job */
1456 DPRINT1("Jobs not yet supported\n");
1459 /* Set process priority class */
1460 Process
->PriorityClass
= PriorityClass
.PriorityClass
;
1462 /* Set process priority mode (foreground or background) */
1463 PsSetProcessPriorityByClass(Process
,
1464 PriorityClass
.Foreground
?
1465 PsProcessPriorityForeground
:
1466 PsProcessPriorityBackground
);
1467 Status
= STATUS_SUCCESS
;
1470 case ProcessForegroundInformation
:
1472 /* Check buffer length */
1473 if (ProcessInformationLength
!= sizeof(PROCESS_FOREGROUND_BACKGROUND
))
1475 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1479 /* Enter SEH for capture */
1482 /* Capture the caller's buffer */
1483 Foreground
= *(PPROCESS_FOREGROUND_BACKGROUND
)ProcessInformation
;
1485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1487 /* Return the exception code */
1488 Status
= _SEH2_GetExceptionCode();
1493 /* Set process priority mode (foreground or background) */
1494 PsSetProcessPriorityByClass(Process
,
1495 Foreground
.Foreground
?
1496 PsProcessPriorityForeground
:
1497 PsProcessPriorityBackground
);
1498 Status
= STATUS_SUCCESS
;
1501 case ProcessBasePriority
:
1503 /* Validate input length */
1504 if (ProcessInformationLength
!= sizeof(KPRIORITY
))
1506 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1510 /* Enter SEH for direct buffer read */
1513 BasePriority
= *(KPRIORITY
*)ProcessInformation
;
1515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1517 /* Get exception code */
1519 Status
= _SEH2_GetExceptionCode();
1524 /* Extract the memory priority out of there */
1525 if (BasePriority
& 0x80000000)
1527 MemoryPriority
= MEMORY_PRIORITY_FOREGROUND
;
1528 BasePriority
&= ~0x80000000;
1532 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
1535 /* Validate the number */
1536 if ((BasePriority
> HIGH_PRIORITY
) || (BasePriority
<= LOW_PRIORITY
))
1538 ObDereferenceObject(Process
);
1539 return STATUS_INVALID_PARAMETER
;
1542 /* Check if the new base is higher */
1543 if (BasePriority
> Process
->Pcb
.BasePriority
)
1545 HasPrivilege
= SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege
,
1547 PROCESS_SET_INFORMATION
,
1551 ObDereferenceObject(Process
);
1552 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority
, Process
->Pcb
.BasePriority
);
1553 return STATUS_PRIVILEGE_NOT_HELD
;
1558 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, BasePriority
, 0);
1560 /* Now set the memory priority */
1561 MmSetMemoryPriorityProcess(Process
, MemoryPriority
);
1562 Status
= STATUS_SUCCESS
;
1565 case ProcessRaisePriority
:
1567 /* Validate input length */
1568 if (ProcessInformationLength
!= sizeof(ULONG
))
1570 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1574 /* Enter SEH for direct buffer read */
1577 Boost
= *(PULONG
)ProcessInformation
;
1579 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1581 /* Get exception code */
1583 Status
= _SEH2_GetExceptionCode();
1588 /* Make sure the process isn't dying */
1589 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1592 KeEnterCriticalRegion();
1593 ExAcquirePushLockShared(&Process
->ProcessLock
);
1595 /* Loop the threads */
1596 for (Next
= Process
->ThreadListHead
.Flink
;
1597 Next
!= &Process
->ThreadListHead
;
1600 /* Call Ke for the thread */
1601 Thread
= CONTAINING_RECORD(Next
, ETHREAD
, ThreadListEntry
);
1602 KeBoostPriorityThread(&Thread
->Tcb
, Boost
);
1605 /* Release the lock and rundown */
1606 ExReleasePushLockShared(&Process
->ProcessLock
);
1607 KeLeaveCriticalRegion();
1608 ExReleaseRundownProtection(&Process
->RundownProtect
);
1610 /* Set success code */
1611 Status
= STATUS_SUCCESS
;
1615 /* Avoid race conditions */
1616 Status
= STATUS_PROCESS_IS_TERMINATING
;
1620 case ProcessBreakOnTermination
:
1622 /* Check buffer length */
1623 if (ProcessInformationLength
!= sizeof(ULONG
))
1625 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1629 /* Enter SEH for direct buffer read */
1632 Break
= *(PULONG
)ProcessInformation
;
1634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1636 /* Get exception code */
1638 Status
= _SEH2_GetExceptionCode();
1643 /* Setting 'break on termination' requires the SeDebugPrivilege */
1644 if (!SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1646 /* We don't hold the privilege, bail out */
1647 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1651 /* Set or clear the flag */
1654 PspSetProcessFlag(Process
, PSF_BREAK_ON_TERMINATION_BIT
);
1658 PspClearProcessFlag(Process
, PSF_BREAK_ON_TERMINATION_BIT
);
1663 case ProcessAffinityMask
:
1665 /* Check buffer length */
1666 if (ProcessInformationLength
!= sizeof(KAFFINITY
))
1668 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1672 /* Enter SEH for direct buffer read */
1675 Affinity
= *(PKAFFINITY
)ProcessInformation
;
1677 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1679 /* Get exception code */
1681 Status
= _SEH2_GetExceptionCode();
1686 /* Make sure it's valid for the CPUs present */
1687 ValidAffinity
= Affinity
& KeActiveProcessors
;
1688 if (!Affinity
|| (ValidAffinity
!= Affinity
))
1690 Status
= STATUS_INVALID_PARAMETER
;
1694 /* Check if it's within job affinity limits */
1697 /* Not yet implemented */
1699 Status
= STATUS_NOT_IMPLEMENTED
;
1703 /* Make sure the process isn't dying */
1704 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1707 KeEnterCriticalRegion();
1708 ExAcquirePushLockShared(&Process
->ProcessLock
);
1710 /* Call Ke to do the work */
1711 KeSetAffinityProcess(&Process
->Pcb
, ValidAffinity
);
1713 /* Release the lock and rundown */
1714 ExReleasePushLockShared(&Process
->ProcessLock
);
1715 KeLeaveCriticalRegion();
1716 ExReleaseRundownProtection(&Process
->RundownProtect
);
1718 /* Set success code */
1719 Status
= STATUS_SUCCESS
;
1723 /* Avoid race conditions */
1724 Status
= STATUS_PROCESS_IS_TERMINATING
;
1728 /* Priority Boosting status */
1729 case ProcessPriorityBoost
:
1731 /* Validate input length */
1732 if (ProcessInformationLength
!= sizeof(ULONG
))
1734 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1738 /* Enter SEH for direct buffer read */
1741 DisableBoost
= *(PBOOLEAN
)ProcessInformation
;
1743 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1745 /* Get exception code */
1747 Status
= _SEH2_GetExceptionCode();
1752 /* Make sure the process isn't dying */
1753 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1756 KeEnterCriticalRegion();
1757 ExAcquirePushLockShared(&Process
->ProcessLock
);
1759 /* Call Ke to do the work */
1760 KeSetDisableBoostProcess(&Process
->Pcb
, DisableBoost
);
1762 /* Loop the threads too */
1763 for (Next
= Process
->ThreadListHead
.Flink
;
1764 Next
!= &Process
->ThreadListHead
;
1767 /* Call Ke for the thread */
1768 Thread
= CONTAINING_RECORD(Next
, ETHREAD
, ThreadListEntry
);
1769 KeSetDisableBoostThread(&Thread
->Tcb
, DisableBoost
);
1772 /* Release the lock and rundown */
1773 ExReleasePushLockShared(&Process
->ProcessLock
);
1774 KeLeaveCriticalRegion();
1775 ExReleaseRundownProtection(&Process
->RundownProtect
);
1777 /* Set success code */
1778 Status
= STATUS_SUCCESS
;
1782 /* Avoid race conditions */
1783 Status
= STATUS_PROCESS_IS_TERMINATING
;
1787 case ProcessDebugFlags
:
1789 /* Check buffer length */
1790 if (ProcessInformationLength
!= sizeof(ULONG
))
1792 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1796 /* Enter SEH for direct buffer read */
1799 DebugFlags
= *(PULONG
)ProcessInformation
;
1801 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1803 /* Get exception code */
1804 Status
= _SEH2_GetExceptionCode();
1810 if (DebugFlags
& ~1)
1812 Status
= STATUS_INVALID_PARAMETER
;
1818 PspClearProcessFlag(Process
, PSF_NO_DEBUG_INHERIT_BIT
);
1822 PspSetProcessFlag(Process
, PSF_NO_DEBUG_INHERIT_BIT
);
1827 Status
= STATUS_SUCCESS
;
1830 case ProcessEnableAlignmentFaultFixup
:
1832 /* Check buffer length */
1833 if (ProcessInformationLength
!= sizeof(ULONG
))
1835 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1839 /* Enter SEH for direct buffer read */
1842 EnableFixup
= *(PULONG
)ProcessInformation
;
1844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1846 /* Get exception code */
1847 Status
= _SEH2_GetExceptionCode();
1855 Process
->DefaultHardErrorProcessing
|= SEM_NOALIGNMENTFAULTEXCEPT
;
1859 Process
->DefaultHardErrorProcessing
&= ~SEM_NOALIGNMENTFAULTEXCEPT
;
1862 /* Call Ke for the update */
1863 KeSetAutoAlignmentProcess(&Process
->Pcb
, FALSE
);
1864 Status
= STATUS_SUCCESS
;
1867 case ProcessUserModeIOPL
:
1869 /* Only TCB can do this */
1870 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1872 /* We don't hold the privilege, bail out */
1873 DPRINT1("Need TCB to set IOPL\n");
1874 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1878 /* Only supported on x86 */
1882 Status
= STATUS_NOT_IMPLEMENTED
;
1887 case ProcessExecuteFlags
:
1889 /* Check buffer length */
1890 if (ProcessInformationLength
!= sizeof(ULONG
))
1892 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1896 if (ProcessHandle
!= NtCurrentProcess())
1898 Status
= STATUS_INVALID_PARAMETER
;
1902 /* Enter SEH for direct buffer read */
1905 NoExecute
= *(PULONG
)ProcessInformation
;
1907 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1909 /* Get exception code */
1910 Status
= _SEH2_GetExceptionCode();
1915 /* Call Mm for the update */
1916 Status
= MmSetExecuteOptions(NoExecute
);
1919 /* We currently don't implement any of these */
1920 case ProcessLdtInformation
:
1921 case ProcessLdtSize
:
1922 case ProcessIoPortHandlers
:
1923 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass
);
1924 Status
= STATUS_NOT_IMPLEMENTED
;
1927 case ProcessQuotaLimits
:
1929 Status
= PspSetQuotaLimits(Process
,
1932 ProcessInformationLength
,
1936 case ProcessWorkingSetWatch
:
1937 DPRINT1("WS watch not implemented\n");
1938 Status
= STATUS_NOT_IMPLEMENTED
;
1941 case ProcessDeviceMap
:
1942 DPRINT1("Device map not implemented\n");
1943 Status
= STATUS_NOT_IMPLEMENTED
;
1946 case ProcessHandleTracing
:
1947 DPRINT1("Handle tracing not implemented\n");
1948 Status
= STATUS_NOT_IMPLEMENTED
;
1951 /* Anything else is invalid */
1953 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass
);
1954 Status
= STATUS_INVALID_INFO_CLASS
;
1957 /* Dereference and return status */
1958 ObDereferenceObject(Process
);
1967 NtSetInformationThread(IN HANDLE ThreadHandle
,
1968 IN THREADINFOCLASS ThreadInformationClass
,
1969 IN PVOID ThreadInformation
,
1970 IN ULONG ThreadInformationLength
)
1974 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1976 HANDLE TokenHandle
= NULL
;
1977 KPRIORITY Priority
= 0;
1978 KAFFINITY Affinity
= 0, CombinedAffinity
;
1979 PVOID Address
= NULL
;
1981 ULONG_PTR DisableBoost
= 0;
1982 ULONG_PTR IdealProcessor
= 0;
1983 ULONG_PTR Break
= 0;
1985 ULONG_PTR TlsIndex
= 0;
1986 PVOID
*ExpansionSlots
;
1987 PETHREAD ProcThread
;
1990 /* Verify Information Class validity */
1992 Status
= DefaultSetInfoBufferCheck(ThreadInformationClass
,
1994 RTL_NUMBER_OF(PsThreadInfoClass
),
1996 ThreadInformationLength
,
1998 if (!NT_SUCCESS(Status
)) return Status
;
2001 /* Check what class this is */
2002 Access
= THREAD_SET_INFORMATION
;
2003 if (ThreadInformationClass
== ThreadImpersonationToken
)
2005 /* Setting the impersonation token needs a special mask */
2006 Access
= THREAD_SET_THREAD_TOKEN
;
2009 /* Reference the thread */
2010 Status
= ObReferenceObjectByHandle(ThreadHandle
,
2016 if (!NT_SUCCESS(Status
)) return Status
;
2018 /* Check what kind of information class this is */
2019 switch (ThreadInformationClass
)
2021 /* Thread priority */
2022 case ThreadPriority
:
2024 /* Check buffer length */
2025 if (ThreadInformationLength
!= sizeof(KPRIORITY
))
2027 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2031 /* Use SEH for capture */
2034 /* Get the priority */
2035 Priority
= *(PLONG
)ThreadInformation
;
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2039 /* Get the exception code */
2040 Status
= _SEH2_GetExceptionCode();
2046 if ((Priority
> HIGH_PRIORITY
) ||
2047 (Priority
<= LOW_PRIORITY
))
2050 Status
= STATUS_INVALID_PARAMETER
;
2054 /* Set the priority */
2055 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
2058 case ThreadBasePriority
:
2060 /* Check buffer length */
2061 if (ThreadInformationLength
!= sizeof(LONG
))
2063 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2067 /* Use SEH for capture */
2070 /* Get the priority */
2071 Priority
= *(PLONG
)ThreadInformation
;
2073 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2075 /* Get the exception code */
2076 Status
= _SEH2_GetExceptionCode();
2082 if ((Priority
> THREAD_BASE_PRIORITY_MAX
) ||
2083 (Priority
< THREAD_BASE_PRIORITY_MIN
))
2085 /* These ones are OK */
2086 if ((Priority
!= THREAD_BASE_PRIORITY_LOWRT
+ 1) &&
2087 (Priority
!= THREAD_BASE_PRIORITY_IDLE
- 1))
2089 /* Check if the process is real time */
2090 if (PsGetCurrentProcess()->PriorityClass
!=
2091 PROCESS_PRIORITY_CLASS_REALTIME
)
2093 /* It isn't, fail */
2094 Status
= STATUS_INVALID_PARAMETER
;
2100 /* Set the base priority */
2101 KeSetBasePriorityThread(&Thread
->Tcb
, Priority
);
2104 case ThreadAffinityMask
:
2106 /* Check buffer length */
2107 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2109 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2113 /* Use SEH for capture */
2116 /* Get the priority */
2117 Affinity
= *(PULONG_PTR
)ThreadInformation
;
2119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2121 /* Get the exception code */
2122 Status
= _SEH2_GetExceptionCode();
2131 Status
= STATUS_INVALID_PARAMETER
;
2135 /* Get the process */
2136 Process
= Thread
->ThreadsProcess
;
2138 /* Try to acquire rundown */
2139 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
2142 KeEnterCriticalRegion();
2143 ExAcquirePushLockShared(&Process
->ProcessLock
);
2146 CombinedAffinity
= Affinity
& Process
->Pcb
.Affinity
;
2147 if (CombinedAffinity
!= Affinity
)
2150 Status
= STATUS_INVALID_PARAMETER
;
2154 /* Set the affinity */
2155 KeSetAffinityThread(&Thread
->Tcb
, CombinedAffinity
);
2158 /* Release the lock and rundown */
2159 ExReleasePushLockShared(&Process
->ProcessLock
);
2160 KeLeaveCriticalRegion();
2161 ExReleaseRundownProtection(&Process
->RundownProtect
);
2166 Status
= STATUS_PROCESS_IS_TERMINATING
;
2172 case ThreadImpersonationToken
:
2174 /* Check buffer length */
2175 if (ThreadInformationLength
!= sizeof(HANDLE
))
2177 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2181 /* Use SEH for capture */
2184 /* Save the token handle */
2185 TokenHandle
= *(PHANDLE
)ThreadInformation
;
2187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2189 /* Get the exception code */
2190 Status
= _SEH2_GetExceptionCode();
2195 /* Assign the actual token */
2196 Status
= PsAssignImpersonationToken(Thread
, TokenHandle
);
2199 case ThreadQuerySetWin32StartAddress
:
2201 /* Check buffer length */
2202 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2204 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2208 /* Use SEH for capture */
2211 /* Get the priority */
2212 Address
= *(PVOID
*)ThreadInformation
;
2214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2216 /* Get the exception code */
2217 Status
= _SEH2_GetExceptionCode();
2222 /* Set the address */
2223 Thread
->Win32StartAddress
= Address
;
2226 case ThreadIdealProcessor
:
2228 /* Check buffer length */
2229 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2231 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2235 /* Use SEH for capture */
2238 /* Get the priority */
2239 IdealProcessor
= *(PULONG_PTR
)ThreadInformation
;
2241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2243 /* Get the exception code */
2244 Status
= _SEH2_GetExceptionCode();
2250 if (IdealProcessor
> MAXIMUM_PROCESSORS
)
2253 Status
= STATUS_INVALID_PARAMETER
;
2258 Status
= KeSetIdealProcessorThread(&Thread
->Tcb
,
2259 (CCHAR
)IdealProcessor
);
2261 /* Get the TEB and protect the thread */
2262 Teb
= Thread
->Tcb
.Teb
;
2263 if ((Teb
) && (ExAcquireRundownProtection(&Thread
->RundownProtect
)))
2265 /* Save the ideal processor */
2266 Teb
->IdealProcessor
= Thread
->Tcb
.IdealProcessor
;
2268 /* Release rundown protection */
2269 ExReleaseRundownProtection(&Thread
->RundownProtect
);
2274 case ThreadPriorityBoost
:
2276 /* Check buffer length */
2277 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2279 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2283 /* Use SEH for capture */
2286 /* Get the priority */
2287 DisableBoost
= *(PULONG_PTR
)ThreadInformation
;
2289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2291 /* Get the exception code */
2292 Status
= _SEH2_GetExceptionCode();
2297 /* Call the kernel */
2298 KeSetDisableBoostThread(&Thread
->Tcb
, (BOOLEAN
)DisableBoost
);
2301 case ThreadZeroTlsCell
:
2303 /* Check buffer length */
2304 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2306 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2310 /* Use SEH for capture */
2313 /* Get the priority */
2314 TlsIndex
= *(PULONG_PTR
)ThreadInformation
;
2316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2318 /* Get the exception code */
2319 Status
= _SEH2_GetExceptionCode();
2324 /* This is only valid for the current thread */
2325 if (Thread
!= PsGetCurrentThread())
2328 Status
= STATUS_INVALID_PARAMETER
;
2332 /* Get the process */
2333 Process
= Thread
->ThreadsProcess
;
2335 /* Loop the threads */
2336 ProcThread
= PsGetNextProcessThread(Process
, NULL
);
2339 /* Acquire rundown */
2340 if (ExAcquireRundownProtection(&ProcThread
->RundownProtect
))
2343 Teb
= ProcThread
->Tcb
.Teb
;
2346 /* Check if we're in the expansion range */
2347 if (TlsIndex
> TLS_MINIMUM_AVAILABLE
- 1)
2349 if (TlsIndex
< (TLS_MINIMUM_AVAILABLE
+
2350 TLS_EXPANSION_SLOTS
) - 1)
2352 /* Check if we have expansion slots */
2353 ExpansionSlots
= Teb
->TlsExpansionSlots
;
2356 /* Clear the index */
2357 ExpansionSlots
[TlsIndex
- TLS_MINIMUM_AVAILABLE
] = 0;
2363 /* Clear the index */
2364 Teb
->TlsSlots
[TlsIndex
] = NULL
;
2368 /* Release rundown */
2369 ExReleaseRundownProtection(&ProcThread
->RundownProtect
);
2372 /* Go to the next thread */
2373 ProcThread
= PsGetNextProcessThread(Process
, ProcThread
);
2379 case ThreadBreakOnTermination
:
2381 /* Check buffer length */
2382 if (ThreadInformationLength
!= sizeof(ULONG
))
2384 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2388 /* Enter SEH for direct buffer read */
2391 Break
= *(PULONG
)ThreadInformation
;
2393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2395 /* Get exception code */
2397 Status
= _SEH2_GetExceptionCode();
2402 /* Setting 'break on termination' requires the SeDebugPrivilege */
2403 if (!SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
2405 /* We don't hold the privilege, bail out */
2406 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2410 /* Set or clear the flag */
2413 PspSetCrossThreadFlag(Thread
, CT_BREAK_ON_TERMINATION_BIT
);
2417 PspClearCrossThreadFlag(Thread
, CT_BREAK_ON_TERMINATION_BIT
);
2421 case ThreadHideFromDebugger
:
2423 /* Check buffer length */
2424 if (ThreadInformationLength
!= 0)
2426 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2431 PspSetCrossThreadFlag(Thread
, CT_HIDE_FROM_DEBUGGER_BIT
);
2435 /* We don't implement it yet */
2436 DPRINT1("Not implemented: %d\n", ThreadInformationClass
);
2437 Status
= STATUS_NOT_IMPLEMENTED
;
2440 /* Dereference and return status */
2441 ObDereferenceObject(Thread
);
2450 NtQueryInformationThread(IN HANDLE ThreadHandle
,
2451 IN THREADINFOCLASS ThreadInformationClass
,
2452 OUT PVOID ThreadInformation
,
2453 IN ULONG ThreadInformationLength
,
2454 OUT PULONG ReturnLength OPTIONAL
)
2457 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
2461 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
=
2462 (PTHREAD_BASIC_INFORMATION
)ThreadInformation
;
2463 PKERNEL_USER_TIMES ThreadTime
= (PKERNEL_USER_TIMES
)ThreadInformation
;
2465 ULONG ThreadTerminated
;
2468 /* Check if we were called from user mode */
2469 if (PreviousMode
!= KernelMode
)
2474 /* Probe the buffer */
2475 ProbeForWrite(ThreadInformation
,
2476 ThreadInformationLength
,
2479 /* Probe the return length if required */
2480 if (ReturnLength
) ProbeForWriteUlong(ReturnLength
);
2482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2484 /* Return the exception code */
2485 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2490 /* Check what class this is */
2491 Access
= THREAD_QUERY_INFORMATION
;
2493 /* Reference the process */
2494 Status
= ObReferenceObjectByHandle(ThreadHandle
,
2500 if (!NT_SUCCESS(Status
)) return Status
;
2502 /* Check what kind of information class this is */
2503 switch (ThreadInformationClass
)
2505 /* Basic thread information */
2506 case ThreadBasicInformation
:
2508 /* Set return length */
2509 Length
= sizeof(THREAD_BASIC_INFORMATION
);
2511 if (ThreadInformationLength
!= Length
)
2513 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2516 /* Protect writes with SEH */
2519 /* Write all the information from the ETHREAD/KTHREAD */
2520 ThreadBasicInfo
->ExitStatus
= Thread
->ExitStatus
;
2521 ThreadBasicInfo
->TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
2522 ThreadBasicInfo
->ClientId
= Thread
->Cid
;
2523 ThreadBasicInfo
->AffinityMask
= Thread
->Tcb
.Affinity
;
2524 ThreadBasicInfo
->Priority
= Thread
->Tcb
.Priority
;
2525 ThreadBasicInfo
->BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
2527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2529 /* Get exception code */
2530 Status
= _SEH2_GetExceptionCode();
2535 /* Thread time information */
2538 /* Set the return length */
2539 Length
= sizeof(KERNEL_USER_TIMES
);
2541 if (ThreadInformationLength
!= Length
)
2543 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2546 /* Protect writes with SEH */
2549 /* Copy time information from ETHREAD/KTHREAD */
2550 ThreadTime
->KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* KeMaximumIncrement
;
2551 ThreadTime
->UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* KeMaximumIncrement
;
2552 ThreadTime
->CreateTime
= Thread
->CreateTime
;
2554 /* Exit time is in a union and only valid on actual exit! */
2555 if (KeReadStateThread(&Thread
->Tcb
))
2557 ThreadTime
->ExitTime
= Thread
->ExitTime
;
2561 ThreadTime
->ExitTime
.QuadPart
= 0;
2564 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2566 /* Get exception code */
2567 Status
= _SEH2_GetExceptionCode();
2572 case ThreadQuerySetWin32StartAddress
:
2574 /* Set the return length*/
2575 Length
= sizeof(PVOID
);
2577 if (ThreadInformationLength
!= Length
)
2579 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2582 /* Protect write with SEH */
2585 /* Return the Win32 Start Address */
2586 *(PVOID
*)ThreadInformation
= Thread
->Win32StartAddress
;
2588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2590 /* Get exception code */
2591 Status
= _SEH2_GetExceptionCode();
2596 case ThreadPerformanceCount
:
2598 /* Set the return length*/
2599 Length
= sizeof(LARGE_INTEGER
);
2601 if (ThreadInformationLength
!= Length
)
2603 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2606 /* Protect write with SEH */
2610 (*(PLARGE_INTEGER
)ThreadInformation
).QuadPart
= 0;
2612 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2614 /* Get exception code */
2615 Status
= _SEH2_GetExceptionCode();
2620 case ThreadAmILastThread
:
2622 /* Set the return length*/
2623 Length
= sizeof(ULONG
);
2625 if (ThreadInformationLength
!= Length
)
2627 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2630 /* Protect write with SEH */
2633 /* Return whether or not we are the last thread */
2634 *(PULONG
)ThreadInformation
= ((Thread
->ThreadsProcess
->
2635 ThreadListHead
.Flink
->Flink
==
2636 &Thread
->ThreadsProcess
->
2640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2642 /* Get exception code */
2643 Status
= _SEH2_GetExceptionCode();
2648 case ThreadIsIoPending
:
2650 /* Set the return length*/
2651 Length
= sizeof(ULONG
);
2653 if (ThreadInformationLength
!= Length
)
2655 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2658 /* Raise the IRQL to protect the IRP list */
2659 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2661 /* Protect write with SEH */
2664 /* Check if the IRP list is empty or not */
2665 *(PULONG
)ThreadInformation
= !IsListEmpty(&Thread
->IrpList
);
2667 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2669 /* Get exception code */
2670 Status
= _SEH2_GetExceptionCode();
2674 /* Lower IRQL back */
2675 KeLowerIrql(OldIrql
);
2678 /* LDT and GDT information */
2679 case ThreadDescriptorTableEntry
:
2682 /* Call the worker routine */
2683 Status
= PspQueryDescriptorThread(Thread
,
2685 ThreadInformationLength
,
2688 /* Only implemented on x86 */
2689 Status
= STATUS_NOT_IMPLEMENTED
;
2693 case ThreadPriorityBoost
:
2695 /* Set the return length*/
2696 Length
= sizeof(ULONG
);
2698 if (ThreadInformationLength
!= Length
)
2700 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2706 *(PULONG
)ThreadInformation
= Thread
->Tcb
.DisableBoost
? 1 : 0;
2708 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2710 Status
= _SEH2_GetExceptionCode();
2715 case ThreadIsTerminated
:
2717 /* Set the return length*/
2718 Length
= sizeof(ThreadTerminated
);
2720 if (ThreadInformationLength
!= Length
)
2722 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2726 ThreadTerminated
= PsIsThreadTerminating(Thread
);
2730 *(PULONG
)ThreadInformation
= ThreadTerminated
? 1 : 0;
2732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2734 Status
= _SEH2_GetExceptionCode();
2743 /* Not yet implemented */
2744 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
2745 Status
= STATUS_NOT_IMPLEMENTED
;
2748 /* Protect write with SEH */
2751 /* Check if caller wanted return length */
2752 if (ReturnLength
) *ReturnLength
= Length
;
2754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2756 /* Get exception code */
2757 Status
= _SEH2_GetExceptionCode();
2761 /* Dereference the thread, and return */
2762 ObDereferenceObject(Thread
);