- Check the caller pointers in all cases.  
- Simplified the thread info functions a little bit.
Modified: trunk/reactos/ntoskrnl/ps/tinfo.c

Modified: trunk/reactos/ntoskrnl/ps/tinfo.c
--- trunk/reactos/ntoskrnl/ps/tinfo.c	2005-01-01 11:53:38 UTC (rev 12697)
+++ trunk/reactos/ntoskrnl/ps/tinfo.c	2005-01-01 11:57:53 UTC (rev 12698)
@@ -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
  * PROJECT:         ReactOS kernel
@@ -16,6 +16,69 @@
 #include <ntoskrnl.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 *****************************************************************/
 
 /*
@@ -29,7 +92,30 @@
 {
   PETHREAD Thread;
   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,
 				      THREAD_SET_INFORMATION,
 				      PsThreadType,
@@ -41,174 +127,62 @@
 	return Status;
      }
 
-  switch (ThreadInformationClass)
-    {
-      case ThreadBasicInformation:
-	/* Can only be queried */
-	Status = STATUS_INVALID_INFO_CLASS;
-	break;
+   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 ThreadTimes:
-	/* Can only be queried */
-	Status = STATUS_INVALID_INFO_CLASS;
-	break;
+           case ThreadBasePriority:
+	     KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
+	     break;
 	
-      case ThreadPriority:
-	  {
-	    KPRIORITY Priority;
-
-	    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 ThreadAffinityMask:
+	     Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
+	     break;
 	
-      case ThreadBasePriority:
-	  {
-	    LONG Increment;
-
-	    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;
-
+           case ThreadImpersonationToken:
+	     Status = PsAssignImpersonationToken (Thread, u.Handle);
+	     break;
+		
 #ifdef _ENABLE_THRDEVTPAIR
-      case ThreadEventPair:
-	{
-	  PKEVENT_PAIR EventPair;
+           case ThreadEventPair:
+	     {
+	       PKEVENT_PAIR EventPair;
 
-	  if (ThreadInformationLength != sizeof(HANDLE))
-	    {
-	      Status = STATUS_INFO_LENGTH_MISMATCH;
-	      break;
-	    }
-
-	  if (ExGetPreviousMode() == UserMode) /* FIXME: Validate this for all infoclasses and system services */
-	    {
-	      DPRINT("NtSetInformationThread:ThreadEventPair: Checking user pointer %08x...\n", ThreadInformation);
-	      ProbeForRead(ThreadInformation, sizeof(HANDLE), sizeof(HANDLE)); /* FIXME: This entire function should be
-	       * wrapped in an SEH frame... return (NTSTATUS)GetExceptionCode() on exception */
-	    }
-
-	  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;
-	}
+	       Status = ObReferenceObjectByHandle(u.Handle,
+					          STANDARD_RIGHTS_ALL,
+					          ExEventPairObjectType,
+					          ExGetPreviousMode(),
+					          (PVOID*)&EventPair,
+					          NULL);
+	       if (NT_SUCCESS(Status))
+	         {
+                   ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
+		 }
+               break;
+	     }
 #endif /* _ENABLE_THRDEVTPAIR */
 	
-      case ThreadQuerySetWin32StartAddress:
-	if (ThreadInformationLength != sizeof(ULONG))
-	  {
-	    Status = STATUS_INFO_LENGTH_MISMATCH;
-	    break;
-	  }
-	Thread->Win32StartAddress = (PVOID)*((PULONG)ThreadInformation);
-	Status = STATUS_SUCCESS;
-	break;
+           case ThreadQuerySetWin32StartAddress:
+	     Thread->Win32StartAddress = u.Address;
+	     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);
 
   return Status;
@@ -226,7 +200,30 @@
 {
    PETHREAD Thread;
    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,
 				      THREAD_QUERY_INFORMATION,
 				      PsThreadType,
@@ -240,161 +237,70 @@
 
    switch (ThreadInformationClass)
      {
-     case ThreadBasicInformation:
-       {
-	 PTHREAD_BASIC_INFORMATION TBI;
-	 
-	 TBI = (PTHREAD_BASIC_INFORMATION)ThreadInformation;
-	 
-	 if (ThreadInformationLength != sizeof(THREAD_BASIC_INFORMATION))
-	   {
-	     Status = STATUS_INFO_LENGTH_MISMATCH;
-	     break;
-	   }
-	 
-    /* 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;
+       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:
-	 {
-	    PKERNEL_USER_TIMES TTI;
-	 
-	    TTI = (PKERNEL_USER_TIMES)ThreadInformation;
-	 
-	    if (ThreadInformationLength != sizeof(KERNEL_USER_TIMES))
-	      {
-	        Status = STATUS_INFO_LENGTH_MISMATCH;
-	        break;
-	      }
+       case ThreadTimes:
+	 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
+         u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
+         u.TTI.CreateTime = (TIME) Thread->CreateTime;
+         /*This works*/
+	 u.TTI.ExitTime = (TIME) Thread->ExitTime;
+         break;
 
-            TTI->KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
-            TTI->UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
-            TTI->CreateTime = (TIME) Thread->CreateTime;
-            /*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 ThreadQuerySetWin32StartAddress:
+         u.Address = Thread->Win32StartAddress;
+         break;
 
-     case ThreadImpersonationToken:
-       /* Can be set only */
-       Status = STATUS_INVALID_INFO_CLASS;
-       break;
-       
-     case ThreadDescriptorTableEntry:
-       /* Nebbett says nothing about this */
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
+       case ThreadPerformanceCount:
+         /* Nebbett says this class is always zero */
+         u.Count.QuadPart = 0;
+         break;
 
-     case ThreadEnableAlignmentFaultFixup:
-       /* Can be set only */
-       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 ==
+       case ThreadAmILastThread:
+         if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
 	     &Thread->ThreadsProcess->ThreadListHead)
 	   {
-	     *((PBOOLEAN)ThreadInformation) = TRUE;
+	     u.Last = TRUE;
 	   }
-	 else
+         else
 	   {
-	     *((PBOOLEAN)ThreadInformation) = FALSE;
+	     u.Last = FALSE;
 	   }
-	 Status = STATUS_SUCCESS;
-	 break;
-       }
-
-     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;
+         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);
 }