[NDK]: Add OB_FLAG_KERNEL_EXCLUSIVE and OBJ_KERNEL_EXCLUSIVE flags
authorAlex Ionescu <aionescu@gmail.com>
Thu, 24 Sep 2015 02:40:30 +0000 (02:40 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 24 Sep 2015 02:40:30 +0000 (02:40 +0000)
[NTOSKRNL]: Add a helper function such that user-mode cannot pass certain kernel-only object attributes to ObOpenObjectByPointer.
[NTOSKRNL]: Make \Device\PhysicalMemory OBJ_KERNEL_EXCLUSIVE
[NTOSKRNL]: Deny access to user-mode when opening a handle to an object with OBJ_KERNEL_EXCLUSIVE
[NTOSKRNL]: Fix NtOpenProcess, NtOpenThread, NtOpenThreadTokenEx, NtOpenProcessTokenEx to use the helper function. Should fix Rtl using OBJ_KERNEL_HANDLE in user-mode.
Thanks to ThFabba for finding out these bugs, and the hbelusca for adding a missing check to NtOpenProcessTokenEx.

svn path=/trunk/; revision=69340

reactos/include/ndk/obtypes.h
reactos/ntoskrnl/include/internal/ob_x.h
reactos/ntoskrnl/mm/section.c
reactos/ntoskrnl/ob/obhandle.c
reactos/ntoskrnl/ob/oblife.c
reactos/ntoskrnl/ob/obname.c
reactos/ntoskrnl/ps/process.c
reactos/ntoskrnl/ps/security.c
reactos/ntoskrnl/ps/thread.c
reactos/ntoskrnl/se/token.c

index eb9d919..aa7968f 100644 (file)
@@ -85,6 +85,12 @@ typedef enum _OBJECT_INFORMATION_CLASS
 
 #else
 
+//
+// Undocumented Attribute for Kernel-Only Access
+//
+#define OBJ_KERNEL_EXCLUSIVE                    0x00010000L
+#define OBJ_VALID_KERNEL_ATTRIBUTES             (OBJ_VALID_ATTRIBUTES | \
+                                                 OBJ_KERNEL_EXCLUSIVE)
 //
 // Object Flags
 //
@@ -97,6 +103,11 @@ typedef enum _OBJECT_INFORMATION_CLASS
 #define OB_FLAG_SINGLE_PROCESS                  0x40
 #define OB_FLAG_DEFER_DELETE                    0x80
 
+//
+// Object Flags encoded in "QueryReferences" field
+//
+#define OB_FLAG_KERNEL_EXCLUSIVE                0x40000000
+
 #define OBJECT_TO_OBJECT_HEADER(o)                          \
     CONTAINING_RECORD((o), OBJECT_HEADER, Body)
 
index b64ae13..8e61218 100644 (file)
 
 #define OBP_NAME_LOOKASIDE_MAX_SIZE 248
 
+FORCEINLINE
+ULONG
+ObpValidateAttributes(IN ULONG Attributes,
+                      IN KPROCESSOR_MODE PreviousMode)
+{
+    if (PreviousMode == KernelMode)
+    {
+        /* For kernel, allow any valid attributes */
+        return Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
+    }
+    else
+    {
+        /* For user, mask out kernel-only attributes */
+        return (Attributes & OBJ_VALID_ATTRIBUTES) &
+               ~(OBJ_KERNEL_HANDLE);
+    }
+}
+
 FORCEINLINE
 ULONG
 ObpSelectObjectLockSlot(IN POBJECT_HEADER ObjectHeader)
