/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ps/query.c
- * PURPOSE: Set/Query Process/Thread Information APIs
- *
- * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File
- * David Welch
+ * PURPOSE: Process Manager: Thread/Process Query/Set Information
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * Thomas Weidenmueller (w3seek@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
-/* GLOBALS ******************************************************************/
+/* Include Information Class Tables */
+#include "internal/ps_i.h"
-static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
+/* Debugging Level */
+ULONG PspTraceLevel = 0;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+NTSTATUS
+NTAPI
+PsReferenceProcessFilePointer(IN PEPROCESS Process,
+ OUT PFILE_OBJECT *FileObject)
{
- ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */
- ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */
- ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */
- ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */
- ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */
- ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */
- ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY ), /* ProcessDebugPort */
- ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */
- ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */
- ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */
- ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */
- ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */
- ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */
- ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */
- ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */
- ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */
- ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */
- ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */
-
- ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */
- /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
- /*Q*/ sizeof(ULONG),
- /*S*/ sizeof(ULONG),
- ICIF_QUERY | ICIF_SET ),
-
- ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */
- ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */
- ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */
-
- /* FIXME */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
- ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
-
- ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */
-};
+ PSECTION Section;
+ PAGED_CODE();
+
+ /* Lock the process */
+ ExAcquireRundownProtection(&Process->RundownProtect);
+
+ /* Get the section */
+ Section = Process->SectionObject;
+ if (Section)
+ {
+ /* Get the file object and reference it */
+ *FileObject = MmGetFileObjectForSection((PVOID)Section);
+ ObReferenceObject(*FileObject);
+ }
+
+ /* Release the protection */
+ ExReleaseRundownProtection(&Process->RundownProtect);
+
+ /* Return status */
+ return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
/*
- * FIXME:
- * Remove the Implemented value if all functions are implemented.
+ * @implemented
*/
-
-static const struct
-{
- BOOLEAN Implemented;
- ULONG Size;
-} QueryInformationData[MaxThreadInfoClass + 1] =
-{
- {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation
- {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes
- {TRUE, 0}, // ThreadPriority
- {TRUE, 0}, // ThreadBasePriority
- {TRUE, 0}, // ThreadAffinityMask
- {TRUE, 0}, // ThreadImpersonationToken
- {FALSE, 0}, // ThreadDescriptorTableEntry
- {TRUE, 0}, // ThreadEnableAlignmentFaultFixup
- {TRUE, 0}, // ThreadEventPair
- {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
- {TRUE, 0}, // ThreadZeroTlsCell
- {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount
- {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread
- {TRUE, 0}, // ThreadIdealProcessor
- {FALSE, 0}, // ThreadPriorityBoost
- {TRUE, 0}, // ThreadSetTlsArrayAddress
- {FALSE, 0}, // ThreadIsIoPending
- {TRUE, 0} // ThreadHideFromDebugger
-};
-
-static const struct
+NTSTATUS
+NTAPI
+NtQueryInformationProcess(IN HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ OUT PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength,
+ OUT PULONG ReturnLength OPTIONAL)
{
- BOOLEAN Implemented;
- ULONG Size;
-} SetInformationData[MaxThreadInfoClass + 1] =
+ PEPROCESS Process;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Length = 0;
+ PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
+ (PPROCESS_BASIC_INFORMATION)ProcessInformation;
+ PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
+ PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
+ ULONG HandleCount;
+ PPROCESS_SESSION_INFORMATION SessionInfo =
+ (PPROCESS_SESSION_INFORMATION)ProcessInformation;
+ PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
+ PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
+ PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
+ PROCESS_DEVICEMAP_INFORMATION DeviceMap;
+ PUNICODE_STRING ImageName;
+ ULONG Cookie;
+ PAGED_CODE();
+
+ /* Check validity of Information Class */
+#if 0
+ Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
+ PsProcessInfoClass,
+ RTL_NUMBER_OF(PsProcessInfoClass),
+ ProcessInformation,
+ ProcessInformationLength,
+ ReturnLength,
+ PreviousMode);
+ if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+ if((ProcessInformationClass == ProcessCookie) &&
+ (ProcessHandle != NtCurrentProcess()))
+ {
+ /*
+ * Retreiving the process cookie is only allowed for the calling process
+ * itself! XP only allowes NtCurrentProcess() as process handles even if
+ * a real handle actually represents the current process.
+ */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check the information class */
+ switch (ProcessInformationClass)
+ {
+ /* Basic process information */
+ case ProcessBasicInformation:
+
+ /* Set return length */
+ Length = sizeof(PROCESS_BASIC_INFORMATION);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Protect writes with SEH */
+ _SEH2_TRY
+ {
+ /* Write all the information from the EPROCESS/KPROCESS */
+ ProcessBasicInfo->ExitStatus = Process->ExitStatus;
+ ProcessBasicInfo->PebBaseAddress = Process->Peb;
+ ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
+ ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
+ UniqueProcessId;
+ ProcessBasicInfo->InheritedFromUniqueProcessId =
+ (ULONG)Process->InheritedFromUniqueProcessId;
+ ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Process quota limits */
+ case ProcessQuotaLimits:
+
+ Length = sizeof(QUOTA_LIMITS);
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Indicate success */
+ Status = STATUS_SUCCESS;
+
+ _SEH2_TRY
+ {
+ /* Set max/min working set sizes */
+ QuotaLimits->MaximumWorkingSetSize =
+ Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
+ QuotaLimits->MinimumWorkingSetSize =
+ Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
+
+ /* Set default time limits */
+ QuotaLimits->TimeLimit.LowPart = (ULONG)-1;
+ QuotaLimits->TimeLimit.HighPart = (ULONG)-1;
+
+ /* Is quota block a default one? */
+ if (Process->QuotaBlock == &PspDefaultQuotaBlock)
+ {
+ /* Set default pools and pagefile limits */
+ QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
+ QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
+ QuotaLimits->PagefileLimit = (SIZE_T)-1;
+ }
+ else
+ {
+ /* Get limits from non-default quota block */
+ QuotaLimits->PagedPoolLimit =
+ Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
+ QuotaLimits->NonPagedPoolLimit =
+ Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
+ QuotaLimits->PagefileLimit =
+ Process->QuotaBlock->QuotaEntry[2].Limit;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ case ProcessIoCounters:
+
+ Length = sizeof(IO_COUNTERS);
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ _SEH2_TRY
+ {
+ IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
+ IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
+ IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
+ IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
+ IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
+ IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Ignore exception */
+ }
+ _SEH2_END;
+
+ /* Set status to success in any case */
+ Status = STATUS_SUCCESS;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Timing */
+ case ProcessTimes:
+
+ /* Set the return length */
+ Length = sizeof(KERNEL_USER_TIMES);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Protect writes with SEH */
+ _SEH2_TRY
+ {
+ /* Copy time information from EPROCESS/KPROCESS */
+ ProcessTime->CreateTime = Process->CreateTime;
+ ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
+ 100000LL;
+ ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
+ 100000LL;
+ ProcessTime->ExitTime = Process->ExitTime;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Process Debug Port */
+ case ProcessDebugPort:
+
+ /* Set return length */
+ Length = sizeof(HANDLE);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Protect write with SEH */
+ _SEH2_TRY
+ {
+ /* Return whether or not we have a debug port */
+ *(PHANDLE)ProcessInformation = (Process->DebugPort ?
+ (HANDLE)-1 : NULL);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* LDT, WS and VDM Information: not implemented */
+ case ProcessLdtInformation:
+ case ProcessWorkingSetWatch:
+ case ProcessWx86Information:
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case ProcessHandleCount:
+
+ /* Set the return length*/
+ Length = sizeof(ULONG);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Count the number of handles this process has */
+ HandleCount = ObGetProcessHandleCount(Process);
+
+ /* Protect write in SEH */
+ _SEH2_TRY
+ {
+ /* Return the count of handles */
+ *(PULONG)ProcessInformation = HandleCount;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Session ID for the process */
+ case ProcessSessionInformation:
+
+ /* Set the return length*/
+ Length = sizeof(PROCESS_SESSION_INFORMATION);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Enter SEH for write safety */
+ _SEH2_TRY
+ {
+ /* Write back the Session ID */
+ SessionInfo->SessionId = Process->Session;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* WOW64: Not implemented */
+ case ProcessWow64Information:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ /* Virtual Memory Statistics */
+ case ProcessVmCounters:
+
+ /* Set the return length */
+ Length = sizeof(VM_COUNTERS);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Enter SEH for write safety */
+ _SEH2_TRY
+ {
+ /* Return data from EPROCESS */
+ VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
+ VmCounters->VirtualSize = Process->VirtualSize;
+ VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
+ VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
+ VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
+ VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
+ VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
+ VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
+ VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
+ VmCounters->PagefileUsage = Process->QuotaUsage[2];
+ VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Hard Error Processing Mode */
+ case ProcessDefaultHardErrorMode:
+
+ /* Set the return length*/
+ Length = sizeof(ULONG);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Enter SEH for writing back data */
+ _SEH2_TRY
+ {
+ /* Write the current processing mode */
+ *(PULONG)ProcessInformation = Process->
+ DefaultHardErrorProcessing;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Priority Boosting status */
+ case ProcessPriorityBoost:
+
+ /* Set the return length*/
+ Length = sizeof(ULONG);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Enter SEH for writing back data */
+ _SEH2_TRY
+ {
+ /* Return boost status */
+ *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
+ TRUE : FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* DOS Device Map */
+ case ProcessDeviceMap:
+
+ /* Set the return length*/
+ Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Query the device map information */
+ ObQueryDeviceMapInformation(Process, &DeviceMap);
+
+ /* Enter SEH for writing back data */
+ _SEH2_TRY
+ {
+ *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Priority class */
+ case ProcessPriorityClass:
+
+ /* Set the return length*/
+ Length = sizeof(PROCESS_PRIORITY_CLASS);
+
+ if (ProcessInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Enter SEH for writing back data */
+ _SEH2_TRY
+ {
+ /* Return current priority class */
+ PsPriorityClass->PriorityClass = Process->PriorityClass;
+ PsPriorityClass->Foreground = FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ case ProcessImageFileName:
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Get the image path */
+ Status = SeLocateProcessImageName(Process, &ImageName);
+ if (NT_SUCCESS(Status))
+ {
+ /* Set return length */
+ Length = ImageName->MaximumLength +
+ sizeof(OBJECT_NAME_INFORMATION);
+
+ /* Make sure it's large enough */
+ if (Length <= ProcessInformationLength)
+ {
+ /* Enter SEH to protect write */
+ _SEH2_TRY
+ {
+ /* Copy it */
+ RtlCopyMemory(ProcessInformation,
+ ImageName,
+ Length);
+
+ /* Update pointer */
+ ((PUNICODE_STRING)ProcessInformation)->Buffer =
+ (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ /* Buffer too small */
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ /* Free the image path */
+ ExFreePool(ImageName);
+ }
+ /* Dereference the process */
+ ObDereferenceObject(Process);
+ break;
+
+ /* Per-process security cookie */
+ case ProcessCookie:
+
+ /* Get the current process and cookie */
+ Process = PsGetCurrentProcess();
+ Cookie = Process->Cookie;
+ if (!Cookie)
+ {
+ LARGE_INTEGER SystemTime;
+ ULONG NewCookie;
+ PKPRCB Prcb;
+
+ /* Generate a new cookie */
+ KeQuerySystemTime(&SystemTime);
+ Prcb = KeGetCurrentPrcb();
+ NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
+ SystemTime.u.LowPart ^ SystemTime.u.HighPart;
+
+ /* Set the new cookie or return the current one */
+ Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
+ NewCookie,
+ Cookie);
+ if (!Cookie) Cookie = NewCookie;
+
+ /* Set return length */
+ Length = sizeof(ULONG);
+ }
+
+ /* Enter SEH to protect write */
+ _SEH2_TRY
+ {
+ /* Write back the cookie */
+ *(PULONG)ProcessInformation = Cookie;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
+
+ /* Not yet implemented, or unknown */
+ case ProcessBasePriority:
+ case ProcessRaisePriority:
+ case ProcessExceptionPort:
+ case ProcessAccessToken:
+ case ProcessLdtSize:
+ case ProcessIoPortHandlers:
+ case ProcessUserModeIOPL:
+ case ProcessEnableAlignmentFaultFixup:
+ case ProcessAffinityMask:
+ case ProcessForegroundInformation:
+ default:
+ DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
+ Status = STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* Protect write with SEH */
+ _SEH2_TRY
+ {
+ /* Check if caller wanted return length */
+ if (ReturnLength) *ReturnLength = Length;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtSetInformationProcess(IN HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ IN PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength)
{
- {TRUE, 0}, // ThreadBasicInformation
- {TRUE, 0}, // ThreadTimes
- {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
- {TRUE, sizeof(LONG)}, // ThreadBasePriority
- {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
- {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken
- {TRUE, 0}, // ThreadDescriptorTableEntry
- {FALSE, 0}, // ThreadEnableAlignmentFaultFixup
- {FALSE, 0}, // ThreadEventPair
- {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
- {FALSE, 0}, // ThreadZeroTlsCell
- {TRUE, 0}, // ThreadPerformanceCount
- {TRUE, 0}, // ThreadAmILastThread
- {FALSE, 0}, // ThreadIdealProcessor
- {FALSE, 0}, // ThreadPriorityBoost
- {FALSE, 0}, // ThreadSetTlsArrayAddress
- {TRUE, 0}, // ThreadIsIoPending
- {FALSE, 0} // ThreadHideFromDebugger
-};
-
-/* FUNCTIONS *****************************************************************/
+ PEPROCESS Process;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ ACCESS_MASK Access;
+ NTSTATUS Status;
+ HANDLE PortHandle = NULL;
+ HANDLE TokenHandle = NULL;
+ PROCESS_SESSION_INFORMATION SessionInfo = {0};
+ PROCESS_PRIORITY_CLASS PriorityClass = {0};
+ PVOID ExceptionPort;
+ PAGED_CODE();
+
+ /* Verify Information Class validity */
+#if 0
+ Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
+ PsProcessInfoClass,
+ RTL_NUMBER_OF(PsProcessInfoClass),
+ ProcessInformation,
+ ProcessInformationLength,
+ PreviousMode);
+ if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+ /* Check what class this is */
+ Access = PROCESS_SET_INFORMATION;
+ if (ProcessInformationClass == ProcessSessionInformation)
+ {
+ /* Setting the Session ID needs a special mask */
+ Access |= PROCESS_SET_SESSIONID;
+ }
+ else if (ProcessInformationClass == ProcessExceptionPort)
+ {
+ /* Setting the exception port needs a special mask */
+ Access |= PROCESS_SUSPEND_RESUME;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ Access,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check what kind of information class this is */
+ switch (ProcessInformationClass)
+ {
+ /* Error/Exception Port */
+ case ProcessExceptionPort:
+
+ /* Check buffer length */
+ if (ProcessInformationLength != sizeof(HANDLE))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Capture the handle */
+ PortHandle = *(PHANDLE)ProcessInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Get the LPC Port */
+ Status = ObReferenceObjectByHandle(PortHandle,
+ 0,
+ LpcPortObjectType,
+ PreviousMode,
+ (PVOID)&ExceptionPort,
+ NULL);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Change the pointer */
+ if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
+ ExceptionPort,
+ NULL))
+ {
+ /* We already had one, fail */
+ ObDereferenceObject(ExceptionPort);
+ Status = STATUS_PORT_ALREADY_SET;
+ }
+ break;
+
+ /* Security Token */
+ case ProcessAccessToken:
+
+ /* Check buffer length */
+ if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Save the token handle */
+ TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
+ Token;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Assign the actual token */
+ Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
+ break;
+
+ /* Hard error processing */
+ case ProcessDefaultHardErrorMode:
+
+ /* Check buffer length */
+ if (ProcessInformationLength != sizeof(ULONG))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Enter SEH for direct buffer read */
+ _SEH2_TRY
+ {
+ /* Update the current mode abd return the previous one */
+ InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
+ *(PLONG)ProcessInformation);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
+
+ /* Session ID */
+ case ProcessSessionInformation:
+
+ /* Check buffer length */
+ if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Enter SEH for capture */
+ _SEH2_TRY
+ {
+ /* Capture the caller's buffer */
+ SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Setting the session id requires the SeTcbPrivilege */
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+ {
+ /* Can't set the session ID, bail out. */
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ break;
+ }
+
+ /* FIXME - update the session id for the process token */
+ //Status = PsLockProcess(Process, FALSE);
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Write the session ID in the EPROCESS */
+ Process->Session = SessionInfo.SessionId;
+
+ /* Check if the process also has a PEB */
+ if (Process->Peb)
+ {
+ /*
+ * Attach to the process to make sure we're in the right
+ * context to access the PEB structure
+ */
+ KeAttachProcess(&Process->Pcb);
+
+ /* Enter SEH for write to user-mode PEB */
+ _SEH2_TRY
+ {
+ /* Write the session ID */
+ Process->Peb->SessionId = SessionInfo.SessionId;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Detach from the process */
+ KeDetachProcess();
+ }
+
+ /* Unlock the process */
+ //PsUnlockProcess(Process);
+ break;
+
+ case ProcessPriorityClass:
+
+ /* Check buffer length */
+ if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Enter SEH for capture */
+ _SEH2_TRY
+ {
+ /* Capture the caller's buffer */
+ PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Check for invalid PriorityClass value */
+ if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* TODO: Check privileges */
+
+ /* Check if we have a job */
+ if (Process->Job)
+ {
+ DPRINT1("Jobs not yet supported\n");
+ }
+
+ /* Set process priority class */
+ Process->PriorityClass = PriorityClass.PriorityClass;
+
+ /* Set process priority mode (foreground or background) */
+ PsSetProcessPriorityByClass(Process,
+ !PriorityClass.Foreground ? PsProcessPriorityBackground :
+ PsProcessPriorityForeground);
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ /* We currently don't implement any of these */
+ case ProcessQuotaLimits:
+ case ProcessBasePriority:
+ case ProcessRaisePriority:
+ case ProcessLdtInformation:
+ case ProcessLdtSize:
+ case ProcessIoPortHandlers:
+ case ProcessWorkingSetWatch:
+ case ProcessUserModeIOPL:
+ case ProcessEnableAlignmentFaultFixup:
+ case ProcessAffinityMask:
+ DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ /* Supposedly these are invalid...!? verify! */
+ case ProcessBasicInformation:
+ case ProcessIoCounters:
+ case ProcessTimes:
+ case ProcessPooledUsageAndLimits:
+ case ProcessWx86Information:
+ case ProcessHandleCount:
+ case ProcessWow64Information:
+ case ProcessDebugPort:
+ default:
+ DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
+ Status = STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* Dereference and return status */
+ ObDereferenceObject(Process);
+ return Status;
+}
/*
- * @unimplemented
+ * @implemented
*/
-NTSTATUS STDCALL
-NtQueryInformationProcess(IN HANDLE ProcessHandle,
- IN PROCESSINFOCLASS ProcessInformationClass,
- OUT PVOID ProcessInformation,
- IN ULONG ProcessInformationLength,
- OUT PULONG ReturnLength OPTIONAL)
+NTSTATUS
+NTAPI
+NtSetInformationThread(IN HANDLE ThreadHandle,
+ IN THREADINFOCLASS ThreadInformationClass,
+ IN PVOID ThreadInformation,
+ IN ULONG ThreadInformationLength)
{
- PEPROCESS Process;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PAGED_CODE();
-
- PreviousMode = ExGetPreviousMode();
-
- DefaultQueryInfoBufferCheck(ProcessInformationClass,
- PsProcessInfoClass,
- ProcessInformation,
- ProcessInformationLength,
- ReturnLength,
- PreviousMode,
- &Status);
- if(!NT_SUCCESS(Status))
- {
- DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
- return Status;
- }
-
- if(ProcessInformationClass != ProcessCookie)
- {
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_QUERY_INFORMATION,
- PsProcessType,
- PreviousMode,
- (PVOID*)&Process,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
- else if(ProcessHandle != NtCurrentProcess())
- {
- /* retreiving the process cookie is only allowed for the calling process
- itself! XP only allowes NtCurrentProcess() as process handles even if a
- real handle actually represents the current process. */
- return STATUS_INVALID_PARAMETER;
- }
-
- switch (ProcessInformationClass)
- {
- case ProcessBasicInformation:
- {
- PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
- (PPROCESS_BASIC_INFORMATION)ProcessInformation;
-
- _SEH_TRY
- {
- ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
- ProcessBasicInformationP->PebBaseAddress = Process->Peb;
- ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
- ProcessBasicInformationP->UniqueProcessId =
- Process->UniqueProcessId;
- ProcessBasicInformationP->InheritedFromUniqueProcessId =
- Process->InheritedFromUniqueProcessId;
- ProcessBasicInformationP->BasePriority =
- Process->Pcb.BasePriority;
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessQuotaLimits:
- case ProcessIoCounters:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
-
- case ProcessTimes:
- {
- PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
- _SEH_TRY
- {
- ProcessTimeP->CreateTime = Process->CreateTime;
- ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
- ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
- ProcessTimeP->ExitTime = Process->ExitTime;
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(KERNEL_USER_TIMES);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessDebugPort:
- {
- _SEH_TRY
- {
- *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
- if (ReturnLength)
- {
- *ReturnLength = sizeof(HANDLE);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessLdtInformation:
- case ProcessWorkingSetWatch:
- case ProcessWx86Information:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
-
- case ProcessHandleCount:
- {
- ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
-
- _SEH_TRY
- {
- *(PULONG)ProcessInformation = HandleCount;
- if (ReturnLength)
- {
- *ReturnLength = sizeof(ULONG);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessSessionInformation:
- {
- PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
-
- _SEH_TRY
- {
- SessionInfo->SessionId = Process->Session;
- if (ReturnLength)
- {
- *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessWow64Information:
- DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
- Status = STATUS_NOT_IMPLEMENTED;
- break;
-
- case ProcessVmCounters:
- {
- PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
-
- _SEH_TRY
- {
- pOut->PeakVirtualSize = Process->PeakVirtualSize;
- /*
- * Here we should probably use VirtualSize.LowPart, but due to
- * incompatibilities in current headers (no unnamed union),
- * I opted for cast.
- */
- pOut->VirtualSize = (ULONG)Process->VirtualSize;
- pOut->PageFaultCount = Process->Vm.PageFaultCount;
- pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
- pOut->WorkingSetSize = Process->Vm.WorkingSetSize;
- pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0]; // TODO: Verify!
- pOut->QuotaPagedPoolUsage = Process->QuotaUsage[0]; // TODO: Verify!
- pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; // TODO: Verify!
- pOut->QuotaNonPagedPoolUsage = Process->QuotaUsage[1]; // TODO: Verify!
- pOut->PagefileUsage = Process->QuotaUsage[2];
- pOut->PeakPagefileUsage = Process->QuotaPeak[2];
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(VM_COUNTERS);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessDefaultHardErrorMode:
- {
- PULONG HardErrMode = (PULONG)ProcessInformation;
- _SEH_TRY
- {
- *HardErrMode = Process->DefaultHardErrorProcessing;
- if (ReturnLength)
- {
- *ReturnLength = sizeof(ULONG);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessPriorityBoost:
- {
- PULONG BoostEnabled = (PULONG)ProcessInformation;
-
- _SEH_TRY
- {
- *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(ULONG);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
+ PETHREAD Thread;
+ ULONG Access;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status;
+ HANDLE TokenHandle = NULL;
+ KPRIORITY Priority = 0;
+ KAFFINITY Affinity = 0, CombinedAffinity;
+ PVOID Address = NULL;
+ PEPROCESS Process;
+ ULONG DisableBoost = 0;
+ ULONG IdealProcessor = 0;
+ PTEB Teb;
+ ULONG TlsIndex = 0;
+ PVOID *ExpansionSlots;
+ PETHREAD ProcThread;
+ PAGED_CODE();
+
+ /* Verify Information Class validity */
+#if 0
+ Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
+ PsThreadInfoClass,
+ RTL_NUMBER_OF(PsThreadInfoClass),
+ ThreadInformation,
+ ThreadInformationLength,
+ PreviousMode);
+ if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+ /* Check what class this is */
+ Access = THREAD_SET_INFORMATION;
+ if (ThreadInformationClass == ThreadImpersonationToken)
+ {
+ /* Setting the impersonation token needs a special mask */
+ Access = THREAD_SET_THREAD_TOKEN;
+ }
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ThreadHandle,
+ Access,
+ PsThreadType,
+ PreviousMode,
+ (PVOID*)&Thread,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check what kind of information class this is */
+ switch (ThreadInformationClass)
+ {
+ /* Thread priority */
+ case ThreadPriority:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(KPRIORITY))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
- case ProcessDeviceMap:
- {
- PROCESS_DEVICEMAP_INFORMATION DeviceMap;
-
- ObQueryDeviceMapInformation(Process, &DeviceMap);
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ Priority = *(PLONG)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
- _SEH_TRY
- {
- *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
- if (ReturnLength)
- {
- *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessPriorityClass:
- {
- PUSHORT Priority = (PUSHORT)ProcessInformation;
-
- _SEH_TRY
- {
- *Priority = Process->PriorityClass;
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(USHORT);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
+ /* Validate it */
+ if ((Priority > HIGH_PRIORITY) ||
+ (Priority <= LOW_PRIORITY))
+ {
+ /* Fail */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
- case ProcessImageFileName:
- {
- /*
- * We DO NOT return the file name stored in the EPROCESS structure.
- * Propably if we can't find a PEB or ProcessParameters structure for the
- * process!
- */
- if(Process->Peb != NULL)
- {
- PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL;
- UNICODE_STRING LocalDest;
- BOOLEAN Attached;
- ULONG ImagePathLen = 0;
- PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
-
- /* we need to attach to the process to make sure we're in the right context! */
- Attached = Process != PsGetCurrentProcess();
-
- if(Attached)
- KeAttachProcess(&Process->Pcb);
-
- _SEH_TRY
- {
- ProcParams = Process->Peb->ProcessParameters;
- ImagePathLen = ProcParams->ImagePathName.Length;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if(NT_SUCCESS(Status))
- {
- if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
- {
- Status = STATUS_INFO_LENGTH_MISMATCH;
+ /* Set the priority */
+ KeSetPriorityThread(&Thread->Tcb, Priority);
+ break;
+
+ case ThreadBasePriority:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(LONG))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
}
- else
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ Priority = *(PLONG)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- PWSTR StrSource = NULL;
-
- RtlZeroMemory(&LocalDest, sizeof(LocalDest));
-
- /* create a DstPath structure on the stack */
- _SEH_TRY
- {
- LocalDest.Length = ImagePathLen;
- LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR);
- LocalDest.Buffer = (PWSTR)(DstPath + 1);
-
- /* save a copy of the pointer to the source buffer */
- StrSource = ProcParams->ImagePathName.Buffer;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if(NT_SUCCESS(Status))
- {
- /* now, let's allocate some anonymous memory to copy the string to.
- we can't just copy it to the buffer the caller pointed as it might
- be user memory in another context */
- PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR));
- if(PathCopy != NULL)
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Validate it */
+ if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
+ (Priority < THREAD_BASE_PRIORITY_MIN))
+ {
+ /* These ones are OK */
+ if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
+ (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
{
- /* make a copy of the buffer to the temporary buffer */
- _SEH_TRY
- {
- RtlCopyMemory(PathCopy, StrSource, LocalDest.Length);
- PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0';
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- /* detach from the process */
- if(Attached)
- KeDetachProcess();
-
- /* only copy the string back to the caller if we were able to
- copy it into the temporary buffer! */
- if(NT_SUCCESS(Status))
- {
- /* now let's copy the buffer back to the caller */
- _SEH_TRY
- {
- *DstPath = LocalDest;
- RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR));
- if (ReturnLength)
- {
- *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR);
- }
- }
- _SEH_HANDLE
+ /* Check if the process is real time */
+ if (PsGetCurrentProcess()->PriorityClass !=
+ PROCESS_PRIORITY_CLASS_REALTIME)
{
- Status = _SEH_GetExceptionCode();
+ /* It isn't, fail */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
}
- _SEH_END;
- }
+ }
+ }
+
+ /* Set the base priority */
+ KeSetBasePriorityThread(&Thread->Tcb, Priority);
+ break;
+
+ case ThreadAffinityMask:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(ULONG_PTR))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ Affinity = *(PULONG_PTR)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Validate it */
+ if (!Affinity)
+ {
+ /* Fail */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Get the process */
+ Process = Thread->ThreadsProcess;
- /* we're done with the copy operation, free the temporary kernel buffer */
- ExFreePool(PathCopy);
+ /* Try to acquire rundown */
+ if (ExAcquireRundownProtection(&Process->RundownProtect))
+ {
+ /* Lock it */
+ KeEnterCriticalRegion();
+ ExAcquirePushLockShared(&Process->ProcessLock);
- /* we need to bail because we're already detached from the process */
- break;
+ /* Combine masks */
+ CombinedAffinity = Affinity & Process->Pcb.Affinity;
+ if (CombinedAffinity != Affinity)
+ {
+ /* Fail */
+ Status = STATUS_INVALID_PARAMETER;
}
else
{
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ /* Set the affinity */
+ KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
}
- }
+
+ /* Release the lock and rundown */
+ ExReleasePushLockShared(&Process->ProcessLock);
+ KeLeaveCriticalRegion();
+ ExReleaseRundownProtection(&Process->RundownProtect);
}
- }
-
- /* don't forget to detach from the process!!! */
- if(Attached)
- KeDetachProcess();
- }
- else
- {
- /* FIXME - what to do here? */
- Status = STATUS_UNSUCCESSFUL;
- }
- break;
- }
-
- case ProcessCookie:
- {
- ULONG Cookie;
-
- /* receive the process cookie, this is only allowed for the current
- process! */
-
- Process = PsGetCurrentProcess();
-
- Cookie = Process->Cookie;
- if(Cookie == 0)
- {
- LARGE_INTEGER SystemTime;
- ULONG NewCookie;
- PKPRCB Prcb;
-
- /* generate a new cookie */
-
- KeQuerySystemTime(&SystemTime);
-
- Prcb = KeGetCurrentPrcb();
-
- NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
- SystemTime.u.LowPart ^ SystemTime.u.HighPart;
-
- /* try to set the new cookie, return the current one if another thread
- set it in the meanwhile */
- Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
- NewCookie,
- Cookie);
- if(Cookie == 0)
- {
- /* successfully set the cookie */
- Cookie = NewCookie;
- }
- }
-
- _SEH_TRY
- {
- *(PULONG)ProcessInformation = Cookie;
- if (ReturnLength)
- {
- *ReturnLength = sizeof(ULONG);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- break;
- }
-
- /*
- * Note: The following 10 information classes are verified to not be
- * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
- */
- case ProcessBasePriority:
- case ProcessRaisePriority:
- case ProcessExceptionPort:
- case ProcessAccessToken:
- case ProcessLdtSize:
- case ProcessIoPortHandlers:
- case ProcessUserModeIOPL:
- case ProcessEnableAlignmentFaultFixup:
- case ProcessAffinityMask:
- case ProcessForegroundInformation:
- default:
- Status = STATUS_INVALID_INFO_CLASS;
- }
-
- if(ProcessInformationClass != ProcessCookie)
- {
- ObDereferenceObject(Process);
- }
-
- return Status;
+ else
+ {
+ /* Too late */
+ Status = STATUS_PROCESS_IS_TERMINATING;
+ }
+
+ /* Return status */
+ break;
+
+ case ThreadImpersonationToken:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(HANDLE))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Save the token handle */
+ TokenHandle = *(PHANDLE)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Assign the actual token */
+ Status = PsAssignImpersonationToken(Thread, TokenHandle);
+ break;
+
+ case ThreadQuerySetWin32StartAddress:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(ULONG_PTR))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ Address = *(PVOID*)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Set the address */
+ Thread->Win32StartAddress = Address;
+ break;
+
+ case ThreadIdealProcessor:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(ULONG_PTR))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ IdealProcessor = *(PULONG_PTR)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Validate it */
+ if (IdealProcessor > MAXIMUM_PROCESSORS)
+ {
+ /* Fail */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Set the ideal */
+ Status = KeSetIdealProcessorThread(&Thread->Tcb,
+ (CCHAR)IdealProcessor);
+
+ /* Get the TEB and protect the thread */
+ Teb = Thread->Tcb.Teb;
+ if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
+ {
+ /* Save the ideal processor */
+ Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
+
+ /* Release rundown protection */
+ ExReleaseRundownProtection(&Thread->RundownProtect);
+ }
+
+ break;
+
+ case ThreadPriorityBoost:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(ULONG_PTR))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ DisableBoost = *(PULONG_PTR)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* Call the kernel */
+ KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
+ break;
+
+ case ThreadZeroTlsCell:
+
+ /* Check buffer length */
+ if (ThreadInformationLength != sizeof(ULONG_PTR))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ /* Use SEH for capture */
+ _SEH2_TRY
+ {
+ /* Get the priority */
+ TlsIndex = *(PULONG_PTR)ThreadInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status)) break;
+
+ /* This is only valid for the current thread */
+ if (Thread != PsGetCurrentThread())
+ {
+ /* Fail */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Get the process */
+ Process = Thread->ThreadsProcess;
+
+ /* Loop the threads */
+ ProcThread = PsGetNextProcessThread(Process, NULL);
+ while (ProcThread)
+ {
+ /* Acquire rundown */
+ if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
+ {
+ /* Get the TEB */
+ Teb = ProcThread->Tcb.Teb;
+ if (Teb)
+ {
+ /* Check if we're in the expansion range */
+ if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
+ {
+ if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
+ TLS_EXPANSION_SLOTS) - 1)
+ {
+ /* Check if we have expansion slots */
+ ExpansionSlots = Teb->TlsExpansionSlots;
+ if (ExpansionSlots)
+ {
+ /* Clear the index */
+ ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
+ }
+ }
+ }
+ else
+ {
+ /* Clear the index */
+ Teb->TlsSlots[TlsIndex] = NULL;
+ }
+ }
+
+ /* Release rundown */
+ ExReleaseRundownProtection(&ProcThread->RundownProtect);
+ }
+
+ /* Go to the next thread */
+ ProcThread = PsGetNextProcessThread(Process, ProcThread);
+ }
+
+ /* All done */
+ break;
+
+ default:
+ /* We don't implement it yet */
+ DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Dereference and return status */
+ ObDereferenceObject(Thread);
+ return Status;
}
/*
- * @unimplemented
+ * @implemented
*/
-NTSTATUS STDCALL
-NtSetInformationProcess(IN HANDLE ProcessHandle,
- IN PROCESSINFOCLASS ProcessInformationClass,
- IN PVOID ProcessInformation,
- IN ULONG ProcessInformationLength)
+NTSTATUS
+NTAPI
+NtQueryInformationThread(IN HANDLE ThreadHandle,
+ IN THREADINFOCLASS ThreadInformationClass,
+ OUT PVOID ThreadInformation,
+ IN ULONG ThreadInformationLength,
+ OUT PULONG ReturnLength OPTIONAL)
{
- PEPROCESS Process;
- KPROCESSOR_MODE PreviousMode;
- ACCESS_MASK Access;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PAGED_CODE();
-
- PreviousMode = ExGetPreviousMode();
-
- DefaultSetInfoBufferCheck(ProcessInformationClass,
- PsProcessInfoClass,
- ProcessInformation,
- ProcessInformationLength,
- PreviousMode,
- &Status);
- if(!NT_SUCCESS(Status))
- {
- DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
- DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
- return Status;
- }
-
- switch(ProcessInformationClass)
- {
- case ProcessSessionInformation:
- Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
- break;
- case ProcessExceptionPort:
- Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
- break;
-
- default:
- Access = PROCESS_SET_INFORMATION;
- break;
- }
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- Access,
- PsProcessType,
- PreviousMode,
- (PVOID*)&Process,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- switch (ProcessInformationClass)
- {
- case ProcessQuotaLimits:
- case ProcessBasePriority:
- case ProcessRaisePriority:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
-
- case ProcessExceptionPort:
- {
- HANDLE PortHandle = NULL;
-
- /* make a safe copy of the buffer on the stack */
- _SEH_TRY
+ PETHREAD Thread;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Access;
+ ULONG Length = 0;
+ PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
+ (PTHREAD_BASIC_INFORMATION)ThreadInformation;
+ PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
+ KIRQL OldIrql;
+ PAGED_CODE();
+
+ if (PreviousMode != KernelMode)
+ {
+ _SEH2_TRY
{
- PortHandle = *(PHANDLE)ProcessInformation;
- Status = STATUS_SUCCESS;
+ ProbeForWrite(ThreadInformation,
+ ThreadInformationLength,
+ sizeof(ULONG));
+
+ if (ReturnLength)
+ {
+ ProbeForWriteUlong(ReturnLength);
+ }
}
- _SEH_HANDLE
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- Status = _SEH_GetExceptionCode();
+ Status = _SEH2_GetExceptionCode();
}
- _SEH_END;
-
- if(NT_SUCCESS(Status))
- {
- PEPORT ExceptionPort;
-
- /* in case we had success reading from the buffer, verify the provided
- * LPC port handle
- */
- Status = ObReferenceObjectByHandle(PortHandle,
- 0,
- LpcPortObjectType,
- PreviousMode,
- (PVOID)&ExceptionPort,
- NULL);
- if(NT_SUCCESS(Status))
- {
- /* lock the process to be thread-safe! */
-
- Status = PsLockProcess(Process, FALSE);
- if(NT_SUCCESS(Status))
- {
- /*
- * according to "NT Native API" documentation, setting the exception
- * port is only permitted once!
- */
- if(Process->ExceptionPort == NULL)
- {
- /* keep the reference to the handle! */
- Process->ExceptionPort = ExceptionPort;
- Status = STATUS_SUCCESS;
- }
- else
- {
- ObDereferenceObject(ExceptionPort);
- Status = STATUS_PORT_ALREADY_SET;
- }
- PsUnlockProcess(Process);
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Check what class this is */
+ Access = THREAD_QUERY_INFORMATION;
+
+ /* Reference the process */
+ Status = ObReferenceObjectByHandle(ThreadHandle,
+ Access,
+ PsThreadType,
+ PreviousMode,
+ (PVOID*)&Thread,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check what kind of information class this is */
+ switch (ThreadInformationClass)
+ {
+ /* Basic thread information */
+ case ThreadBasicInformation:
+
+ /* Set return length */
+ Length = sizeof(THREAD_BASIC_INFORMATION);
+
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
}
- else
+ /* Protect writes with SEH */
+ _SEH2_TRY
{
- ObDereferenceObject(ExceptionPort);
+ /* Write all the information from the ETHREAD/KTHREAD */
+ ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
+ ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
+ ThreadBasicInfo->ClientId = Thread->Cid;
+ ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
+ ThreadBasicInfo->Priority = Thread->Tcb.Priority;
+ ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
}
- }
- }
- break;
- }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
- case ProcessAccessToken:
- {
- HANDLE TokenHandle = NULL;
+ /* Thread time information */
+ case ThreadTimes:
- /* make a safe copy of the buffer on the stack */
- _SEH_TRY
- {
- TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
- Status = STATUS_SUCCESS;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Set the return length */
+ Length = sizeof(KERNEL_USER_TIMES);
- if(NT_SUCCESS(Status))
- {
- /* in case we had success reading from the buffer, perform the actual task */
- Status = PspAssignPrimaryToken(Process, TokenHandle);
- }
- break;
- }
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+ /* Protect writes with SEH */
+ _SEH2_TRY
+ {
+ /* Copy time information from ETHREAD/KTHREAD */
+ ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
+ 100000LL;
+ ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
+ 100000LL;
+ ThreadTime->CreateTime = Thread->CreateTime;
+ ThreadTime->ExitTime = Thread->ExitTime;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
- case ProcessDefaultHardErrorMode:
- {
- _SEH_TRY
- {
- InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
- *(PLONG)ProcessInformation);
- Status = STATUS_SUCCESS;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- case ProcessSessionInformation:
- {
- PROCESS_SESSION_INFORMATION SessionInfo;
- Status = STATUS_SUCCESS;
-
- RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
-
- _SEH_TRY
- {
- /* copy the structure to the stack */
- SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if(NT_SUCCESS(Status))
- {
- /* we successfully copied the structure to the stack, continue processing */
-
- /*
- * setting the session id requires the SeTcbPrivilege!
- */
- if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
- PreviousMode))
- {
- DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
- /* can't set the session id, bail! */
- Status = STATUS_PRIVILEGE_NOT_HELD;
+ case ThreadQuerySetWin32StartAddress:
+
+ /* Set the return length*/
+ Length = sizeof(PVOID);
+
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+ /* Protect write with SEH */
+ _SEH2_TRY
+ {
+ /* Return the Win32 Start Address */
+ *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
break;
- }
-
- /* FIXME - update the session id for the process token */
- Status = PsLockProcess(Process, FALSE);
- if(NT_SUCCESS(Status))
- {
- Process->Session = SessionInfo.SessionId;
+ case ThreadPerformanceCount:
+
+ /* Set the return length*/
+ Length = sizeof(LARGE_INTEGER);
- /* Update the session id in the PEB structure */
- if(Process->Peb != NULL)
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+ /* Protect write with SEH */
+ _SEH2_TRY
{
- /* we need to attach to the process to make sure we're in the right
- context to access the PEB structure */
- KeAttachProcess(&Process->Pcb);
+ /* FIXME */
+ (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
- _SEH_TRY
- {
- /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
+ case ThreadAmILastThread:
- Status = STATUS_SUCCESS;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Set the return length*/
+ Length = sizeof(ULONG);
- KeDetachProcess();
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+ /* Protect write with SEH */
+ _SEH2_TRY
+ {
+ /* Return whether or not we are the last thread */
+ *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
+ ThreadListHead.Flink->Flink ==
+ &Thread->ThreadsProcess->
+ ThreadListHead) ?
+ TRUE : FALSE);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
}
+ _SEH2_END;
+ break;
- PsUnlockProcess(Process);
- }
- }
- break;
- }
-
- case ProcessPriorityClass:
- {
- PROCESS_PRIORITY_CLASS ppc;
-
- _SEH_TRY
- {
- ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if(NT_SUCCESS(Status))
- {
- }
-
- break;
- }
-
- case ProcessLdtInformation:
- case ProcessLdtSize:
- case ProcessIoPortHandlers:
- case ProcessWorkingSetWatch:
- case ProcessUserModeIOPL:
- case ProcessEnableAlignmentFaultFixup:
- case ProcessAffinityMask:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
-
- case ProcessBasicInformation:
- case ProcessIoCounters:
- case ProcessTimes:
- case ProcessPooledUsageAndLimits:
- case ProcessWx86Information:
- case ProcessHandleCount:
- case ProcessWow64Information:
- case ProcessDebugPort:
- default:
- Status = STATUS_INVALID_INFO_CLASS;
- }
- ObDereferenceObject(Process);
- return(Status);
-}
+ case ThreadIsIoPending:
+ /* Set the return length*/
+ Length = sizeof(ULONG);
-/**********************************************************************
- * NAME INTERNAL
- * PiQuerySystemProcessInformation
- *
- * DESCRIPTION
- * Compute the size of a process+thread snapshot as
- * expected by NtQuerySystemInformation.
- *
- * RETURN VALUE
- * 0 on error; otherwise the size, in bytes of the buffer
- * required to write a full snapshot.
- *
- * NOTE
- * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
- */
-NTSTATUS
-PiQuerySystemProcessInformation(PVOID Buffer,
- ULONG Size,
- PULONG ReqSize)
-{
- return STATUS_NOT_IMPLEMENTED;
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+ /* Raise the IRQL to protect the IRP list */
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
-#if 0
- PLIST_ENTRY CurrentEntryP;
- PEPROCESS CurrentP;
- PLIST_ENTRY CurrentEntryT;
- PETHREAD CurrentT;
-
- ULONG RequiredSize = 0L;
- BOOLEAN SizeOnly = FALSE;
-
- ULONG SpiSize = 0L;
-
- PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
- PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
- PSYSTEM_THREAD_INFO pInfoT = NULL;
-
-
- /* Lock the process list. */
- ExAcquireFastMutex(&PspActiveProcessMutex);
-
- /*
- * Scan the process list. Since the
- * list is circular, the guard is false
- * after the last process.
- */
- for ( CurrentEntryP = PsActiveProcessHead.Flink;
- (CurrentEntryP != & PsActiveProcessHead);
- CurrentEntryP = CurrentEntryP->Flink
- )
- {
- /*
- * Compute how much space is
- * occupied in the snapshot
- * by adding this process info.
- * (at least one thread).
- */
- SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
- RequiredSize += SpiSizeCurrent;
- /*
- * Do not write process data in the
- * buffer if it is too small.
- */
- if (TRUE == SizeOnly) continue;
- /*
- * Check if the buffer can contain
- * the full snapshot.
- */
- if (Size < RequiredSize)
- {
- SizeOnly = TRUE;
- continue;
- }
- /*
- * Get a reference to the
- * process descriptor we are
- * handling.
- */
- CurrentP = CONTAINING_RECORD(
- CurrentEntryP,
- EPROCESS,
- ProcessListEntry
- );
- /*
- * Write process data in the buffer.
- */
- RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
- /* PROCESS */
- pInfoP->ThreadCount = 0L;
- pInfoP->ProcessId = CurrentP->UniqueProcessId;
- RtlInitUnicodeString (
- & pInfoP->Name,
- CurrentP->ImageFileName
- );
- /* THREAD */
- for ( pInfoT = & CurrentP->ThreadSysInfo [0],
- CurrentEntryT = CurrentP->ThreadListHead.Flink;
-
- (CurrentEntryT != & CurrentP->ThreadListHead);
-
- pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
- CurrentEntryT = CurrentEntryT->Flink
- )
- {
- /*
- * Recalculate the size of the
- * information block.
- */
- if (0 < pInfoP->ThreadCount)
- {
- RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
- }
- /*
- * Do not write thread data in the
- * buffer if it is too small.
- */
- if (TRUE == SizeOnly) continue;
- /*
- * Check if the buffer can contain
- * the full snapshot.
- */
- if (Size < RequiredSize)
- {
- SizeOnly = TRUE;
- continue;
- }
- /*
- * Get a reference to the
- * thread descriptor we are
- * handling.
- */
- CurrentT = CONTAINING_RECORD(
- CurrentEntryT,
- KTHREAD,
- ThreadListEntry
- );
- /*
- * Write thread data.
- */
- RtlZeroMemory (
- pInfoT,
- sizeof (SYSTEM_THREAD_INFORMATION)
- );
- pInfoT->KernelTime = CurrentT-> ; /* TIME */
- pInfoT->UserTime = CurrentT-> ; /* TIME */
- pInfoT->CreateTime = CurrentT-> ; /* TIME */
- pInfoT->TickCount = CurrentT-> ; /* ULONG */
- pInfoT->StartEIP = CurrentT-> ; /* ULONG */
- pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
- pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
- pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */
- pInfoT->BasePriority = CurrentT-> ; /* ULONG */
- pInfoT->nSwitches = CurrentT-> ; /* ULONG */
- pInfoT->State = CurrentT-> ; /* DWORD */
- pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */
- /*
- * Count the number of threads
- * this process has.
- */
- ++ pInfoP->ThreadCount;
- }
- /*
- * Save the size of information
- * stored in the buffer for the
- * current process.
- */
- pInfoP->RelativeOffset = SpiSize;
- /*
- * Save a reference to the last
- * valid information block.
- */
- pInfoPLast = pInfoP;
- /*
- * Compute the offset of the
- * SYSTEM_PROCESS_INFORMATION
- * descriptor in the snapshot
- * buffer for the next process.
- */
- (ULONG) pInfoP += SpiSize;
- }
- /*
- * Unlock the process list.
- */
- ExReleaseFastMutex (
- & PspActiveProcessMutex
- );
- /*
- * Return the proper error status code,
- * if the buffer was too small.
- */
- if (TRUE == SizeOnly)
- {
- if (NULL != RequiredSize)
- {
- *pRequiredSize = RequiredSize;
- }
- return STATUS_INFO_LENGTH_MISMATCH;
- }
- /*
- * Mark the end of the snapshot.
- */
- pInfoP->RelativeOffset = 0L;
- /* OK */
- return STATUS_SUCCESS;
-#endif
-}
+ /* Protect write with SEH */
+ _SEH2_TRY
+ {
+ /* Check if the IRP list is empty or not */
+ *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
-/*
- * @unimplemented
- */
-NTSTATUS STDCALL
-NtSetInformationThread (IN HANDLE ThreadHandle,
- IN THREADINFOCLASS ThreadInformationClass,
- IN PVOID ThreadInformation,
- IN ULONG ThreadInformationLength)
-{
- PETHREAD Thread;
- NTSTATUS Status;
- union
- {
- KPRIORITY Priority;
- LONG Increment;
- KAFFINITY Affinity;
- HANDLE Handle;
- PVOID Address;
- }u;
-
- PAGED_CODE();
-
- if (ThreadInformationClass <= MaxThreadInfoClass &&
- !SetInformationData[ThreadInformationClass].Implemented)
- {
- return STATUS_NOT_IMPLEMENTED;
+ /* Lower IRQL back */
+ KeLowerIrql(OldIrql);
+ break;
+
+ case ThreadDescriptorTableEntry:
+ DPRINT1("NtQueryInformationThread(): case ThreadDescriptorTableEntry not implemented!\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case ThreadPriorityBoost:
+
+ /* Set the return length*/
+ Length = sizeof(ULONG);
+
+ if (ThreadInformationLength != Length)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ _SEH2_TRY
+ {
+ *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ break;
+
+ /* Anything else */
+ default:
+
+ /* Not yet implemented */
+ DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+ Status = STATUS_NOT_IMPLEMENTED;
}
- if (ThreadInformationClass > MaxThreadInfoClass ||
- SetInformationData[ThreadInformationClass].Size == 0)
+
+ /* Protect write with SEH */
+ _SEH2_TRY
{
- return STATUS_INVALID_INFO_CLASS;
+ /* Check if caller wanted return length */
+ if (ReturnLength) *ReturnLength = Length;
}
- if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- return STATUS_INFO_LENGTH_MISMATCH;
+ /* Get exception code */
+ Status = _SEH2_GetExceptionCode();
}
+ _SEH2_END;
- Status = ObReferenceObjectByHandle (ThreadHandle,
- THREAD_SET_INFORMATION,
- PsThreadType,
- ExGetPreviousMode (),
- (PVOID*)&Thread,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- Status = MmCopyFromCaller(&u.Priority,
- ThreadInformation,
- SetInformationData[ThreadInformationClass].Size);
- if (NT_SUCCESS(Status))
- {
- switch (ThreadInformationClass)
- {
- case ThreadPriority:
- if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
- {
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- KeSetPriorityThread(&Thread->Tcb, u.Priority);
- break;
-
- case ThreadBasePriority:
- KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
- break;
-
- case ThreadAffinityMask:
- Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
- break;
-
- case ThreadImpersonationToken:
- Status = PsAssignImpersonationToken (Thread, u.Handle);
- break;
-
- case ThreadQuerySetWin32StartAddress:
- Thread->Win32StartAddress = u.Address;
- break;
-
- default:
- /* Shoult never occure if the data table is correct */
- KEBUGCHECK(0);
- }
- }
- ObDereferenceObject (Thread);
-
- return Status;
+ /* Dereference the thread, and return */
+ ObDereferenceObject(Thread);
+ return Status;
}
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-NtQueryInformationThread (IN HANDLE ThreadHandle,
- IN THREADINFOCLASS ThreadInformationClass,
- OUT PVOID ThreadInformation,
- IN ULONG ThreadInformationLength,
- OUT PULONG ReturnLength OPTIONAL)
-{
- PETHREAD Thread;
- NTSTATUS Status;
- union
- {
- THREAD_BASIC_INFORMATION TBI;
- KERNEL_USER_TIMES TTI;
- PVOID Address;
- LARGE_INTEGER Count;
- BOOLEAN Last;
- }u;
-
- PAGED_CODE();
-
- if (ThreadInformationClass <= MaxThreadInfoClass &&
- !QueryInformationData[ThreadInformationClass].Implemented)
- {
- return STATUS_NOT_IMPLEMENTED;
- }
- if (ThreadInformationClass > MaxThreadInfoClass ||
- QueryInformationData[ThreadInformationClass].Size == 0)
- {
- return STATUS_INVALID_INFO_CLASS;
- }
- if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
- {
- return STATUS_INFO_LENGTH_MISMATCH;
- }
-
- Status = ObReferenceObjectByHandle(ThreadHandle,
- THREAD_QUERY_INFORMATION,
- PsThreadType,
- ExGetPreviousMode(),
- (PVOID*)&Thread,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- switch (ThreadInformationClass)
- {
- case ThreadBasicInformation:
- /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
- * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
- * 0. So do the conversion here:
- * -Gunnar */
- u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
- u.TBI.TebBaseAddress = Thread->Tcb.Teb;
- u.TBI.ClientId = Thread->Cid;
- u.TBI.AffinityMask = Thread->Tcb.Affinity;
- u.TBI.Priority = Thread->Tcb.Priority;
- u.TBI.BasePriority = Thread->Tcb.BasePriority;
- break;
-
- case ThreadTimes:
- u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
- u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
- u.TTI.CreateTime = Thread->CreateTime;
- /*This works*/
- u.TTI.ExitTime = Thread->ExitTime;
- break;
-
- case ThreadQuerySetWin32StartAddress:
- u.Address = Thread->Win32StartAddress;
- break;
-
- case ThreadPerformanceCount:
- /* Nebbett says this class is always zero */
- u.Count.QuadPart = 0;
- break;
-
- case ThreadAmILastThread:
- if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
- &Thread->ThreadsProcess->ThreadListHead)
- {
- u.Last = TRUE;
- }
- else
- {
- u.Last = FALSE;
- }
- break;
- default:
- /* Shoult never occure if the data table is correct */
- KEBUGCHECK(0);
- }
- if (QueryInformationData[ThreadInformationClass].Size)
- {
- Status = MmCopyToCaller(ThreadInformation,
- &u.TBI,
- QueryInformationData[ThreadInformationClass].Size);
- }
- if (ReturnLength)
- {
- NTSTATUS Status2;
- static ULONG Null = 0;
- Status2 = MmCopyToCaller(ReturnLength,
- NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null,
- sizeof(ULONG));
- if (NT_SUCCESS(Status))
- {
- Status = Status2;
- }
- }
-
- ObDereferenceObject(Thread);
- return(Status);
-}
/* EOF */