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 ExAcquireRundownProtection(&Process
->RundownProtect
);
34 Section
= Process
->SectionObject
;
37 /* Get the file object and reference it */
38 *FileObject
= MmGetFileObjectForSection((PVOID
)Section
);
39 ObReferenceObject(*FileObject
);
42 /* Release the protection */
43 ExReleaseRundownProtection(&Process
->RundownProtect
);
46 return Section
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
49 /* PUBLIC FUNCTIONS **********************************************************/
56 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
57 IN PROCESSINFOCLASS ProcessInformationClass
,
58 OUT PVOID ProcessInformation
,
59 IN ULONG ProcessInformationLength
,
60 OUT PULONG ReturnLength OPTIONAL
)
63 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
67 PPROCESS_BASIC_INFORMATION ProcessBasicInfo
=
68 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
69 PKERNEL_USER_TIMES ProcessTime
= (PKERNEL_USER_TIMES
)ProcessInformation
;
70 ULONG UserTime
, KernelTime
;
71 PPROCESS_PRIORITY_CLASS PsPriorityClass
= (PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
73 PPROCESS_SESSION_INFORMATION SessionInfo
=
74 (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
75 PVM_COUNTERS VmCounters
= (PVM_COUNTERS
)ProcessInformation
;
76 PIO_COUNTERS IoCounters
= (PIO_COUNTERS
)ProcessInformation
;
77 PQUOTA_LIMITS QuotaLimits
= (PQUOTA_LIMITS
)ProcessInformation
;
78 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
79 PUNICODE_STRING ImageName
;
80 ULONG Cookie
, ExecuteOptions
= 0;
84 /* Check for user-mode caller */
85 if (PreviousMode
!= KernelMode
)
87 /* Prepare to probe parameters */
90 /* Probe the buffer */
91 ProbeForRead(ProcessInformation
,
92 ProcessInformationLength
,
95 /* Probe the return length if required */
96 if (ReturnLength
) ProbeForWriteUlong(ReturnLength
);
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
100 /* Return the exception code */
101 _SEH2_YIELD(return _SEH2_GetExceptionCode());
106 if (((ProcessInformationClass
== ProcessCookie
) ||
107 (ProcessInformationClass
== ProcessImageInformation
)) &&
108 (ProcessHandle
!= NtCurrentProcess()))
111 * Retrieving the process cookie is only allowed for the calling process
112 * itself! XP only allows NtCurrentProcess() as process handles even if
113 * a real handle actually represents the current process.
115 return STATUS_INVALID_PARAMETER
;
118 /* Check the information class */
119 switch (ProcessInformationClass
)
121 /* Basic process information */
122 case ProcessBasicInformation
:
124 if (ProcessInformationLength
!= sizeof(PROCESS_BASIC_INFORMATION
))
126 Status
= STATUS_INFO_LENGTH_MISMATCH
;
130 /* Set return length */
131 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
133 /* Reference the process */
134 Status
= ObReferenceObjectByHandle(ProcessHandle
,
135 PROCESS_QUERY_INFORMATION
,
140 if (!NT_SUCCESS(Status
)) break;
142 /* Protect writes with SEH */
145 /* Write all the information from the EPROCESS/KPROCESS */
146 ProcessBasicInfo
->ExitStatus
= Process
->ExitStatus
;
147 ProcessBasicInfo
->PebBaseAddress
= Process
->Peb
;
148 ProcessBasicInfo
->AffinityMask
= Process
->Pcb
.Affinity
;
149 ProcessBasicInfo
->UniqueProcessId
= (ULONG_PTR
)Process
->
151 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
152 (ULONG_PTR
)Process
->InheritedFromUniqueProcessId
;
153 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
158 /* Get exception code */
159 Status
= _SEH2_GetExceptionCode();
163 /* Dereference the process */
164 ObDereferenceObject(Process
);
167 /* Process quota limits */
168 case ProcessQuotaLimits
:
170 if (ProcessInformationLength
!= sizeof(QUOTA_LIMITS
))
172 Status
= STATUS_INFO_LENGTH_MISMATCH
;
176 Length
= sizeof(QUOTA_LIMITS
);
178 /* Reference the process */
179 Status
= ObReferenceObjectByHandle(ProcessHandle
,
180 PROCESS_QUERY_INFORMATION
,
185 if (!NT_SUCCESS(Status
)) break;
187 /* Indicate success */
188 Status
= STATUS_SUCCESS
;
192 /* Set max/min working set sizes */
193 QuotaLimits
->MaximumWorkingSetSize
=
194 Process
->Vm
.MaximumWorkingSetSize
<< PAGE_SHIFT
;
195 QuotaLimits
->MinimumWorkingSetSize
=
196 Process
->Vm
.MinimumWorkingSetSize
<< PAGE_SHIFT
;
198 /* Set default time limits */
199 QuotaLimits
->TimeLimit
.LowPart
= MAXULONG
;
200 QuotaLimits
->TimeLimit
.HighPart
= MAXULONG
;
202 /* Is quota block a default one? */
203 if (Process
->QuotaBlock
== &PspDefaultQuotaBlock
)
205 /* Set default pools and pagefile limits */
206 QuotaLimits
->PagedPoolLimit
= (SIZE_T
)-1;
207 QuotaLimits
->NonPagedPoolLimit
= (SIZE_T
)-1;
208 QuotaLimits
->PagefileLimit
= (SIZE_T
)-1;
212 /* Get limits from non-default quota block */
213 QuotaLimits
->PagedPoolLimit
=
214 Process
->QuotaBlock
->QuotaEntry
[PagedPool
].Limit
;
215 QuotaLimits
->NonPagedPoolLimit
=
216 Process
->QuotaBlock
->QuotaEntry
[NonPagedPool
].Limit
;
217 QuotaLimits
->PagefileLimit
=
218 Process
->QuotaBlock
->QuotaEntry
[2].Limit
;
221 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
223 /* Get exception code */
224 Status
= _SEH2_GetExceptionCode();
228 /* Dereference the process */
229 ObDereferenceObject(Process
);
232 case ProcessIoCounters
:
234 if (ProcessInformationLength
!= sizeof(IO_COUNTERS
))
236 Status
= STATUS_INFO_LENGTH_MISMATCH
;
240 Length
= sizeof(IO_COUNTERS
);
242 /* Reference the process */
243 Status
= ObReferenceObjectByHandle(ProcessHandle
,
244 PROCESS_QUERY_INFORMATION
,
249 if (!NT_SUCCESS(Status
)) break;
253 /* FIXME: Call KeQueryValuesProcess */
254 IoCounters
->ReadOperationCount
= Process
->ReadOperationCount
.QuadPart
;
255 IoCounters
->ReadTransferCount
= Process
->ReadTransferCount
.QuadPart
;
256 IoCounters
->WriteOperationCount
= Process
->WriteOperationCount
.QuadPart
;
257 IoCounters
->WriteTransferCount
= Process
->WriteTransferCount
.QuadPart
;
258 IoCounters
->OtherOperationCount
= Process
->OtherOperationCount
.QuadPart
;
259 IoCounters
->OtherTransferCount
= Process
->OtherTransferCount
.QuadPart
;
261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
263 /* Ignore exception */
267 /* Set status to success in any case */
268 Status
= STATUS_SUCCESS
;
270 /* Dereference the process */
271 ObDereferenceObject(Process
);
277 /* Set the return length */
278 if (ProcessInformationLength
!= sizeof(KERNEL_USER_TIMES
))
280 Status
= STATUS_INFO_LENGTH_MISMATCH
;
284 Length
= sizeof(KERNEL_USER_TIMES
);
286 /* Reference the process */
287 Status
= ObReferenceObjectByHandle(ProcessHandle
,
288 PROCESS_QUERY_INFORMATION
,
293 if (!NT_SUCCESS(Status
)) break;
295 /* Protect writes with SEH */
298 /* Copy time information from EPROCESS/KPROCESS */
299 KernelTime
= KeQueryRuntimeProcess(&Process
->Pcb
, &UserTime
);
300 ProcessTime
->CreateTime
= Process
->CreateTime
;
301 ProcessTime
->UserTime
.QuadPart
= (LONGLONG
)UserTime
* KeMaximumIncrement
;
302 ProcessTime
->KernelTime
.QuadPart
= (LONGLONG
)KernelTime
* KeMaximumIncrement
;
303 ProcessTime
->ExitTime
= Process
->ExitTime
;
305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
307 /* Get exception code */
308 Status
= _SEH2_GetExceptionCode();
312 /* Dereference the process */
313 ObDereferenceObject(Process
);
316 /* Process Debug Port */
317 case ProcessDebugPort
:
319 if (ProcessInformationLength
!= sizeof(HANDLE
))
321 Status
= STATUS_INFO_LENGTH_MISMATCH
;
325 /* Set return length */
326 Length
= sizeof(HANDLE
);
328 /* Reference the process */
329 Status
= ObReferenceObjectByHandle(ProcessHandle
,
330 PROCESS_QUERY_INFORMATION
,
335 if (!NT_SUCCESS(Status
)) break;
337 /* Protect write with SEH */
340 /* Return whether or not we have a debug port */
341 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
?
344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
346 /* Get exception code */
347 Status
= _SEH2_GetExceptionCode();
351 /* Dereference the process */
352 ObDereferenceObject(Process
);
355 case ProcessHandleCount
:
357 if (ProcessInformationLength
!= sizeof(ULONG
))
359 Status
= STATUS_INFO_LENGTH_MISMATCH
;
363 /* Set the return length*/
364 Length
= sizeof(ULONG
);
366 /* Reference the process */
367 Status
= ObReferenceObjectByHandle(ProcessHandle
,
368 PROCESS_QUERY_INFORMATION
,
373 if (!NT_SUCCESS(Status
)) break;
375 /* Count the number of handles this process has */
376 HandleCount
= ObGetProcessHandleCount(Process
);
378 /* Protect write in SEH */
381 /* Return the count of handles */
382 *(PULONG
)ProcessInformation
= HandleCount
;
384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
386 /* Get the exception code */
387 Status
= _SEH2_GetExceptionCode();
391 /* Dereference the process */
392 ObDereferenceObject(Process
);
395 /* Session ID for the process */
396 case ProcessSessionInformation
:
398 if (ProcessInformationLength
!= sizeof(PROCESS_SESSION_INFORMATION
))
400 Status
= STATUS_INFO_LENGTH_MISMATCH
;
404 /* Set the return length*/
405 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
407 /* Reference the process */
408 Status
= ObReferenceObjectByHandle(ProcessHandle
,
409 PROCESS_QUERY_INFORMATION
,
414 if (!NT_SUCCESS(Status
)) break;
416 /* Enter SEH for write safety */
419 /* Write back the Session ID */
420 SessionInfo
->SessionId
= PsGetProcessSessionId(Process
);
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
424 /* Get the exception code */
425 Status
= _SEH2_GetExceptionCode();
429 /* Dereference the process */
430 ObDereferenceObject(Process
);
433 /* Virtual Memory Statistics */
434 case ProcessVmCounters
:
436 /* Validate the input length */
437 if ((ProcessInformationLength
!= sizeof(VM_COUNTERS
)) &&
438 (ProcessInformationLength
!= sizeof(VM_COUNTERS_EX
)))
440 Status
= STATUS_INFO_LENGTH_MISMATCH
;
444 /* Reference the process */
445 Status
= ObReferenceObjectByHandle(ProcessHandle
,
446 PROCESS_QUERY_INFORMATION
,
451 if (!NT_SUCCESS(Status
)) break;
453 /* Enter SEH for write safety */
456 /* Return data from EPROCESS */
457 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
458 VmCounters
->VirtualSize
= Process
->VirtualSize
;
459 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
460 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
461 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
462 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
463 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
464 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
465 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
466 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2] << PAGE_SHIFT
;
467 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2] << PAGE_SHIFT
;
468 //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT;
471 /* Set the return length */
472 Length
= ProcessInformationLength
;
474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
476 /* Get the exception code */
477 Status
= _SEH2_GetExceptionCode();
481 /* Dereference the process */
482 ObDereferenceObject(Process
);
485 /* Hard Error Processing Mode */
486 case ProcessDefaultHardErrorMode
:
488 if (ProcessInformationLength
!= sizeof(ULONG
))
490 Status
= STATUS_INFO_LENGTH_MISMATCH
;
494 /* Set the return length*/
495 Length
= sizeof(ULONG
);
497 /* Reference the process */
498 Status
= ObReferenceObjectByHandle(ProcessHandle
,
499 PROCESS_QUERY_INFORMATION
,
504 if (!NT_SUCCESS(Status
)) break;
506 /* Enter SEH for writing back data */
509 /* Write the current processing mode */
510 *(PULONG
)ProcessInformation
= Process
->
511 DefaultHardErrorProcessing
;
513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
515 /* Get the exception code */
516 Status
= _SEH2_GetExceptionCode();
520 /* Dereference the process */
521 ObDereferenceObject(Process
);
524 /* Priority Boosting status */
525 case ProcessPriorityBoost
:
527 if (ProcessInformationLength
!= sizeof(ULONG
))
529 Status
= STATUS_INFO_LENGTH_MISMATCH
;
533 /* Set the return length */
534 Length
= sizeof(ULONG
);
536 /* Reference the process */
537 Status
= ObReferenceObjectByHandle(ProcessHandle
,
538 PROCESS_QUERY_INFORMATION
,
543 if (!NT_SUCCESS(Status
)) break;
545 /* Enter SEH for writing back data */
548 /* Return boost status */
549 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
554 /* Get the exception code */
555 Status
= _SEH2_GetExceptionCode();
559 /* Dereference the process */
560 ObDereferenceObject(Process
);
564 case ProcessDeviceMap
:
566 if (ProcessInformationLength
!= sizeof(PROCESS_DEVICEMAP_INFORMATION
))
568 if (ProcessInformationLength
== sizeof(PROCESS_DEVICEMAP_INFORMATION_EX
))
570 DPRINT1("PROCESS_DEVICEMAP_INFORMATION_EX not supported!\n");
571 Status
= STATUS_NOT_IMPLEMENTED
;
575 Status
= STATUS_INFO_LENGTH_MISMATCH
;
580 /* Set the return length */
581 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
583 /* Reference the process */
584 Status
= ObReferenceObjectByHandle(ProcessHandle
,
585 PROCESS_QUERY_INFORMATION
,
590 if (!NT_SUCCESS(Status
)) break;
592 /* Query the device map information */
593 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
595 /* Enter SEH for writing back data */
598 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
602 /* Get the exception code */
603 Status
= _SEH2_GetExceptionCode();
607 /* Dereference the process */
608 ObDereferenceObject(Process
);
612 case ProcessPriorityClass
:
614 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
616 Status
= STATUS_INFO_LENGTH_MISMATCH
;
620 /* Set the return length*/
621 Length
= sizeof(PROCESS_PRIORITY_CLASS
);
623 /* Reference the process */
624 Status
= ObReferenceObjectByHandle(ProcessHandle
,
625 PROCESS_QUERY_INFORMATION
,
630 if (!NT_SUCCESS(Status
)) break;
632 /* Enter SEH for writing back data */
635 /* Return current priority class */
636 PsPriorityClass
->PriorityClass
= Process
->PriorityClass
;
637 PsPriorityClass
->Foreground
= FALSE
;
639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
641 /* Get the exception code */
642 Status
= _SEH2_GetExceptionCode();
646 /* Dereference the process */
647 ObDereferenceObject(Process
);
650 case ProcessImageFileName
:
652 /* Reference the process */
653 Status
= ObReferenceObjectByHandle(ProcessHandle
,
654 PROCESS_QUERY_INFORMATION
,
659 if (!NT_SUCCESS(Status
)) break;
661 /* Get the image path */
662 Status
= SeLocateProcessImageName(Process
, &ImageName
);
663 if (NT_SUCCESS(Status
))
665 /* Set return length */
666 Length
= ImageName
->MaximumLength
+
667 sizeof(OBJECT_NAME_INFORMATION
);
669 /* Make sure it's large enough */
670 if (Length
<= ProcessInformationLength
)
672 /* Enter SEH to protect write */
676 RtlCopyMemory(ProcessInformation
,
681 ((PUNICODE_STRING
)ProcessInformation
)->Buffer
=
682 (PWSTR
)((PUNICODE_STRING
)ProcessInformation
+ 1);
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
686 /* Get the exception code */
687 Status
= _SEH2_GetExceptionCode();
693 /* Buffer too small */
694 Status
= STATUS_INFO_LENGTH_MISMATCH
;
697 /* Free the image path */
698 ExFreePoolWithTag(ImageName
, TAG_SEPA
);
700 /* Dereference the process */
701 ObDereferenceObject(Process
);
704 case ProcessDebugFlags
:
706 if (ProcessInformationLength
!= sizeof(ULONG
))
708 Status
= STATUS_INFO_LENGTH_MISMATCH
;
712 /* Set the return length*/
713 Length
= sizeof(ULONG
);
715 /* Reference the process */
716 Status
= ObReferenceObjectByHandle(ProcessHandle
,
717 PROCESS_QUERY_INFORMATION
,
722 if (!NT_SUCCESS(Status
)) break;
724 /* Enter SEH for writing back data */
727 /* Return the debug flag state */
728 *(PULONG
)ProcessInformation
= Process
->NoDebugInherit
? 0 : 1;
730 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
732 /* Get the exception code */
733 Status
= _SEH2_GetExceptionCode();
737 /* Dereference the process */
738 ObDereferenceObject(Process
);
741 case ProcessBreakOnTermination
:
743 if (ProcessInformationLength
!= sizeof(ULONG
))
745 Status
= STATUS_INFO_LENGTH_MISMATCH
;
749 /* Set the return length */
750 Length
= sizeof(ULONG
);
752 /* Reference the process */
753 Status
= ObReferenceObjectByHandle(ProcessHandle
,
754 PROCESS_QUERY_INFORMATION
,
759 if (!NT_SUCCESS(Status
)) break;
761 /* Enter SEH for writing back data */
764 /* Return the BreakOnTermination state */
765 *(PULONG
)ProcessInformation
= Process
->BreakOnTermination
;
767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
769 /* Get the exception code */
770 Status
= _SEH2_GetExceptionCode();
774 /* Dereference the process */
775 ObDereferenceObject(Process
);
778 /* Per-process security cookie */
781 /* Get the current process and cookie */
782 Process
= PsGetCurrentProcess();
783 Cookie
= Process
->Cookie
;
786 LARGE_INTEGER SystemTime
;
790 /* Generate a new cookie */
791 KeQuerySystemTime(&SystemTime
);
792 Prcb
= KeGetCurrentPrcb();
793 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
794 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
796 /* Set the new cookie or return the current one */
797 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
800 if (!Cookie
) Cookie
= NewCookie
;
802 /* Set return length */
803 Length
= sizeof(ULONG
);
806 /* Indicate success */
807 Status
= STATUS_SUCCESS
;
809 /* Enter SEH to protect write */
812 /* Write back the cookie */
813 *(PULONG
)ProcessInformation
= Cookie
;
815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
817 /* Get the exception code */
818 Status
= _SEH2_GetExceptionCode();
823 case ProcessImageInformation
:
825 if (ProcessInformationLength
!= sizeof(SECTION_IMAGE_INFORMATION
))
828 Status
= STATUS_INFO_LENGTH_MISMATCH
;
832 /* Set the length required and validate it */
833 Length
= sizeof(SECTION_IMAGE_INFORMATION
);
835 /* Enter SEH to protect write */
838 MmGetImageInformation((PSECTION_IMAGE_INFORMATION
)ProcessInformation
);
840 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
842 /* Get the exception code */
843 Status
= _SEH2_GetExceptionCode();
847 /* Indicate success */
848 Status
= STATUS_SUCCESS
;
851 case ProcessDebugObjectHandle
:
853 if (ProcessInformationLength
!= sizeof(HANDLE
))
855 Status
= STATUS_INFO_LENGTH_MISMATCH
;
859 /* Set the return length */
860 Length
= sizeof(HANDLE
);
862 /* Reference the process */
863 Status
= ObReferenceObjectByHandle(ProcessHandle
,
864 PROCESS_QUERY_INFORMATION
,
869 if (!NT_SUCCESS(Status
)) break;
871 /* Get the debug port */
872 Status
= DbgkOpenProcessDebugPort(Process
, PreviousMode
, &DebugPort
);
874 /* Let go of the process */
875 ObDereferenceObject(Process
);
877 /* Protect write in SEH */
880 /* Return debug port's handle */
881 *(PHANDLE
)ProcessInformation
= DebugPort
;
883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
885 /* Get the exception code */
886 Status
= _SEH2_GetExceptionCode();
891 case ProcessHandleTracing
:
892 DPRINT1("Handle tracing Not implemented: %lx\n", ProcessInformationClass
);
893 Status
= STATUS_NOT_IMPLEMENTED
;
896 case ProcessLUIDDeviceMapsEnabled
:
898 if (ProcessInformationLength
!= sizeof(ULONG
))
900 Status
= STATUS_INFO_LENGTH_MISMATCH
;
904 /* Set the return length */
905 Length
= sizeof(ULONG
);
907 /* Indicate success */
908 Status
= STATUS_SUCCESS
;
910 /* Protect write in SEH */
913 /* Return FALSE -- we don't support this */
914 *(PULONG
)ProcessInformation
= FALSE
;
916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
918 /* Get the exception code */
919 Status
= _SEH2_GetExceptionCode();
924 case ProcessWx86Information
:
926 if (ProcessInformationLength
!= sizeof(ULONG
))
928 Status
= STATUS_INFO_LENGTH_MISMATCH
;
932 /* Set the return length */
933 Length
= sizeof(ULONG
);
935 /* Reference the process */
936 Status
= ObReferenceObjectByHandle(ProcessHandle
,
937 PROCESS_QUERY_INFORMATION
,
942 if (!NT_SUCCESS(Status
)) break;
944 /* Protect write in SEH */
947 /* Return if the flag is set */
948 *(PULONG
)ProcessInformation
= (ULONG
)Process
->VdmAllowed
;
950 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
952 /* Get the exception code */
953 Status
= _SEH2_GetExceptionCode();
957 /* Dereference the process */
958 ObDereferenceObject(Process
);
961 case ProcessWow64Information
:
963 if (ProcessInformationLength
!= sizeof(ULONG_PTR
))
965 Status
= STATUS_INFO_LENGTH_MISMATCH
;
969 /* Set return length */
970 Length
= sizeof(ULONG_PTR
);
972 /* Reference the process */
973 Status
= ObReferenceObjectByHandle(ProcessHandle
,
974 PROCESS_QUERY_INFORMATION
,
979 if (!NT_SUCCESS(Status
)) break;
981 /* Make sure the process isn't dying */
982 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
984 /* Get the WOW64 process structure */
986 Wow64
= (ULONG_PTR
)Process
->Wow64Process
;
990 /* Release the lock */
991 ExReleaseRundownProtection(&Process
->RundownProtect
);
994 /* Protect write with SEH */
997 /* Return whether or not we have a debug port */
998 *(PULONG_PTR
)ProcessInformation
= Wow64
;
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1002 /* Get exception code */
1003 Status
= _SEH2_GetExceptionCode();
1007 /* Dereference the process */
1008 ObDereferenceObject(Process
);
1011 case ProcessExecuteFlags
:
1013 if (ProcessInformationLength
!= sizeof(ULONG
))
1015 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1019 /* Set return length */
1020 Length
= sizeof(ULONG
);
1022 if (ProcessHandle
!= NtCurrentProcess())
1024 return STATUS_INVALID_PARAMETER
;
1027 /* Get the options */
1028 Status
= MmGetExecuteOptions(&ExecuteOptions
);
1029 if (NT_SUCCESS(Status
))
1031 /* Protect write with SEH */
1035 *(PULONG
)ProcessInformation
= ExecuteOptions
;
1037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1039 /* Get exception code */
1040 Status
= _SEH2_GetExceptionCode();
1046 case ProcessLdtInformation
:
1047 DPRINT1("VDM/16-bit not implemented: %lx\n", ProcessInformationClass
);
1048 Status
= STATUS_NOT_IMPLEMENTED
;
1051 case ProcessWorkingSetWatch
:
1052 DPRINT1("WS Watch Not implemented: %lx\n", ProcessInformationClass
);
1053 Status
= STATUS_NOT_IMPLEMENTED
;
1056 case ProcessPooledUsageAndLimits
:
1057 DPRINT1("Pool limits Not implemented: %lx\n", ProcessInformationClass
);
1058 Status
= STATUS_NOT_IMPLEMENTED
;
1061 /* Not supported by Server 2003 */
1063 DPRINT1("Unsupported info class: %lx\n", ProcessInformationClass
);
1064 Status
= STATUS_INVALID_INFO_CLASS
;
1067 /* Protect write with SEH */
1070 /* Check if caller wanted return length */
1071 if ((ReturnLength
) && (Length
)) *ReturnLength
= Length
;
1073 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1075 /* Get exception code */
1076 Status
= _SEH2_GetExceptionCode();
1088 NtSetInformationProcess(IN HANDLE ProcessHandle
,
1089 IN PROCESSINFOCLASS ProcessInformationClass
,
1090 IN PVOID ProcessInformation
,
1091 IN ULONG ProcessInformationLength
)
1094 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1097 HANDLE PortHandle
= NULL
;
1098 HANDLE TokenHandle
= NULL
;
1099 PROCESS_SESSION_INFORMATION SessionInfo
= {0};
1100 PROCESS_PRIORITY_CLASS PriorityClass
= {0};
1101 PROCESS_FOREGROUND_BACKGROUND Foreground
= {0};
1102 PVOID ExceptionPort
;
1104 KAFFINITY ValidAffinity
, Affinity
= 0;
1105 KPRIORITY BasePriority
= 0;
1106 UCHAR MemoryPriority
= 0;
1107 BOOLEAN DisableBoost
= 0;
1108 ULONG DefaultHardErrorMode
= 0;
1109 ULONG DebugFlags
= 0, EnableFixup
= 0, Boost
= 0;
1110 ULONG NoExecute
= 0, VdmPower
= 0;
1111 BOOLEAN HasPrivilege
;
1116 /* Verify Information Class validity */
1118 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
1120 RTL_NUMBER_OF(PsProcessInfoClass
),
1122 ProcessInformationLength
,
1124 if (!NT_SUCCESS(Status
)) return Status
;
1127 /* Check what class this is */
1128 Access
= PROCESS_SET_INFORMATION
;
1129 if (ProcessInformationClass
== ProcessSessionInformation
)
1131 /* Setting the Session ID needs a special mask */
1132 Access
|= PROCESS_SET_SESSIONID
;
1134 else if (ProcessInformationClass
== ProcessExceptionPort
)
1136 /* Setting the exception port needs a special mask */
1137 Access
|= PROCESS_SUSPEND_RESUME
;
1140 /* Reference the process */
1141 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1147 if (!NT_SUCCESS(Status
)) return Status
;
1149 /* Check what kind of information class this is */
1150 switch (ProcessInformationClass
)
1152 case ProcessWx86Information
:
1154 /* Check buffer length */
1155 if (ProcessInformationLength
!= sizeof(HANDLE
))
1157 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1161 /* Use SEH for capture */
1164 /* Capture the boolean */
1165 VdmPower
= *(PULONG
)ProcessInformation
;
1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1169 /* Get the exception code */
1170 Status
= _SEH2_GetExceptionCode();
1175 /* Getting VDM powers requires the SeTcbPrivilege */
1176 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1178 /* We don't hold the privilege, bail out */
1179 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1180 DPRINT1("Need TCB privilege\n");
1184 /* Set or clear the flag */
1187 PspSetProcessFlag(Process
, PSF_VDM_ALLOWED_BIT
);
1191 PspClearProcessFlag(Process
, PSF_VDM_ALLOWED_BIT
);
1195 /* Error/Exception Port */
1196 case ProcessExceptionPort
:
1198 /* Check buffer length */
1199 if (ProcessInformationLength
!= sizeof(HANDLE
))
1201 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1205 /* Use SEH for capture */
1208 /* Capture the handle */
1209 PortHandle
= *(PHANDLE
)ProcessInformation
;
1211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1213 /* Get the exception code */
1214 Status
= _SEH2_GetExceptionCode();
1219 /* Setting the error port requires the SeTcbPrivilege */
1220 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1222 /* We don't hold the privilege, bail out */
1223 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1227 /* Get the LPC Port */
1228 Status
= ObReferenceObjectByHandle(PortHandle
,
1232 (PVOID
)&ExceptionPort
,
1234 if (!NT_SUCCESS(Status
)) break;
1236 /* Change the pointer */
1237 if (InterlockedCompareExchangePointer(&Process
->ExceptionPort
,
1241 /* We already had one, fail */
1242 ObDereferenceObject(ExceptionPort
);
1243 Status
= STATUS_PORT_ALREADY_SET
;
1247 /* Security Token */
1248 case ProcessAccessToken
:
1250 /* Check buffer length */
1251 if (ProcessInformationLength
!= sizeof(PROCESS_ACCESS_TOKEN
))
1253 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1257 /* Use SEH for capture */
1260 /* Save the token handle */
1261 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->
1264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1266 /* Get the exception code */
1267 Status
= _SEH2_GetExceptionCode();
1272 /* Assign the actual token */
1273 Status
= PspSetPrimaryToken(Process
, TokenHandle
, NULL
);
1276 /* Hard error processing */
1277 case ProcessDefaultHardErrorMode
:
1279 /* Check buffer length */
1280 if (ProcessInformationLength
!= sizeof(ULONG
))
1282 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1286 /* Enter SEH for direct buffer read */
1289 DefaultHardErrorMode
= *(PULONG
)ProcessInformation
;
1291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1293 /* Get exception code */
1294 Status
= _SEH2_GetExceptionCode();
1300 Process
->DefaultHardErrorProcessing
= DefaultHardErrorMode
;
1302 /* Call Ke for the update */
1303 if (DefaultHardErrorMode
& SEM_NOALIGNMENTFAULTEXCEPT
)
1305 KeSetAutoAlignmentProcess(&Process
->Pcb
, TRUE
);
1309 KeSetAutoAlignmentProcess(&Process
->Pcb
, FALSE
);
1311 Status
= STATUS_SUCCESS
;
1315 case ProcessSessionInformation
:
1317 /* Check buffer length */
1318 if (ProcessInformationLength
!= sizeof(PROCESS_SESSION_INFORMATION
))
1320 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1324 /* Enter SEH for capture */
1327 /* Capture the caller's buffer */
1328 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
1330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1332 /* Get the exception code */
1333 Status
= _SEH2_GetExceptionCode();
1338 /* Setting the session id requires the SeTcbPrivilege */
1339 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1341 /* We don't hold the privilege, bail out */
1342 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1346 #if 0 // OLD AND DEPRECATED CODE!!!!
1348 /* FIXME - update the session id for the process token */
1349 //Status = PsLockProcess(Process, FALSE);
1350 if (!NT_SUCCESS(Status
)) break;
1352 /* Write the session ID in the EPROCESS */
1353 Process
->Session
= UlongToPtr(SessionInfo
.SessionId
); // HACK!!!
1355 /* Check if the process also has a PEB */
1359 * Attach to the process to make sure we're in the right
1360 * context to access the PEB structure
1362 KeAttachProcess(&Process
->Pcb
);
1364 /* Enter SEH for write to user-mode PEB */
1367 /* Write the session ID */
1368 Process
->Peb
->SessionId
= SessionInfo
.SessionId
;
1370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1372 /* Get exception code */
1373 Status
= _SEH2_GetExceptionCode();
1377 /* Detach from the process */
1381 /* Unlock the process */
1382 //PsUnlockProcess(Process);
1387 * Since we cannot change the session ID of the given
1388 * process anymore because it is set once and for all
1389 * at process creation time and because it is stored
1390 * inside the Process->Session structure managed by MM,
1391 * we fake changing it: we just return success if the
1392 * user-defined value is the same as the session ID of
1393 * the process, and otherwise we fail.
1395 if (SessionInfo
.SessionId
== PsGetProcessSessionId(Process
))
1397 Status
= STATUS_SUCCESS
;
1401 Status
= STATUS_ACCESS_DENIED
;
1406 case ProcessPriorityClass
:
1408 /* Check buffer length */
1409 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
1411 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1415 /* Enter SEH for capture */
1418 /* Capture the caller's buffer */
1419 PriorityClass
= *(PPROCESS_PRIORITY_CLASS
)ProcessInformation
;
1421 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1423 /* Return the exception code */
1424 Status
= _SEH2_GetExceptionCode();
1429 /* Check for invalid PriorityClass value */
1430 if (PriorityClass
.PriorityClass
> PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
)
1432 Status
= STATUS_INVALID_PARAMETER
;
1436 if ((PriorityClass
.PriorityClass
!= Process
->PriorityClass
) &&
1437 (PriorityClass
.PriorityClass
== PROCESS_PRIORITY_CLASS_REALTIME
))
1439 /* Check the privilege */
1440 HasPrivilege
= SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege
,
1442 PROCESS_SET_INFORMATION
,
1446 ObDereferenceObject(Process
);
1447 DPRINT1("Privilege to change priority to realtime lacking\n");
1448 return STATUS_PRIVILEGE_NOT_HELD
;
1452 /* Check if we have a job */
1455 DPRINT1("Jobs not yet supported\n");
1458 /* Set process priority class */
1459 Process
->PriorityClass
= PriorityClass
.PriorityClass
;
1461 /* Set process priority mode (foreground or background) */
1462 PsSetProcessPriorityByClass(Process
,
1463 PriorityClass
.Foreground
?
1464 PsProcessPriorityForeground
:
1465 PsProcessPriorityBackground
);
1466 Status
= STATUS_SUCCESS
;
1469 case ProcessForegroundInformation
:
1471 /* Check buffer length */
1472 if (ProcessInformationLength
!= sizeof(PROCESS_FOREGROUND_BACKGROUND
))
1474 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1478 /* Enter SEH for capture */
1481 /* Capture the caller's buffer */
1482 Foreground
= *(PPROCESS_FOREGROUND_BACKGROUND
)ProcessInformation
;
1484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1486 /* Return the exception code */
1487 Status
= _SEH2_GetExceptionCode();
1492 /* Set process priority mode (foreground or background) */
1493 PsSetProcessPriorityByClass(Process
,
1494 Foreground
.Foreground
?
1495 PsProcessPriorityForeground
:
1496 PsProcessPriorityBackground
);
1497 Status
= STATUS_SUCCESS
;
1500 case ProcessBasePriority
:
1502 /* Validate input length */
1503 if (ProcessInformationLength
!= sizeof(KPRIORITY
))
1505 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1509 /* Enter SEH for direct buffer read */
1512 BasePriority
= *(KPRIORITY
*)ProcessInformation
;
1514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1516 /* Get exception code */
1518 Status
= _SEH2_GetExceptionCode();
1523 /* Extract the memory priority out of there */
1524 if (BasePriority
& 0x80000000)
1526 MemoryPriority
= MEMORY_PRIORITY_FOREGROUND
;
1527 BasePriority
&= ~0x80000000;
1531 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
1534 /* Validate the number */
1535 if ((BasePriority
> HIGH_PRIORITY
) || (BasePriority
<= LOW_PRIORITY
))
1537 ObDereferenceObject(Process
);
1538 return STATUS_INVALID_PARAMETER
;
1541 /* Check if the new base is higher */
1542 if (BasePriority
> Process
->Pcb
.BasePriority
)
1544 HasPrivilege
= SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege
,
1546 PROCESS_SET_INFORMATION
,
1550 ObDereferenceObject(Process
);
1551 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority
, Process
->Pcb
.BasePriority
);
1552 return STATUS_PRIVILEGE_NOT_HELD
;
1557 KeSetPriorityAndQuantumProcess(&Process
->Pcb
, BasePriority
, 0);
1559 /* Now set the memory priority */
1560 MmSetMemoryPriorityProcess(Process
, MemoryPriority
);
1561 Status
= STATUS_SUCCESS
;
1564 case ProcessRaisePriority
:
1566 /* Validate input length */
1567 if (ProcessInformationLength
!= sizeof(ULONG
))
1569 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1573 /* Enter SEH for direct buffer read */
1576 Boost
= *(PULONG
)ProcessInformation
;
1578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1580 /* Get exception code */
1582 Status
= _SEH2_GetExceptionCode();
1587 /* Make sure the process isn't dying */
1588 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1591 KeEnterCriticalRegion();
1592 ExAcquirePushLockShared(&Process
->ProcessLock
);
1594 /* Loop the threads */
1595 for (Next
= Process
->ThreadListHead
.Flink
;
1596 Next
!= &Process
->ThreadListHead
;
1599 /* Call Ke for the thread */
1600 Thread
= CONTAINING_RECORD(Next
, ETHREAD
, ThreadListEntry
);
1601 KeBoostPriorityThread(&Thread
->Tcb
, Boost
);
1604 /* Release the lock and rundown */
1605 ExReleasePushLockShared(&Process
->ProcessLock
);
1606 KeLeaveCriticalRegion();
1607 ExReleaseRundownProtection(&Process
->RundownProtect
);
1609 /* Set success code */
1610 Status
= STATUS_SUCCESS
;
1614 /* Avoid race conditions */
1615 Status
= STATUS_PROCESS_IS_TERMINATING
;
1619 case ProcessBreakOnTermination
:
1621 /* Check buffer length */
1622 if (ProcessInformationLength
!= sizeof(ULONG
))
1624 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1628 /* Enter SEH for direct buffer read */
1631 Break
= *(PULONG
)ProcessInformation
;
1633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1635 /* Get exception code */
1637 Status
= _SEH2_GetExceptionCode();
1642 /* Setting 'break on termination' requires the SeDebugPrivilege */
1643 if (!SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1645 /* We don't hold the privilege, bail out */
1646 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1650 /* Set or clear the flag */
1653 PspSetProcessFlag(Process
, PSF_BREAK_ON_TERMINATION_BIT
);
1657 PspClearProcessFlag(Process
, PSF_BREAK_ON_TERMINATION_BIT
);
1662 case ProcessAffinityMask
:
1664 /* Check buffer length */
1665 if (ProcessInformationLength
!= sizeof(KAFFINITY
))
1667 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1671 /* Enter SEH for direct buffer read */
1674 Affinity
= *(PKAFFINITY
)ProcessInformation
;
1676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1678 /* Get exception code */
1680 Status
= _SEH2_GetExceptionCode();
1685 /* Make sure it's valid for the CPUs present */
1686 ValidAffinity
= Affinity
& KeActiveProcessors
;
1687 if (!Affinity
|| (ValidAffinity
!= Affinity
))
1689 Status
= STATUS_INVALID_PARAMETER
;
1693 /* Check if it's within job affinity limits */
1696 /* Not yet implemented */
1698 Status
= STATUS_NOT_IMPLEMENTED
;
1702 /* Make sure the process isn't dying */
1703 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1706 KeEnterCriticalRegion();
1707 ExAcquirePushLockShared(&Process
->ProcessLock
);
1709 /* Call Ke to do the work */
1710 KeSetAffinityProcess(&Process
->Pcb
, ValidAffinity
);
1712 /* Release the lock and rundown */
1713 ExReleasePushLockShared(&Process
->ProcessLock
);
1714 KeLeaveCriticalRegion();
1715 ExReleaseRundownProtection(&Process
->RundownProtect
);
1717 /* Set success code */
1718 Status
= STATUS_SUCCESS
;
1722 /* Avoid race conditions */
1723 Status
= STATUS_PROCESS_IS_TERMINATING
;
1727 /* Priority Boosting status */
1728 case ProcessPriorityBoost
:
1730 /* Validate input length */
1731 if (ProcessInformationLength
!= sizeof(ULONG
))
1733 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1737 /* Enter SEH for direct buffer read */
1740 DisableBoost
= *(PBOOLEAN
)ProcessInformation
;
1742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1744 /* Get exception code */
1746 Status
= _SEH2_GetExceptionCode();
1751 /* Make sure the process isn't dying */
1752 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
1755 KeEnterCriticalRegion();
1756 ExAcquirePushLockShared(&Process
->ProcessLock
);
1758 /* Call Ke to do the work */
1759 KeSetDisableBoostProcess(&Process
->Pcb
, DisableBoost
);
1761 /* Loop the threads too */
1762 for (Next
= Process
->ThreadListHead
.Flink
;
1763 Next
!= &Process
->ThreadListHead
;
1766 /* Call Ke for the thread */
1767 Thread
= CONTAINING_RECORD(Next
, ETHREAD
, ThreadListEntry
);
1768 KeSetDisableBoostThread(&Thread
->Tcb
, DisableBoost
);
1771 /* Release the lock and rundown */
1772 ExReleasePushLockShared(&Process
->ProcessLock
);
1773 KeLeaveCriticalRegion();
1774 ExReleaseRundownProtection(&Process
->RundownProtect
);
1776 /* Set success code */
1777 Status
= STATUS_SUCCESS
;
1781 /* Avoid race conditions */
1782 Status
= STATUS_PROCESS_IS_TERMINATING
;
1786 case ProcessDebugFlags
:
1788 /* Check buffer length */
1789 if (ProcessInformationLength
!= sizeof(ULONG
))
1791 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1795 /* Enter SEH for direct buffer read */
1798 DebugFlags
= *(PULONG
)ProcessInformation
;
1800 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1802 /* Get exception code */
1803 Status
= _SEH2_GetExceptionCode();
1809 if (DebugFlags
& ~1)
1811 Status
= STATUS_INVALID_PARAMETER
;
1817 PspClearProcessFlag(Process
, PSF_NO_DEBUG_INHERIT_BIT
);
1821 PspSetProcessFlag(Process
, PSF_NO_DEBUG_INHERIT_BIT
);
1826 Status
= STATUS_SUCCESS
;
1829 case ProcessEnableAlignmentFaultFixup
:
1831 /* Check buffer length */
1832 if (ProcessInformationLength
!= sizeof(ULONG
))
1834 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1838 /* Enter SEH for direct buffer read */
1841 EnableFixup
= *(PULONG
)ProcessInformation
;
1843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1845 /* Get exception code */
1846 Status
= _SEH2_GetExceptionCode();
1854 Process
->DefaultHardErrorProcessing
|= SEM_NOALIGNMENTFAULTEXCEPT
;
1858 Process
->DefaultHardErrorProcessing
&= ~SEM_NOALIGNMENTFAULTEXCEPT
;
1861 /* Call Ke for the update */
1862 KeSetAutoAlignmentProcess(&Process
->Pcb
, FALSE
);
1863 Status
= STATUS_SUCCESS
;
1866 case ProcessUserModeIOPL
:
1868 /* Only TCB can do this */
1869 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1871 /* We don't hold the privilege, bail out */
1872 DPRINT1("Need TCB to set IOPL\n");
1873 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1877 /* Only supported on x86 */
1881 Status
= STATUS_NOT_IMPLEMENTED
;
1886 case ProcessExecuteFlags
:
1888 /* Check buffer length */
1889 if (ProcessInformationLength
!= sizeof(ULONG
))
1891 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1895 if (ProcessHandle
!= NtCurrentProcess())
1897 Status
= STATUS_INVALID_PARAMETER
;
1901 /* Enter SEH for direct buffer read */
1904 NoExecute
= *(PULONG
)ProcessInformation
;
1906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1908 /* Get exception code */
1909 Status
= _SEH2_GetExceptionCode();
1914 /* Call Mm for the update */
1915 Status
= MmSetExecuteOptions(NoExecute
);
1918 /* We currently don't implement any of these */
1919 case ProcessLdtInformation
:
1920 case ProcessLdtSize
:
1921 case ProcessIoPortHandlers
:
1922 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass
);
1923 Status
= STATUS_NOT_IMPLEMENTED
;
1926 case ProcessQuotaLimits
:
1928 Status
= PspSetQuotaLimits(Process
,
1931 ProcessInformationLength
,
1935 case ProcessWorkingSetWatch
:
1936 DPRINT1("WS watch not implemented\n");
1937 Status
= STATUS_NOT_IMPLEMENTED
;
1940 case ProcessDeviceMap
:
1941 DPRINT1("Device map not implemented\n");
1942 Status
= STATUS_NOT_IMPLEMENTED
;
1945 case ProcessHandleTracing
:
1946 DPRINT1("Handle tracing not implemented\n");
1947 Status
= STATUS_NOT_IMPLEMENTED
;
1950 /* Anything else is invalid */
1952 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass
);
1953 Status
= STATUS_INVALID_INFO_CLASS
;
1956 /* Dereference and return status */
1957 ObDereferenceObject(Process
);
1966 NtSetInformationThread(IN HANDLE ThreadHandle
,
1967 IN THREADINFOCLASS ThreadInformationClass
,
1968 IN PVOID ThreadInformation
,
1969 IN ULONG ThreadInformationLength
)
1973 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1975 HANDLE TokenHandle
= NULL
;
1976 KPRIORITY Priority
= 0;
1977 KAFFINITY Affinity
= 0, CombinedAffinity
;
1978 PVOID Address
= NULL
;
1980 ULONG_PTR DisableBoost
= 0;
1981 ULONG_PTR IdealProcessor
= 0;
1982 ULONG_PTR Break
= 0;
1984 ULONG_PTR TlsIndex
= 0;
1985 PVOID
*ExpansionSlots
;
1986 PETHREAD ProcThread
;
1989 /* Verify Information Class validity */
1991 Status
= DefaultSetInfoBufferCheck(ThreadInformationClass
,
1993 RTL_NUMBER_OF(PsThreadInfoClass
),
1995 ThreadInformationLength
,
1997 if (!NT_SUCCESS(Status
)) return Status
;
2000 /* Check what class this is */
2001 Access
= THREAD_SET_INFORMATION
;
2002 if (ThreadInformationClass
== ThreadImpersonationToken
)
2004 /* Setting the impersonation token needs a special mask */
2005 Access
= THREAD_SET_THREAD_TOKEN
;
2008 /* Reference the thread */
2009 Status
= ObReferenceObjectByHandle(ThreadHandle
,
2015 if (!NT_SUCCESS(Status
)) return Status
;
2017 /* Check what kind of information class this is */
2018 switch (ThreadInformationClass
)
2020 /* Thread priority */
2021 case ThreadPriority
:
2023 /* Check buffer length */
2024 if (ThreadInformationLength
!= sizeof(KPRIORITY
))
2026 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2030 /* Use SEH for capture */
2033 /* Get the priority */
2034 Priority
= *(PLONG
)ThreadInformation
;
2036 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2038 /* Get the exception code */
2039 Status
= _SEH2_GetExceptionCode();
2045 if ((Priority
> HIGH_PRIORITY
) ||
2046 (Priority
<= LOW_PRIORITY
))
2049 Status
= STATUS_INVALID_PARAMETER
;
2053 /* Set the priority */
2054 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
2057 case ThreadBasePriority
:
2059 /* Check buffer length */
2060 if (ThreadInformationLength
!= sizeof(LONG
))
2062 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2066 /* Use SEH for capture */
2069 /* Get the priority */
2070 Priority
= *(PLONG
)ThreadInformation
;
2072 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2074 /* Get the exception code */
2075 Status
= _SEH2_GetExceptionCode();
2081 if ((Priority
> THREAD_BASE_PRIORITY_MAX
) ||
2082 (Priority
< THREAD_BASE_PRIORITY_MIN
))
2084 /* These ones are OK */
2085 if ((Priority
!= THREAD_BASE_PRIORITY_LOWRT
+ 1) &&
2086 (Priority
!= THREAD_BASE_PRIORITY_IDLE
- 1))
2088 /* Check if the process is real time */
2089 if (PsGetCurrentProcess()->PriorityClass
!=
2090 PROCESS_PRIORITY_CLASS_REALTIME
)
2092 /* It isn't, fail */
2093 Status
= STATUS_INVALID_PARAMETER
;
2099 /* Set the base priority */
2100 KeSetBasePriorityThread(&Thread
->Tcb
, Priority
);
2103 case ThreadAffinityMask
:
2105 /* Check buffer length */
2106 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2108 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2112 /* Use SEH for capture */
2115 /* Get the priority */
2116 Affinity
= *(PULONG_PTR
)ThreadInformation
;
2118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2120 /* Get the exception code */
2121 Status
= _SEH2_GetExceptionCode();
2130 Status
= STATUS_INVALID_PARAMETER
;
2134 /* Get the process */
2135 Process
= Thread
->ThreadsProcess
;
2137 /* Try to acquire rundown */
2138 if (ExAcquireRundownProtection(&Process
->RundownProtect
))
2141 KeEnterCriticalRegion();
2142 ExAcquirePushLockShared(&Process
->ProcessLock
);
2145 CombinedAffinity
= Affinity
& Process
->Pcb
.Affinity
;
2146 if (CombinedAffinity
!= Affinity
)
2149 Status
= STATUS_INVALID_PARAMETER
;
2153 /* Set the affinity */
2154 KeSetAffinityThread(&Thread
->Tcb
, CombinedAffinity
);
2157 /* Release the lock and rundown */
2158 ExReleasePushLockShared(&Process
->ProcessLock
);
2159 KeLeaveCriticalRegion();
2160 ExReleaseRundownProtection(&Process
->RundownProtect
);
2165 Status
= STATUS_PROCESS_IS_TERMINATING
;
2171 case ThreadImpersonationToken
:
2173 /* Check buffer length */
2174 if (ThreadInformationLength
!= sizeof(HANDLE
))
2176 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2180 /* Use SEH for capture */
2183 /* Save the token handle */
2184 TokenHandle
= *(PHANDLE
)ThreadInformation
;
2186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2188 /* Get the exception code */
2189 Status
= _SEH2_GetExceptionCode();
2194 /* Assign the actual token */
2195 Status
= PsAssignImpersonationToken(Thread
, TokenHandle
);
2198 case ThreadQuerySetWin32StartAddress
:
2200 /* Check buffer length */
2201 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2203 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2207 /* Use SEH for capture */
2210 /* Get the priority */
2211 Address
= *(PVOID
*)ThreadInformation
;
2213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2215 /* Get the exception code */
2216 Status
= _SEH2_GetExceptionCode();
2221 /* Set the address */
2222 Thread
->Win32StartAddress
= Address
;
2225 case ThreadIdealProcessor
:
2227 /* Check buffer length */
2228 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2230 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2234 /* Use SEH for capture */
2237 /* Get the priority */
2238 IdealProcessor
= *(PULONG_PTR
)ThreadInformation
;
2240 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2242 /* Get the exception code */
2243 Status
= _SEH2_GetExceptionCode();
2249 if (IdealProcessor
> MAXIMUM_PROCESSORS
)
2252 Status
= STATUS_INVALID_PARAMETER
;
2257 Status
= KeSetIdealProcessorThread(&Thread
->Tcb
,
2258 (CCHAR
)IdealProcessor
);
2260 /* Get the TEB and protect the thread */
2261 Teb
= Thread
->Tcb
.Teb
;
2262 if ((Teb
) && (ExAcquireRundownProtection(&Thread
->RundownProtect
)))
2264 /* Save the ideal processor */
2265 Teb
->IdealProcessor
= Thread
->Tcb
.IdealProcessor
;
2267 /* Release rundown protection */
2268 ExReleaseRundownProtection(&Thread
->RundownProtect
);
2273 case ThreadPriorityBoost
:
2275 /* Check buffer length */
2276 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2278 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2282 /* Use SEH for capture */
2285 /* Get the priority */
2286 DisableBoost
= *(PULONG_PTR
)ThreadInformation
;
2288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2290 /* Get the exception code */
2291 Status
= _SEH2_GetExceptionCode();
2296 /* Call the kernel */
2297 KeSetDisableBoostThread(&Thread
->Tcb
, (BOOLEAN
)DisableBoost
);
2300 case ThreadZeroTlsCell
:
2302 /* Check buffer length */
2303 if (ThreadInformationLength
!= sizeof(ULONG_PTR
))
2305 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2309 /* Use SEH for capture */
2312 /* Get the priority */
2313 TlsIndex
= *(PULONG_PTR
)ThreadInformation
;
2315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2317 /* Get the exception code */
2318 Status
= _SEH2_GetExceptionCode();
2323 /* This is only valid for the current thread */
2324 if (Thread
!= PsGetCurrentThread())
2327 Status
= STATUS_INVALID_PARAMETER
;
2331 /* Get the process */
2332 Process
= Thread
->ThreadsProcess
;
2334 /* Loop the threads */
2335 ProcThread
= PsGetNextProcessThread(Process
, NULL
);
2338 /* Acquire rundown */
2339 if (ExAcquireRundownProtection(&ProcThread
->RundownProtect
))
2342 Teb
= ProcThread
->Tcb
.Teb
;
2345 /* Check if we're in the expansion range */
2346 if (TlsIndex
> TLS_MINIMUM_AVAILABLE
- 1)
2348 if (TlsIndex
< (TLS_MINIMUM_AVAILABLE
+
2349 TLS_EXPANSION_SLOTS
) - 1)
2351 /* Check if we have expansion slots */
2352 ExpansionSlots
= Teb
->TlsExpansionSlots
;
2355 /* Clear the index */
2356 ExpansionSlots
[TlsIndex
- TLS_MINIMUM_AVAILABLE
] = 0;
2362 /* Clear the index */
2363 Teb
->TlsSlots
[TlsIndex
] = NULL
;
2367 /* Release rundown */
2368 ExReleaseRundownProtection(&ProcThread
->RundownProtect
);
2371 /* Go to the next thread */
2372 ProcThread
= PsGetNextProcessThread(Process
, ProcThread
);
2378 case ThreadBreakOnTermination
:
2380 /* Check buffer length */
2381 if (ThreadInformationLength
!= sizeof(ULONG
))
2383 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2387 /* Enter SEH for direct buffer read */
2390 Break
= *(PULONG
)ThreadInformation
;
2392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2394 /* Get exception code */
2396 Status
= _SEH2_GetExceptionCode();
2401 /* Setting 'break on termination' requires the SeDebugPrivilege */
2402 if (!SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
2404 /* We don't hold the privilege, bail out */
2405 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2409 /* Set or clear the flag */
2412 PspSetCrossThreadFlag(Thread
, CT_BREAK_ON_TERMINATION_BIT
);
2416 PspClearCrossThreadFlag(Thread
, CT_BREAK_ON_TERMINATION_BIT
);
2421 /* We don't implement it yet */
2422 DPRINT1("Not implemented: %d\n", ThreadInformationClass
);
2423 Status
= STATUS_NOT_IMPLEMENTED
;
2426 /* Dereference and return status */
2427 ObDereferenceObject(Thread
);
2436 NtQueryInformationThread(IN HANDLE ThreadHandle
,
2437 IN THREADINFOCLASS ThreadInformationClass
,
2438 OUT PVOID ThreadInformation
,
2439 IN ULONG ThreadInformationLength
,
2440 OUT PULONG ReturnLength OPTIONAL
)
2443 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
2447 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
=
2448 (PTHREAD_BASIC_INFORMATION
)ThreadInformation
;
2449 PKERNEL_USER_TIMES ThreadTime
= (PKERNEL_USER_TIMES
)ThreadInformation
;
2451 ULONG ThreadTerminated
;
2454 /* Check if we were called from user mode */
2455 if (PreviousMode
!= KernelMode
)
2460 /* Probe the buffer */
2461 ProbeForWrite(ThreadInformation
,
2462 ThreadInformationLength
,
2465 /* Probe the return length if required */
2466 if (ReturnLength
) ProbeForWriteUlong(ReturnLength
);
2468 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2470 /* Return the exception code */
2471 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2476 /* Check what class this is */
2477 Access
= THREAD_QUERY_INFORMATION
;
2479 /* Reference the process */
2480 Status
= ObReferenceObjectByHandle(ThreadHandle
,
2486 if (!NT_SUCCESS(Status
)) return Status
;
2488 /* Check what kind of information class this is */
2489 switch (ThreadInformationClass
)
2491 /* Basic thread information */
2492 case ThreadBasicInformation
:
2494 /* Set return length */
2495 Length
= sizeof(THREAD_BASIC_INFORMATION
);
2497 if (ThreadInformationLength
!= Length
)
2499 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2502 /* Protect writes with SEH */
2505 /* Write all the information from the ETHREAD/KTHREAD */
2506 ThreadBasicInfo
->ExitStatus
= Thread
->ExitStatus
;
2507 ThreadBasicInfo
->TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
2508 ThreadBasicInfo
->ClientId
= Thread
->Cid
;
2509 ThreadBasicInfo
->AffinityMask
= Thread
->Tcb
.Affinity
;
2510 ThreadBasicInfo
->Priority
= Thread
->Tcb
.Priority
;
2511 ThreadBasicInfo
->BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
2513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2515 /* Get exception code */
2516 Status
= _SEH2_GetExceptionCode();
2521 /* Thread time information */
2524 /* Set the return length */
2525 Length
= sizeof(KERNEL_USER_TIMES
);
2527 if (ThreadInformationLength
!= Length
)
2529 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2532 /* Protect writes with SEH */
2535 /* Copy time information from ETHREAD/KTHREAD */
2536 ThreadTime
->KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
* KeMaximumIncrement
;
2537 ThreadTime
->UserTime
.QuadPart
= Thread
->Tcb
.UserTime
* KeMaximumIncrement
;
2538 ThreadTime
->CreateTime
= Thread
->CreateTime
;
2540 /* Exit time is in a union and only valid on actual exit! */
2541 if (KeReadStateThread(&Thread
->Tcb
))
2543 ThreadTime
->ExitTime
= Thread
->ExitTime
;
2547 ThreadTime
->ExitTime
.QuadPart
= 0;
2550 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2552 /* Get exception code */
2553 Status
= _SEH2_GetExceptionCode();
2558 case ThreadQuerySetWin32StartAddress
:
2560 /* Set the return length*/
2561 Length
= sizeof(PVOID
);
2563 if (ThreadInformationLength
!= Length
)
2565 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2568 /* Protect write with SEH */
2571 /* Return the Win32 Start Address */
2572 *(PVOID
*)ThreadInformation
= Thread
->Win32StartAddress
;
2574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2576 /* Get exception code */
2577 Status
= _SEH2_GetExceptionCode();
2582 case ThreadPerformanceCount
:
2584 /* Set the return length*/
2585 Length
= sizeof(LARGE_INTEGER
);
2587 if (ThreadInformationLength
!= Length
)
2589 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2592 /* Protect write with SEH */
2596 (*(PLARGE_INTEGER
)ThreadInformation
).QuadPart
= 0;
2598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2600 /* Get exception code */
2601 Status
= _SEH2_GetExceptionCode();
2606 case ThreadAmILastThread
:
2608 /* Set the return length*/
2609 Length
= sizeof(ULONG
);
2611 if (ThreadInformationLength
!= Length
)
2613 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2616 /* Protect write with SEH */
2619 /* Return whether or not we are the last thread */
2620 *(PULONG
)ThreadInformation
= ((Thread
->ThreadsProcess
->
2621 ThreadListHead
.Flink
->Flink
==
2622 &Thread
->ThreadsProcess
->
2626 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2628 /* Get exception code */
2629 Status
= _SEH2_GetExceptionCode();
2634 case ThreadIsIoPending
:
2636 /* Set the return length*/
2637 Length
= sizeof(ULONG
);
2639 if (ThreadInformationLength
!= Length
)
2641 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2644 /* Raise the IRQL to protect the IRP list */
2645 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2647 /* Protect write with SEH */
2650 /* Check if the IRP list is empty or not */
2651 *(PULONG
)ThreadInformation
= !IsListEmpty(&Thread
->IrpList
);
2653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2655 /* Get exception code */
2656 Status
= _SEH2_GetExceptionCode();
2660 /* Lower IRQL back */
2661 KeLowerIrql(OldIrql
);
2664 /* LDT and GDT information */
2665 case ThreadDescriptorTableEntry
:
2668 /* Call the worker routine */
2669 Status
= PspQueryDescriptorThread(Thread
,
2671 ThreadInformationLength
,
2674 /* Only implemented on x86 */
2675 Status
= STATUS_NOT_IMPLEMENTED
;
2679 case ThreadPriorityBoost
:
2681 /* Set the return length*/
2682 Length
= sizeof(ULONG
);
2684 if (ThreadInformationLength
!= Length
)
2686 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2692 *(PULONG
)ThreadInformation
= Thread
->Tcb
.DisableBoost
? 1 : 0;
2694 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2696 Status
= _SEH2_GetExceptionCode();
2701 case ThreadIsTerminated
:
2703 /* Set the return length*/
2704 Length
= sizeof(ThreadTerminated
);
2706 if (ThreadInformationLength
!= Length
)
2708 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2712 ThreadTerminated
= PsIsThreadTerminating(Thread
);
2716 *(PULONG
)ThreadInformation
= ThreadTerminated
? 1 : 0;
2718 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2720 Status
= _SEH2_GetExceptionCode();
2729 /* Not yet implemented */
2730 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
2731 Status
= STATUS_NOT_IMPLEMENTED
;
2734 /* Protect write with SEH */
2737 /* Check if caller wanted return length */
2738 if (ReturnLength
) *ReturnLength
= Length
;
2740 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2742 /* Get exception code */
2743 Status
= _SEH2_GetExceptionCode();
2747 /* Dereference the thread, and return */
2748 ObDereferenceObject(Thread
);