- 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:
Hartmut Birr 2005-01-01 11:57:53 +00:00
parent 38d12a5ce6
commit 6bd1cc19a3

View file

@ -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);
} }