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=25... ============================================================================== --- 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; }