index f25e3b7..d7a1996 100644 (file)
@@ -2756,7 +2756,7 @@ MmCreatePhysicalMemorySection(VOID)
     SectionSize.QuadPart = 0xFFFFFFFF;
     InitializeObjectAttributes(&Obj,
                                &Name,
-                               OBJ_PERMANENT,
+                               OBJ_PERMANENT | OBJ_KERNEL_EXCLUSIVE,
                                NULL,
                                NULL);
     Status = MmCreateSection((PVOID)&PhysSection,
index e374e8d..94d9622 100644 (file)
@@ -807,6 +807,7 @@ ObpIncrementHandleCount(IN PVOID Object,
     KIRQL CalloutIrql;
     KPROCESSOR_MODE ProbeMode;
     ULONG Total;
+    POBJECT_HEADER_NAME_INFO NameInfo;
     PAGED_CODE();
 
     /* Get the object header and type */
@@ -872,6 +873,16 @@ ObpIncrementHandleCount(IN PVOID Object,
         goto Quickie;
     }
 
+    /* Check for exclusive kernel object */
+    NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+    if ((NameInfo) && (NameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE) &&
+        (ProbeMode != KernelMode))
+    {
+        /* Caller is not kernel, but the object is kernel exclusive */
+        Status = STATUS_ACCESS_DENIED;
+        goto Quickie;
+    }
+
     /*
      * Check if this is an object that went from 0 handles back to existence,
      * but doesn't have an open procedure, only a close procedure. This means
index 10095f7..62b3c25 100644 (file)
@@ -731,10 +731,10 @@ ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
         /* Check if this is a call with the special protection flag */
         if ((PreviousMode == KernelMode) &&
             (ObjectCreateInfo) &&
-            (ObjectCreateInfo->Attributes & 0x10000))
+            (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE))
         {
             /* Set flag which will make the object protected from user-mode */
-            NameInfo->QueryReferences |= 0x40000000;
+            NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE;
         }
 
         /* Set the header pointer */
index 7f6274d..9f0f1f2 100644 (file)
@@ -261,14 +261,14 @@ ObpDeleteNameCheck(IN PVOID Object)
                     ObpDeleteSymbolicLinkName(Object);
                 }
 
-                /* Check if the magic protection flag is set */
+                /* Check if the kernel exclusive is set */
                 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
                 if ((ObjectNameInfo) &&
-                    (ObjectNameInfo->QueryReferences & 0x40000000))
+                    (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE))
                 {
                     /* Remove protection flag */
                     InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences,
-                                           -0x40000000);
+                                           -OB_FLAG_KERNEL_EXCLUSIVE);
                 }
 
                 /* Get the directory */
index a1086da..d3bff78 100644 (file)
@@ -1483,7 +1483,9 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
                          sizeof(OBJECT_ATTRIBUTES),
                          sizeof(ULONG));
             HasObjectName = (ObjectAttributes->ObjectName != NULL);
-            Attributes = ObjectAttributes->Attributes;
+
+            /* Validate user attributes */
+            Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -1496,7 +1498,9 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
     {
         /* Otherwise just get the data directly */
         HasObjectName = (ObjectAttributes->ObjectName != NULL);
-        Attributes = ObjectAttributes->Attributes;
+
+        /* Still have to sanitize attributes */
+        Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
     }
 
     /* Can't pass both, fail */
index 5c8e717..e49e23b 100644 (file)
@@ -371,6 +371,9 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
         _SEH2_END;
     }
 
+    /* Validate object attributes */
+    HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
+
     /* Open the process token */
     Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
     if (NT_SUCCESS(Status))
index 571c2e0..aee19d2 100644 (file)
@@ -1054,7 +1054,9 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
                          sizeof(OBJECT_ATTRIBUTES),
                          sizeof(ULONG));
             HasObjectName = (ObjectAttributes->ObjectName != NULL);
-            Attributes = ObjectAttributes->Attributes;
+
+            /* Validate user attributes */
+            Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -1067,7 +1069,9 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
     {
         /* Otherwise just get the data directly */
         HasObjectName = (ObjectAttributes->ObjectName != NULL);
-        Attributes = ObjectAttributes->Attributes;
+
+        /* Still have to sanitize attributes */
+        Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
     }
 
     /* Can't pass both, fail */
index 65f56fc..ca802c0 100644 (file)
@@ -2952,10 +2952,12 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
         _SEH2_END;
     }
 
+    /* Validate object attributes */
+    HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
+
     /*
      * At first open the thread token for information access and verify
-     * that the token associated with thread is valid.
-     */
+     * that the token associated with thread is valid.     */
 
     Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
                                        PsThreadType, PreviousMode, (PVOID*)&Thread,