mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 05:12:43 +00:00
- Check the caller pointers in all cases.
- Simplified the thread info functions a little bit. svn path=/trunk/; revision=12698
This commit is contained in:
parent
38d12a5ce6
commit
6bd1cc19a3
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: tinfo.c,v 1.31 2004/11/19 22:19:33 gdalsnes Exp $
|
/* $Id$
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -16,6 +16,69 @@
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME:
|
||||||
|
* Remove the Implemented value if all functions are 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
|
||||||
|
{
|
||||||
|
BOOLEAN Implemented;
|
||||||
|
ULONG Size;
|
||||||
|
} SetInformationData[MaxThreadInfoClass + 1] =
|
||||||
|
{
|
||||||
|
{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
|
||||||
|
#ifdef _ENABLE_THRDEVTPAIR
|
||||||
|
{TRUE, sizeof(HANDLE)}, // ThreadEventPair
|
||||||
|
#else
|
||||||
|
{FALSE, 0}, // ThreadEventPair
|
||||||
|
#endif
|
||||||
|
{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 *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -29,6 +92,29 @@ NtSetInformationThread (IN HANDLE ThreadHandle,
|
||||||
{
|
{
|
||||||
PETHREAD Thread;
|
PETHREAD Thread;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
KPRIORITY Priority;
|
||||||
|
LONG Increment;
|
||||||
|
KAFFINITY Affinity;
|
||||||
|
HANDLE Handle;
|
||||||
|
PVOID Address;
|
||||||
|
}u;
|
||||||
|
|
||||||
|
if (ThreadInformationClass <= MaxThreadInfoClass &&
|
||||||
|
!SetInformationData[ThreadInformationClass].Implemented)
|
||||||
|
{
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
if (ThreadInformationClass > MaxThreadInfoClass ||
|
||||||
|
SetInformationData[ThreadInformationClass].Size == 0)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_INFO_CLASS;
|
||||||
|
}
|
||||||
|
if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
|
||||||
|
{
|
||||||
|
return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle (ThreadHandle,
|
Status = ObReferenceObjectByHandle (ThreadHandle,
|
||||||
THREAD_SET_INFORMATION,
|
THREAD_SET_INFORMATION,
|
||||||
|
@ -41,174 +127,62 @@ NtSetInformationThread (IN HANDLE ThreadHandle,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ThreadInformationClass)
|
Status = MmCopyFromCaller(&u.Priority,
|
||||||
{
|
ThreadInformation,
|
||||||
case ThreadBasicInformation:
|
SetInformationData[ThreadInformationClass].Size);
|
||||||
/* Can only be queried */
|
if (NT_SUCCESS(Status))
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
{
|
||||||
break;
|
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 ThreadTimes:
|
case ThreadBasePriority:
|
||||||
/* Can only be queried */
|
KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadPriority:
|
case ThreadAffinityMask:
|
||||||
{
|
Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
|
||||||
KPRIORITY Priority;
|
break;
|
||||||
|
|
||||||
if (ThreadInformationLength != sizeof(KPRIORITY))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Priority = *(KPRIORITY*)ThreadInformation;
|
|
||||||
if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
|
|
||||||
{
|
|
||||||
Status = STATUS_INVALID_PARAMETER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
KeSetPriorityThread(&Thread->Tcb, Priority);
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ThreadBasePriority:
|
case ThreadImpersonationToken:
|
||||||
{
|
Status = PsAssignImpersonationToken (Thread, u.Handle);
|
||||||
LONG Increment;
|
break;
|
||||||
|
|
||||||
if (ThreadInformationLength != sizeof(LONG))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Status = MmCopyFromCaller(&Increment,
|
|
||||||
ThreadInformation,
|
|
||||||
sizeof(ULONG));
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
KeSetBasePriorityThread (&Thread->Tcb, Increment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadAffinityMask:
|
|
||||||
Thread->Tcb.UserAffinity = *((PULONG)ThreadInformation);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadImpersonationToken:
|
|
||||||
{
|
|
||||||
HANDLE TokenHandle;
|
|
||||||
|
|
||||||
if (ThreadInformationLength != sizeof(HANDLE))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TokenHandle = *((PHANDLE)ThreadInformation);
|
|
||||||
Status = PsAssignImpersonationToken (Thread,
|
|
||||||
TokenHandle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ThreadDescriptorTableEntry:
|
|
||||||
/* Can only be queried */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef _ENABLE_THRDEVTPAIR
|
#ifdef _ENABLE_THRDEVTPAIR
|
||||||
case ThreadEventPair:
|
case ThreadEventPair:
|
||||||
{
|
{
|
||||||
PKEVENT_PAIR EventPair;
|
PKEVENT_PAIR EventPair;
|
||||||
|
|
||||||
if (ThreadInformationLength != sizeof(HANDLE))
|
Status = ObReferenceObjectByHandle(u.Handle,
|
||||||
{
|
STANDARD_RIGHTS_ALL,
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
ExEventPairObjectType,
|
||||||
break;
|
ExGetPreviousMode(),
|
||||||
}
|
(PVOID*)&EventPair,
|
||||||
|
NULL);
|
||||||
if (ExGetPreviousMode() == UserMode) /* FIXME: Validate this for all infoclasses and system services */
|
if (NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT("NtSetInformationThread:ThreadEventPair: Checking user pointer %08x...\n", ThreadInformation);
|
ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
|
||||||
ProbeForRead(ThreadInformation, sizeof(HANDLE), sizeof(HANDLE)); /* FIXME: This entire function should be
|
}
|
||||||
* wrapped in an SEH frame... return (NTSTATUS)GetExceptionCode() on exception */
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(*(PHANDLE)ThreadInformation,
|
|
||||||
STANDARD_RIGHTS_ALL,
|
|
||||||
ExEventPairObjectType,
|
|
||||||
ExGetPreviousMode(),
|
|
||||||
(PVOID*)&EventPair,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#else /* !_ENABLE_THRDEVTPAIR */
|
|
||||||
case ThreadEventPair:
|
|
||||||
{
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif /* _ENABLE_THRDEVTPAIR */
|
#endif /* _ENABLE_THRDEVTPAIR */
|
||||||
|
|
||||||
case ThreadQuerySetWin32StartAddress:
|
case ThreadQuerySetWin32StartAddress:
|
||||||
if (ThreadInformationLength != sizeof(ULONG))
|
Thread->Win32StartAddress = u.Address;
|
||||||
{
|
break;
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Thread->Win32StartAddress = (PVOID)*((PULONG)ThreadInformation);
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadZeroTlsCell:
|
|
||||||
{
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ThreadPerformanceCount:
|
|
||||||
/* Can only be queried */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadAmILastThread:
|
|
||||||
/* Can only be queried */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadIdealProcessor:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadPriorityBoost:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadSetTlsArrayAddress:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadIsIoPending:
|
|
||||||
/* Can only be queried */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadHideFromDebugger:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Shoult never occure if the data table is correct */
|
||||||
|
KEBUGCHECK(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
ObDereferenceObject (Thread);
|
ObDereferenceObject (Thread);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
|
@ -226,6 +200,29 @@ NtQueryInformationThread (IN HANDLE ThreadHandle,
|
||||||
{
|
{
|
||||||
PETHREAD Thread;
|
PETHREAD Thread;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
THREAD_BASIC_INFORMATION TBI;
|
||||||
|
KERNEL_USER_TIMES TTI;
|
||||||
|
PVOID Address;
|
||||||
|
LARGE_INTEGER Count;
|
||||||
|
BOOLEAN Last;
|
||||||
|
}u;
|
||||||
|
|
||||||
|
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,
|
Status = ObReferenceObjectByHandle(ThreadHandle,
|
||||||
THREAD_QUERY_INFORMATION,
|
THREAD_QUERY_INFORMATION,
|
||||||
|
@ -240,161 +237,70 @@ NtQueryInformationThread (IN HANDLE ThreadHandle,
|
||||||
|
|
||||||
switch (ThreadInformationClass)
|
switch (ThreadInformationClass)
|
||||||
{
|
{
|
||||||
case ThreadBasicInformation:
|
case ThreadBasicInformation:
|
||||||
{
|
/* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
|
||||||
PTHREAD_BASIC_INFORMATION TBI;
|
* as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
|
||||||
|
* 0. So do the conversion here:
|
||||||
TBI = (PTHREAD_BASIC_INFORMATION)ThreadInformation;
|
* -Gunnar */
|
||||||
|
u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
|
||||||
if (ThreadInformationLength != sizeof(THREAD_BASIC_INFORMATION))
|
u.TBI.TebBaseAddress = Thread->Tcb.Teb;
|
||||||
{
|
u.TBI.ClientId = Thread->Cid;
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
u.TBI.AffinityMask = Thread->Tcb.Affinity;
|
||||||
break;
|
u.TBI.Priority = Thread->Tcb.Priority;
|
||||||
}
|
u.TBI.BasePriority = Thread->Tcb.BasePriority;
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
TBI->ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
|
|
||||||
TBI->TebBaseAddress = Thread->Tcb.Teb;
|
|
||||||
TBI->ClientId = Thread->Cid;
|
|
||||||
TBI->AffinityMask = Thread->Tcb.Affinity;
|
|
||||||
TBI->Priority = Thread->Tcb.Priority;
|
|
||||||
TBI->BasePriority = Thread->Tcb.BasePriority;
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case ThreadTimes:
|
case ThreadTimes:
|
||||||
{
|
u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
|
||||||
PKERNEL_USER_TIMES TTI;
|
u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
|
||||||
|
u.TTI.CreateTime = (TIME) Thread->CreateTime;
|
||||||
TTI = (PKERNEL_USER_TIMES)ThreadInformation;
|
/*This works*/
|
||||||
|
u.TTI.ExitTime = (TIME) Thread->ExitTime;
|
||||||
if (ThreadInformationLength != sizeof(KERNEL_USER_TIMES))
|
break;
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TTI->KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
|
case ThreadQuerySetWin32StartAddress:
|
||||||
TTI->UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
|
u.Address = Thread->Win32StartAddress;
|
||||||
TTI->CreateTime = (TIME) Thread->CreateTime;
|
break;
|
||||||
/*This works*/
|
|
||||||
TTI->ExitTime = (TIME) Thread->ExitTime;
|
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ThreadPriority:
|
|
||||||
/* Can be set only */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadBasePriority:
|
|
||||||
/* Can be set only */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadAffinityMask:
|
|
||||||
/* Can be set only */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadImpersonationToken:
|
case ThreadPerformanceCount:
|
||||||
/* Can be set only */
|
/* Nebbett says this class is always zero */
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
u.Count.QuadPart = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ThreadDescriptorTableEntry:
|
|
||||||
/* Nebbett says nothing about this */
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadEnableAlignmentFaultFixup:
|
case ThreadAmILastThread:
|
||||||
/* Can be set only */
|
if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadEventPair:
|
|
||||||
/* Can be set only */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadQuerySetWin32StartAddress:
|
|
||||||
if (ThreadInformationLength != sizeof(PVOID))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*((PVOID*)ThreadInformation) = Thread->Win32StartAddress;
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadZeroTlsCell:
|
|
||||||
/* Can only be set */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadPerformanceCount:
|
|
||||||
/* Nebbett says this class is always zero */
|
|
||||||
if (ThreadInformationLength != sizeof(LARGE_INTEGER))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
((PLARGE_INTEGER)ThreadInformation)->QuadPart = 0;
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadAmILastThread:
|
|
||||||
{
|
|
||||||
if (ThreadInformationLength != sizeof(BOOLEAN))
|
|
||||||
{
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
|
|
||||||
&Thread->ThreadsProcess->ThreadListHead)
|
&Thread->ThreadsProcess->ThreadListHead)
|
||||||
{
|
{
|
||||||
*((PBOOLEAN)ThreadInformation) = TRUE;
|
u.Last = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*((PBOOLEAN)ThreadInformation) = FALSE;
|
u.Last = FALSE;
|
||||||
}
|
}
|
||||||
Status = STATUS_SUCCESS;
|
break;
|
||||||
break;
|
default:
|
||||||
}
|
/* Shoult never occure if the data table is correct */
|
||||||
|
KEBUGCHECK(0);
|
||||||
case ThreadIdealProcessor:
|
|
||||||
/* Can only be set */
|
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadPriorityBoost:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadSetTlsArrayAddress:
|
|
||||||
/* Can only be set */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadIsIoPending:
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadHideFromDebugger:
|
|
||||||
/* Can only be set */
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
}
|
}
|
||||||
|
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);
|
ObDereferenceObject(Thread);
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue