[ros-diffs] [ion] 25393: - Merge some local changes from my version of ObpLookupObjectName: - Fixup the way we allocate object names: use paged pool instead of non-paged pool, detect insufficient memory case, detect failure to insert entry into the object directory, use name length, not maximum length when copying, use RtlCopy, not RtlMove. - Support forcing of case-insensitivity and OBJ_FORCE_ACCESS_CHECK. - Call ObCheckCreateObjectAccess and fail if access isn't granted. - Call ObpCheckTraverseAccess if traversing a directory fomr user-mode and fail lookup if access wasn't granted. - Fixup return of proper error code if we reparsed. - Add FIXME note for SeCreateGlobalPrivilege check which is missing. - Add callout IRQL checks around parse callouts. - Rename some variables for clearer meaning. - Add an extra reference when calling the parse routine in the reparse case.

ion at svn.reactos.org ion at svn.reactos.org
Tue Jan 9 08:54:20 CET 2007


Author: ion
Date: Tue Jan  9 10:54:19 2007
New Revision: 25393

URL: http://svn.reactos.org/svn/reactos?rev=25393&view=rev
Log:
- Merge some local changes from my version of ObpLookupObjectName:
   - Fixup the way we allocate object names: use paged pool instead of non-paged pool, detect insufficient memory case, detect failure to insert entry into the object directory, use name length, not maximum length when copying, use RtlCopy, not RtlMove.
   - Support forcing of case-insensitivity and OBJ_FORCE_ACCESS_CHECK.
   - Call ObCheckCreateObjectAccess and fail if access isn't granted.
   - Call ObpCheckTraverseAccess if traversing a directory fomr user-mode and fail lookup if access wasn't granted.
   - Fixup return of proper error code if we reparsed.
   - Add FIXME note for SeCreateGlobalPrivilege check which is missing.
   - Add callout IRQL checks around parse callouts.
   - Rename some variables for clearer meaning.
   - Add an extra reference when calling the parse routine in the reparse case.

Modified:
    trunk/reactos/ntoskrnl/ob/obname.c

Modified: trunk/reactos/ntoskrnl/ob/obname.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ob/obname.c?rev=25393&r1=25392&r2=25393&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ob/obname.c (original)
+++ trunk/reactos/ntoskrnl/ob/obname.c Tue Jan  9 10:54:19 2007
@@ -287,30 +287,46 @@
                     IN KPROCESSOR_MODE AccessMode,
                     IN OUT PVOID ParseContext,
                     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
-                    IN PVOID ExpectedObject,
+                    IN PVOID InsertObject,
                     IN PACCESS_STATE AccessState,
-                    IN POBP_LOOKUP_CONTEXT Context,
-                    OUT PVOID *ReturnedObject)
+                    IN POBP_LOOKUP_CONTEXT LookupContext,
+                    OUT PVOID *FoundObject)
 {
     PVOID RootDirectory;
-    PVOID CurrentDirectory = NULL;
-    PVOID CurrentObject = NULL;
-    POBJECT_HEADER CurrentHeader;
-    NTSTATUS Status = STATUS_SUCCESS;
-    PVOID NewName;
+    PVOID Directory = NULL;
+    PVOID Object;
+    POBJECT_HEADER ObjectHeader;
+    NTSTATUS Status;
+    PWCHAR NewName;
     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
-    UNICODE_STRING RemainingPath, PartName;
+    UNICODE_STRING RemainingName, ComponentName;
     BOOLEAN InsideRoot = FALSE;
+    KPROCESSOR_MODE AccessCheckMode;
     OB_PARSE_METHOD ParseRoutine;
+    KIRQL CalloutIrql;
     PAGED_CODE();
-
-    /* Assume failure */
     OBTRACE(OB_NAMESPACE_DEBUG,
             "%s - Finding Object: %wZ. Expecting: %p\n",
             __FUNCTION__,
             ObjectName,
-            ExpectedObject);
-    *ReturnedObject = NULL;
+            InsertObject);
+
+    /* Initialize starting state */
+    LookupContext->Object = NULL;
+    *FoundObject = NULL;
+    Status = STATUS_SUCCESS;
+    Object = NULL;
+
+    /* Check if case-insensitivity is forced */
+    if ((ObpCaseInsensitive) || (ObjectType->TypeInfo.CaseInsensitive))
+    {
+        /* Add the flag to disable case sensitivity */
+        Attributes |= OBJ_CASE_INSENSITIVE;
+    }
+
+    /* Check if this is a access checks are being forced */
+    AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ?
+                       UserMode : AccessMode;
 
     /* Check if we got a Root Directory */
     if (RootHandle)
@@ -325,12 +341,12 @@
         if (!NT_SUCCESS(Status)) return Status;
 
         /* Get the header */
-        CurrentHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
+        ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
 
         /* The name cannot start with a separator, unless this is a file */
         if ((ObjectName->Buffer) &&
             (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
-            (CurrentHeader->Type != IoFileObjectType))
+            (ObjectHeader->Type != IoFileObjectType))
         {
             /* The syntax is bad, so fail this request */
             ObDereferenceObject(RootDirectory);
@@ -338,10 +354,10 @@
         }
 
         /* Don't parse a Directory */
-        if (CurrentHeader->Type != ObDirectoryType)
+        if (ObjectHeader->Type != ObDirectoryType)
         {
             /* Make sure the Object Type has a parse routine */
-            ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
+            ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
             if (!ParseRoutine)
             {
                 /* We can't parse a name if we don't have a parse routine */
@@ -353,19 +369,21 @@
             while (TRUE)
             {
                 /* Start with the full name */
-                RemainingPath = *ObjectName;
+                RemainingName = *ObjectName;
 
                 /* Call the Parse Procedure */
+                ObpCalloutStart(&CalloutIrql);
                 Status = ParseRoutine(RootDirectory,
                                       ObjectType,
                                       AccessState,
                                       AccessMode,
                                       Attributes,
                                       ObjectName,
-                                      &RemainingPath,
+                                      &RemainingName,
                                       ParseContext,
                                       SecurityQos,
-                                      &CurrentObject);
+                                      &Object);
+                ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
 
                 /* Check for success or failure, so not reparse */
                 if ((Status != STATUS_REPARSE) &&
@@ -375,16 +393,16 @@
                     if (!NT_SUCCESS(Status))
                     {
                         /* Parse routine might not have cleared this, do it */
-                        CurrentObject = NULL;
+                        Object = NULL;
                     }
-                    else if (!CurrentObject)
+                    else if (!Object)
                     {
                         /* Modify status to reflect failure inside Ob */
                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
                     }
 
                     /* We're done, return the status and object */
-                    *ReturnedObject = CurrentObject;
+                    *FoundObject = Object;
                     ObDereferenceObject(RootDirectory);
                     return Status;
                 }
@@ -409,8 +427,11 @@
                                                 0,
                                                 ObjectType,
                                                 AccessMode);
-            if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
+            if (NT_SUCCESS(Status)) Object = RootDirectory;
+
+            /* Remove the first reference we added and return the object */
             ObDereferenceObject(RootDirectory);
+            *FoundObject = Object;
             return Status;
         }
     }
@@ -435,14 +456,14 @@
             if (!RootDirectory)
             {
                 /* This must be the first time we're creating it... right? */
-                if (ExpectedObject)
+                if (InsertObject)
                 {
                     /* Yes, so return it to ObInsert so that it can create it */
-                    Status = ObReferenceObjectByPointer(ExpectedObject,
+                    Status = ObReferenceObjectByPointer(InsertObject,
                                                         0,
                                                         ObjectType,
                                                         AccessMode);
-                    if (NT_SUCCESS(Status)) *ReturnedObject = ExpectedObject;
+                    if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
                     return Status;
                 }
                 else
@@ -459,7 +480,7 @@
                                                     0,
                                                     ObjectType,
                                                     AccessMode);
-                if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
+                if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
                 return Status;
             }
         }
@@ -467,7 +488,7 @@
 
     /* Save the name */
 ReparseNewDir:
-    RemainingPath = *ObjectName;
+    RemainingName = *ObjectName;
 
     /* Reparse */
     while (TRUE)
@@ -476,121 +497,171 @@
         if (!InsideRoot)
         {
             /* Yes, use the root directory and remember that */
-            CurrentDirectory = RootDirectory;
+            Directory = RootDirectory;
             InsideRoot = TRUE;
         }
 
         /* Check if the name starts with a path separator */
-        if ((RemainingPath.Length) &&
-            (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
+        if ((RemainingName.Length) &&
+            (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
         {
             /* Skip the path separator */
-            RemainingPath.Buffer++;
-            RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+            RemainingName.Buffer++;
+            RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
         }
 
         /* Find the next Part Name */
-        PartName = RemainingPath;
-        while (RemainingPath.Length)
+        ComponentName = RemainingName;
+        while (RemainingName.Length)
         {
             /* Break if we found the \ ending */
-            if (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
+            if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
 
             /* Move on */
-            RemainingPath.Buffer++;
-            RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+            RemainingName.Buffer++;
+            RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
         }
 
         /* Get its size and make sure it's valid */
-        if (!(PartName.Length -= RemainingPath.Length))
+        if (!(ComponentName.Length -= RemainingName.Length))
         {
             Status = STATUS_OBJECT_NAME_INVALID;
             break;
         }
 
         /* Do the look up */
-        Context->DirectoryLocked = TRUE;
-        Context->Directory = CurrentDirectory;
-        CurrentObject = ObpLookupEntryDirectory(CurrentDirectory,
-                                                &PartName,
+        LookupContext->DirectoryLocked = TRUE;
+        LookupContext->Directory = Directory;
+        Object = ObpLookupEntryDirectory(Directory,
+                                                &ComponentName,
                                                 Attributes,
-                                                FALSE,
-                                                Context);
-        if (!CurrentObject)
+                                                InsertObject ? FALSE : TRUE,
+                                                LookupContext);
+        if (!Object)
         {
             /* We didn't find it... do we still have a path? */
-            if (RemainingPath.Length)
+            if (RemainingName.Length)
             {
                 /* Then tell the caller the path wasn't found */
                 Status = STATUS_OBJECT_PATH_NOT_FOUND;
                 break;
             }
-            else if (!ExpectedObject)
+            else if (!InsertObject)
             {
                 /* Otherwise, we have a path, but the name isn't valid */
                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
                 break;
             }
 
-            /* Reference newly to be inserted object */
-            ObReferenceObject(ExpectedObject);
-            CurrentHeader = OBJECT_TO_OBJECT_HEADER(ExpectedObject);
-
-            /* Create Object Name */
-            NewName = ExAllocatePoolWithTag(NonPagedPool,
-                                            PartName.MaximumLength,
-                                            OB_NAME_TAG);
-            ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(CurrentHeader);
-
-            /* Copy the Name */
-            RtlMoveMemory(NewName, PartName.Buffer, PartName.MaximumLength);
-
-            /* Free old name */
-            if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer);
-
-            /* Write new one */
-            ObjectNameInfo->Name.Buffer = NewName;
-            ObjectNameInfo->Name.Length = PartName.Length;
-            ObjectNameInfo->Name.MaximumLength = PartName.MaximumLength;
-
-            /* Rereference the Directory and insert */
-            ObReferenceObject(CurrentDirectory);
-            ObpInsertEntryDirectory(CurrentDirectory, Context, CurrentHeader);
-
-            /* Return Status and the Expected Object */
-            Status = STATUS_SUCCESS;
-            CurrentObject = ExpectedObject;
-
-            /* Get out of here */
-            break;
+            /* Check create access for the object */
+            if (!ObCheckCreateObjectAccess(Directory,
+                                           ObjectType == ObDirectoryType ?
+                                           DIRECTORY_CREATE_SUBDIRECTORY :
+                                           DIRECTORY_CREATE_OBJECT,
+                                           AccessState,
+                                           &ComponentName,
+                                           FALSE,
+                                           AccessCheckMode,
+                                           &Status))
+            {
+                /* We don't have create access, fail */
+                break;
+            }
+
+                /* Get the object header */
+                ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject);
+
+                /* FIXME: Check if this is a Section Object or Sym Link */
+                /* FIXME: If it is, then check if this isn't session 0 */
+                /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
+                /* FIXME: If privilege isn't there, check for unsecure name */
+                /* FIXME: If it isn't a known unsecure name, then fail */
+
+                /* Create Object Name */
+                NewName = ExAllocatePoolWithTag(PagedPool,
+                                                ComponentName.Length,
+                                                OB_NAME_TAG);
+                if (!(NewName) ||
+                    !(ObpInsertEntryDirectory(Directory,
+                                              LookupContext,
+                                              ObjectHeader)))
+                {
+                    /* Either couldn't allocate the name, or insert failed */
+                    if (NewName) ExFreePool(NewName);
+
+                    /* Fail due to memory reasons */
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                    break;
+                }
+
+                /* Reference newly to be inserted object */
+                ObReferenceObject(InsertObject);
+
+                /* Get the name information */
+                ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+
+                /* Reference the directory */
+                ObReferenceObject(Directory);
+
+                /* Copy the Name */
+                RtlCopyMemory(NewName,
+                              ComponentName.Buffer,
+                              ComponentName.Length);
+
+                /* Check if we had an old name */
+                if (ObjectNameInfo->Name.Buffer)
+                {
+                    /* Free it */
+                    ExFreePool(ObjectNameInfo->Name.Buffer);
+                }
+
+                /* Write new one */
+                ObjectNameInfo->Name.Buffer = NewName;
+                ObjectNameInfo->Name.Length = ComponentName.Length;
+                ObjectNameInfo->Name.MaximumLength = ComponentName.Length;
+
+                /* Return Status and the Expected Object */
+                Status = STATUS_SUCCESS;
+                Object = InsertObject;
+
+                /* Get out of here */
+                break;
         }
 
 Reparse:
         /* We found it, so now get its header */
-        CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
+        ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
 
         /*
          * Check for a parse Procedure, but don't bother to parse for an insert
          * unless it's a Symbolic Link, in which case we MUST parse
          */
-        ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
-        if (ParseRoutine &&
-            (!ExpectedObject || ParseRoutine == ObpParseSymbolicLink))
+        ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
+        if ((ParseRoutine) &&
+            (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
         {
             /* Use the Root Directory next time */
             InsideRoot = FALSE;
 
+            /* Increment the pointer count */
+            InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
+
             /* Call the Parse Procedure */
-            Status = ParseRoutine(CurrentObject,
+            ObpCalloutStart(&CalloutIrql);
+            Status = ParseRoutine(Object,
                                   ObjectType,
                                   AccessState,
                                   AccessMode,
                                   Attributes,
                                   ObjectName,
-                                  &RemainingPath,
+                                  &RemainingName,
                                   ParseContext,
                                   SecurityQos,
-                                  &CurrentObject);
+                                  &Object);
+            ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
+
+            /* Remove our extra reference */
+            ObDereferenceObject(&ObjectHeader->Body);
 
             /* Check if we have to reparse */
             if ((Status == STATUS_REPARSE) ||
@@ -615,7 +686,7 @@
                     if (Status == STATUS_REPARSE_OBJECT)
                     {
                         /* Did we actually get an object to which to reparse? */
-                        if (!CurrentObject)
+                        if (!Object)
                         {
                             /* We didn't, so set a failure status */
                             Status = STATUS_OBJECT_NAME_NOT_FOUND;
@@ -634,16 +705,16 @@
                 else if (RootDirectory == NameSpaceRoot)
                 {
                     /* We got STATUS_REPARSE but are at the Root Directory */
-                    CurrentObject = NULL;
+                    Object = NULL;
                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
                 }
             }
             else if (!NT_SUCCESS(Status))
             {
                 /* Total failure */
-                CurrentObject = NULL;
-            }
-            else if (!CurrentObject)
+                Object = NULL;
+            }
+            else if (!Object)
             {
                 /* We didn't reparse but we didn't find the Object Either */
                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
@@ -655,17 +726,35 @@
         else
         {
             /* No parse routine...do we still have a remaining name? */
-            if (!RemainingPath.Length)
+            if (!RemainingName.Length)
             {
                 /* Are we creating an object? */
-                if (!ExpectedObject)
-                {
-                    /* We don't... reference the Object */
-                    Status = ObReferenceObjectByPointer(CurrentObject,
+                if (!InsertObject)
+                {
+                    /* Check if this is a user-mode call that needs to traverse */
+                    if ((AccessCheckMode != KernelMode) &&
+                        !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
+                    {
+                        /* Check if we can get it */
+                        if (!ObpCheckTraverseAccess(Directory,
+                                                    DIRECTORY_TRAVERSE,
+                                                    AccessState,
+                                                    FALSE,
+                                                    AccessCheckMode,
+                                                    &Status))
+                        {
+                            /* We don't have access, fail */
+                            Object = NULL;
+                            break;
+                        }
+                    }
+
+                    /* Reference the Object */
+                    Status = ObReferenceObjectByPointer(Object,
                                                         0,
                                                         ObjectType,
                                                         AccessMode);
-                    if (!NT_SUCCESS(Status)) CurrentObject = NULL;
+                    if (!NT_SUCCESS(Status)) Object = NULL;
                 }
 
                 /* And get out of the reparse loop */
@@ -674,42 +763,51 @@
             else
             {
                 /* We still have a name; check if this is a directory object */
-                if (CurrentHeader->Type == ObDirectoryType)
+                if (ObjectHeader->Type == ObDirectoryType)
                 {
                     /* Restart from this directory */
-                    CurrentDirectory = CurrentObject;
+                    Directory = Object;
                 }
                 else
                 {
                     /* We still have a name, but no parse routine for it */
                     Status = STATUS_OBJECT_TYPE_MISMATCH;
-                    CurrentObject = NULL;
+                    Object = NULL;
                     break;
                 }
             }
         }
     }
 
-    /* Write what we found, and if it's null, check if we got success */
-    if (!(*ReturnedObject = CurrentObject) && (NT_SUCCESS(Status)))
-    {
-        /* Nothing found... but we have success. Correct the status code */
-        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Cleanup after lookup */
+        //ObpCleanupDirectoryLookup(LookupContext, TRUE);
+        LookupContext->Object = NULL;
+    }
+
+    /* Set the found object and check if we got one */
+    *FoundObject = Object;
+    if (!Object)
+    {
+        /* Nothing was found. Did we reparse or get success? */
+        if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status)))
+        {
+            /* Set correct failure */
+            Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        }
     }
 
     /* Check if we had a root directory */
-    if (RootHandle)
-    {
-        /* Dereference it */
-        ObDereferenceObject(RootDirectory);
-    }
+    if (RootHandle) ObDereferenceObject(RootDirectory);
 
     /* Return status to caller */
     OBTRACE(OB_NAMESPACE_DEBUG,
             "%s - Found Object: %p. Expected: %p\n",
             __FUNCTION__,
-            *ReturnedObject,
-            ExpectedObject);
+            *FoundObject,
+            InsertObject);
     return Status;
 }
 




More information about the Ros-diffs mailing list