- Fix MSVC breakage caused by recent modifications of cctypes.h.

- Remove structures from ntifs.h that shouldn't be there.
- Add support for optimized detection of a DOS device path \?? or \??\ and implement it into ObpLookupObjectName.
- Add support for proper re-parsing up to a maximum of 30 times to avoid reparse DOS attacks on the kernel.
- Set WIN32_WINNT version to Windows 2003 SP1.

svn path=/trunk/; revision=25602
This commit is contained in:
Alex Ionescu 2007-01-22 22:16:13 +00:00
parent b5edfb619c
commit 89056c2f7a
7 changed files with 546 additions and 427 deletions

View file

@ -50,6 +50,9 @@ extern "C" {
#define NTSYSAPI #define NTSYSAPI
#endif #endif
#define EX_PUSH_LOCK ULONG_PTR
#define PEX_PUSH_LOCK PULONG_PTR
#include "csq.h" #include "csq.h"
typedef struct _SE_EXPORTS *PSE_EXPORTS; typedef struct _SE_EXPORTS *PSE_EXPORTS;
@ -1402,35 +1405,6 @@ typedef struct _PATHNAME_BUFFER {
WCHAR Name[1]; WCHAR Name[1];
} PATHNAME_BUFFER, *PPATHNAME_BUFFER; } PATHNAME_BUFFER, *PPATHNAME_BUFFER;
#if (VER_PRODUCTBUILD >= 2600)
typedef struct _PRIVATE_CACHE_MAP_FLAGS {
ULONG DontUse : 16;
ULONG ReadAheadActive : 1;
ULONG ReadAheadEnabled : 1;
ULONG Available : 14;
} PRIVATE_CACHE_MAP_FLAGS, *PPRIVATE_CACHE_MAP_FLAGS;
typedef struct _PRIVATE_CACHE_MAP {
_ANONYMOUS_UNION union {
CSHORT NodeTypeCode;
PRIVATE_CACHE_MAP_FLAGS Flags;
ULONG UlongFlags;
} DUMMYUNIONNAME;
ULONG ReadAheadMask;
PFILE_OBJECT FileObject;
LARGE_INTEGER FileOffset1;
LARGE_INTEGER BeyondLastByte1;
LARGE_INTEGER FileOffset2;
LARGE_INTEGER BeyondLastByte2;
LARGE_INTEGER ReadAheadOffset[2];
ULONG ReadAheadLength[2];
KSPIN_LOCK ReadAheadSpinLock;
LIST_ENTRY PrivateLinks;
} PRIVATE_CACHE_MAP, *PPRIVATE_CACHE_MAP;
#endif
typedef enum _RTL_GENERIC_COMPARE_RESULTS typedef enum _RTL_GENERIC_COMPARE_RESULTS
{ {
GenericLessThan, GenericLessThan,
@ -1715,16 +1689,6 @@ typedef struct _TUNNEL {
USHORT NumEntries; USHORT NumEntries;
} TUNNEL, *PTUNNEL; } TUNNEL, *PTUNNEL;
typedef struct _VACB {
PVOID BaseAddress;
PSHARED_CACHE_MAP SharedCacheMap;
union {
LARGE_INTEGER FileOffset;
USHORT ActiveCount;
} Overlay;
LIST_ENTRY LruList;
} VACB, *PVACB;
typedef struct _VAD_HEADER { typedef struct _VAD_HEADER {
PVOID StartVPN; PVOID StartVPN;
PVOID EndVPN; PVOID EndVPN;

View file

@ -35,54 +35,101 @@ extern ULONG NTSYSAPI CcFastReadResourceMiss;
extern ULONG NTSYSAPI CcFastReadNoWait; extern ULONG NTSYSAPI CcFastReadNoWait;
extern ULONG NTSYSAPI CcFastMdlReadNotPossible; extern ULONG NTSYSAPI CcFastMdlReadNotPossible;
//
// Virtual Address Control BLock
//
typedef struct _VACB
{
PVOID BaseAddress;
struct _SHARED_CACHE_MAP *SharedCacheMap;
union
{
LARGE_INTEGER FileOffset;
USHORT ActiveCount;
} Overlay;
LIST_ENTRY LruList;
} VACB, *PVACB;
//
// Private Cache Map Structure and Flags
//
typedef struct _PRIVATE_CACHE_MAP_FLAGS
{
ULONG DontUse:16;
ULONG ReadAheadActive:1;
ULONG ReadAheadEnabled:1;
ULONG Available:14;
} PRIVATE_CACHE_MAP_FLAGS;
typedef struct _PRIVATE_CACHE_MAP
{
union
{
CSHORT NodeTypeCode;
PRIVATE_CACHE_MAP_FLAGS Flags;
ULONG UlongFlags;
};
ULONG ReadAheadMask;
PFILE_OBJECT FileObject;
LARGE_INTEGER FileOffset1;
LARGE_INTEGER BeyondLastByte1;
LARGE_INTEGER FileOffset2;
LARGE_INTEGER BeyondLastByte2;
LARGE_INTEGER ReadAheadOffset[2];
ULONG ReadAheadLength[2];
KSPIN_LOCK ReadAheadSpinLock;
LIST_ENTRY PrivateLinks;
} PRIVATE_CACHE_MAP, *PPRIVATE_CACHE_MAP;
#ifdef _NTIFS_INCLUDED_ #ifdef _NTIFS_INCLUDED_
typedef struct _SHARED_CACHE_MAP { //
SHORT NodeTypeCode; // Shared Cache Map
SHORT NodeByteSize; //
ULONG OpenCount; typedef struct _SHARED_CACHE_MAP
LARGE_INTEGER FileSize; {
LIST_ENTRY BcbList; SHORT NodeTypeCode;
LARGE_INTEGER SectionSize; SHORT NodeByteSize;
LARGE_INTEGER ValidDataLength; ULONG OpenCount;
LARGE_INTEGER ValidDataGoal; LARGE_INTEGER FileSize;
PVACB InitialVacbs[4]; LIST_ENTRY BcbList;
PVACB Vacbs; LARGE_INTEGER SectionSize;
PFILE_OBJECT FileObject; LARGE_INTEGER ValidDataLength;
PVACB ActiveVacb; LARGE_INTEGER ValidDataGoal;
PVOID NeedToZero; PVACB InitialVacbs[4];
ULONG ActivePage; PVACB Vacbs;
ULONG NeedToZeroPage; PFILE_OBJECT FileObject;
ULONG ActiveVacbSpinLock; PVACB ActiveVacb;
ULONG VacbActiveCount; PVOID NeedToZero;
ULONG DirtyPages; ULONG ActivePage;
LIST_ENTRY SharedCacheMapLinks; ULONG NeedToZeroPage;
ULONG Flags; ULONG ActiveVacbSpinLock;
ULONG Status; ULONG VacbActiveCount;
PMCB Mbcb; ULONG DirtyPages;
PVOID Section; LIST_ENTRY SharedCacheMapLinks;
PKEVENT CreateEvent; ULONG Flags;
PKEVENT WaitOnActiveCount; ULONG Status;
ULONG PagesToWrite; PMCB Mbcb;
LONGLONG BeyondLastFlush; PVOID Section;
PCACHE_MANAGER_CALLBACKS Callbacks; PKEVENT CreateEvent;
PVOID LazyWriteContext; PKEVENT WaitOnActiveCount;
PLIST_ENTRY PrivateList; ULONG PagesToWrite;
PVOID LogHandle; LONGLONG BeyondLastFlush;
PVOID FlushToLsnRoutine; PCACHE_MANAGER_CALLBACKS Callbacks;
ULONG DirtyPageThreshold; PVOID LazyWriteContext;
ULONG LazyWritePassCount; PLIST_ENTRY PrivateList;
PCACHE_UNINITIALIZE_EVENT UninitializeEvent; PVOID LogHandle;
PVACB NeedToZeroVacb; PVOID FlushToLsnRoutine;
ULONG BcbSpinLock; ULONG DirtyPageThreshold;
PVOID Reserved; ULONG LazyWritePassCount;
KEVENT Event; PCACHE_UNINITIALIZE_EVENT UninitializeEvent;
/* FIX ME: This should be PEX_PUSH_LOCK */ PVACB NeedToZeroVacb;
PVOID VacbPushLock; ULONG BcbSpinLock;
PPRIVATE_CACHE_MAP PrivateCacheMap; PVOID Reserved;
} SHARED_CACHE_MAP; KEVENT Event;
PEX_PUSH_LOCK VacbPushLock;
PPRIVATE_CACHE_MAP PrivateCacheMap;
} SHARED_CACHE_MAP;
#endif /* _NTIFS_INCLUDED_ */ #endif /* _NTIFS_INCLUDED_ */
#endif /* NTOS_MODE_USER */ #endif /* NTOS_MODE_USER */

View file

@ -362,7 +362,7 @@ ExTimedWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
VOID VOID
FASTCALL FASTCALL
ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock, ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock) IN PVOID WaitBlock)
{ {
/* Call the timed function with no timeout */ /* Call the timed function with no timeout */
ExTimedWaitForUnblockPushLock(PushLock, WaitBlock, NULL); ExTimedWaitForUnblockPushLock(PushLock, WaitBlock, NULL);

View file

@ -652,18 +652,24 @@ _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
VOID VOID
FASTCALL FASTCALL
ExBlockPushLock(PEX_PUSH_LOCK PushLock, ExBlockPushLock(
PVOID WaitBlock); IN PEX_PUSH_LOCK PushLock,
IN PVOID WaitBlock
);
VOID VOID
FASTCALL FASTCALL
ExfUnblockPushLock(PEX_PUSH_LOCK PushLock, ExfUnblockPushLock(
PVOID CurrentWaitBlock); IN PEX_PUSH_LOCK PushLock,
IN PVOID CurrentWaitBlock
);
VOID VOID
FASTCALL FASTCALL
ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock, ExWaitForUnblockPushLock(
IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock); IN PEX_PUSH_LOCK PushLock,
IN PVOID WaitBlock
);
/*++ /*++
* @name ExInitializePushLock * @name ExInitializePushLock

View file

@ -102,6 +102,15 @@ typedef struct _OBP_FIND_HANDLE_DATA
POBJECT_HANDLE_INFORMATION HandleInformation; POBJECT_HANDLE_INFORMATION HandleInformation;
} OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA; } OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA;
//
// Structure for quick-compare of a DOS Device path
//
typedef union
{
WCHAR Name[sizeof(ULARGE_INTEGER) / sizeof(WCHAR)];
ULARGE_INTEGER Alignment;
} ALIGNEDNAME;
// //
// Private Temporary Buffer for Lookup Routines // Private Temporary Buffer for Lookup Routines
// //
@ -502,6 +511,9 @@ extern WORK_QUEUE_ITEM ObpReaperWorkItem;
extern volatile PVOID ObpReaperList; extern volatile PVOID ObpReaperList;
extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList; extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
extern BOOLEAN IoCountOperations; extern BOOLEAN IoCountOperations;
extern ALIGNEDNAME ObpDosDevicesShortNamePrefix;
extern ALIGNEDNAME ObpDosDevicesShortNameRoot;
extern UNICODE_STRING ObpDosDevicesShortName;
// //
// Inlined Functions // Inlined Functions

View file

@ -9,7 +9,7 @@
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
/* Always target Windows 2003 Service Pack 1 */ /* Always target Windows 2003 Service Pack 1 */
#undef NTDDI_VERSION #define _WIN32_WINNT _WIN32_WINNT_WS03
#define NTDDI_VERSION NTDDI_WS03SP1 #define NTDDI_VERSION NTDDI_WS03SP1
#define NTKERNELAPI #define NTKERNELAPI

View file

@ -16,8 +16,18 @@
#include <debug.h> #include <debug.h>
BOOLEAN ObpCaseInsensitive = TRUE; BOOLEAN ObpCaseInsensitive = TRUE;
POBJECT_DIRECTORY NameSpaceRoot = NULL; POBJECT_DIRECTORY NameSpaceRoot;
POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL; POBJECT_DIRECTORY ObpTypeDirectoryObject;
/* DOS Device Prefix \??\ and \?? */
ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}};
ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}};
UNICODE_STRING ObpDosDevicesShortName =
{
sizeof(ObpDosDevicesShortNamePrefix),
sizeof(ObpDosDevicesShortNamePrefix),
(PWSTR)&ObpDosDevicesShortNamePrefix
};
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
@ -256,22 +266,22 @@ ObpDeleteNameCheck(IN PVOID Object)
NTSTATUS NTSTATUS
NTAPI NTAPI
ObpLookupObjectName(IN HANDLE RootHandle, ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
IN PUNICODE_STRING ObjectName, IN PUNICODE_STRING ObjectName,
IN ULONG Attributes, IN ULONG Attributes,
IN POBJECT_TYPE ObjectType, IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode, IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext, IN OUT PVOID ParseContext,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
IN PVOID InsertObject, IN PVOID InsertObject OPTIONAL,
IN PACCESS_STATE AccessState, IN OUT PACCESS_STATE AccessState,
IN POBP_LOOKUP_CONTEXT LookupContext, OUT POBP_LOOKUP_CONTEXT LookupContext,
OUT PVOID *FoundObject) OUT PVOID *FoundObject)
{ {
PVOID Object; PVOID Object;
POBJECT_HEADER ObjectHeader; POBJECT_HEADER ObjectHeader;
UNICODE_STRING ComponentName, RemainingName; UNICODE_STRING ComponentName, RemainingName;
BOOLEAN InsideRoot = FALSE; BOOLEAN Reparse = FALSE, SymLink = FALSE;
PDEVICE_MAP DeviceMap = NULL; PDEVICE_MAP DeviceMap = NULL;
POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
@ -281,6 +291,7 @@ ObpLookupObjectName(IN HANDLE RootHandle,
KPROCESSOR_MODE AccessCheckMode; KPROCESSOR_MODE AccessCheckMode;
PWCHAR NewName; PWCHAR NewName;
POBJECT_HEADER_NAME_INFO ObjectNameInfo; POBJECT_HEADER_NAME_INFO ObjectNameInfo;
ULONG MaxReparse = 30;
PAGED_CODE(); PAGED_CODE();
OBTRACE(OB_NAMESPACE_DEBUG, OBTRACE(OB_NAMESPACE_DEBUG,
"%s - Finding Object: %wZ. Expecting: %p\n", "%s - Finding Object: %wZ. Expecting: %p\n",
@ -346,6 +357,9 @@ ObpLookupObjectName(IN HANDLE RootHandle,
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
/* Set default parse count */
MaxReparse = 30;
/* Now parse */ /* Now parse */
while (TRUE) while (TRUE)
{ {
@ -397,7 +411,22 @@ ObpLookupObjectName(IN HANDLE RootHandle,
/* Don't use this anymore, since we're starting at root */ /* Don't use this anymore, since we're starting at root */
RootHandle = NULL; RootHandle = NULL;
break; goto ParseFromRoot;
}
else if (--MaxReparse)
{
/* Try reparsing again */
continue;
}
else
{
/* Reparsed too many times */
ObDereferenceObject(RootDirectory);
/* Return the object and normalized status */
*FoundObject = Object;
if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND;
return Status;
} }
} }
} }
@ -465,373 +494,434 @@ ObpLookupObjectName(IN HANDLE RootHandle,
return Status; return Status;
} }
} }
} else
/* Save the name */
ReparseNewDir:
RemainingName = *ObjectName;
/* Reparse */
while (TRUE)
{
/* Check if we should use the Root Directory */
if (!InsideRoot)
{ {
/* Yes, use the root directory and remember that */ ParseFromRoot:
Directory = RootDirectory; /* Check if we have a device map */
InsideRoot = TRUE; if (DeviceMap)
}
/* Check if the name starts with a path separator */
if ((RemainingName.Length) &&
(RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
{
/* Skip the path separator */
RemainingName.Buffer++;
RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
}
/* Find the next Part Name */
ComponentName = RemainingName;
while (RemainingName.Length)
{
/* Break if we found the \ ending */
if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
/* Move on */
RemainingName.Buffer++;
RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
}
/* Get its size and make sure it's valid */
ComponentName.Length -= RemainingName.Length;
if (!ComponentName.Length)
{
/* Invalid size, fail */
Status = STATUS_OBJECT_NAME_INVALID;
break;
}
/* Check if this is a user-mode call that needs to traverse */
if ((AccessCheckMode != KernelMode) &&
!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
{
/* We shouldn't have referenced a directory yet */
ASSERT(ReferencedDirectory == NULL);
/* Reference the directory */
ObReferenceObject(Directory);
ReferencedDirectory = Directory;
/* Check if we have a parent directory */
if (ParentDirectory)
{ {
/* Check for traverse access */ /* Dereference it */
if (!ObpCheckTraverseAccess(ParentDirectory, ObfDereferenceDeviceMap(DeviceMap);
DIRECTORY_TRAVERSE, DeviceMap = NULL;
AccessState, }
FALSE,
AccessCheckMode, /* Check if this is a possible DOS name */
&Status)) if (!((ULONG_PTR)(ObjectName->Buffer) & 7))
{
/*
* This could be one. Does it match the prefix?
* Note that as an optimization, the match is done as 64-bit
* compare since the prefix is "\??\" which is exactly 8 bytes.
*
* In the second branch, we test for "\??" which is also valid.
* This time, we use a 32-bit compare followed by a Unicode
* character compare (16-bit), since the sum is 6 bytes.
*/
if ((ObjectName->Length >= ObpDosDevicesShortName.Length) &&
(*(PULONGLONG)(ObjectName->Buffer) ==
ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
{ {
/* We don't have it, fail */ /* FIXME! */
break; }
else if ((ObjectName->Length == ObpDosDevicesShortName.Length -
sizeof(WCHAR)) &&
(*(PULONG)(ObjectName->Buffer) ==
ObpDosDevicesShortNameRoot.Alignment.LowPart) &&
(*((PWCHAR)(ObjectName->Buffer) + 2) ==
(WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart)))
{
/* FIXME! */
} }
} }
} }
}
/* Check if we don't have a remaining name yet */ /* Check if we were reparsing a symbolic link */
if (!RemainingName.Length) if (!SymLink)
{
/* Allow reparse */
Reparse = TRUE;
MaxReparse = 30;
}
/* Reparse */
while (Reparse)
{
/* Get the name */
RemainingName = *ObjectName;
/* Disable reparsing again */
Reparse = FALSE;
/* Start parse loop */
while (TRUE)
{ {
/* Check if we don't have a referenced directory yet */ /* Clear object */
if (!ReferencedDirectory) Object = NULL;
/* Check if the name starts with a path separator */
if ((RemainingName.Length) &&
(RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
{ {
/* Reference it */ /* Skip the path separator */
RemainingName.Buffer++;
RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
}
/* Find the next Part Name */
ComponentName = RemainingName;
while (RemainingName.Length)
{
/* Break if we found the \ ending */
if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
/* Move on */
RemainingName.Buffer++;
RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
}
/* Get its size and make sure it's valid */
ComponentName.Length -= RemainingName.Length;
if (!ComponentName.Length)
{
/* Invalid size, fail */
Status = STATUS_OBJECT_NAME_INVALID;
break;
}
/* Check if we're in the root */
if (!Directory) Directory = RootDirectory;
/* Check if this is a user-mode call that needs to traverse */
if ((AccessCheckMode != KernelMode) &&
!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
{
/* We shouldn't have referenced a directory yet */
ASSERT(ReferencedDirectory == NULL);
/* Reference the directory */
ObReferenceObject(Directory); ObReferenceObject(Directory);
ReferencedDirectory = Directory; ReferencedDirectory = Directory;
}
/* Check if we are inserting an object */ /* Check if we have a parent directory */
if (InsertObject) if (ParentDirectory)
{
/* Lock the directory */
ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
}
}
/* Do the lookup */
Object = ObpLookupEntryDirectory(Directory,
&ComponentName,
Attributes,
InsertObject ? FALSE : TRUE,
LookupContext);
if (!Object)
{
/* We didn't find it... do we still have a path? */
if (RemainingName.Length)
{
/* Then tell the caller the path wasn't found */
Status = STATUS_OBJECT_PATH_NOT_FOUND;
break;
}
else if (!InsertObject)
{
/* Otherwise, we have a path, but the name isn't valid */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
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 */
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 = 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);
/* Cleanup from the first lookup */
ObpCleanupDirectoryLookup(LookupContext);
/* Check if we have a referenced directory */
if (ReferencedDirectory)
{
/* We do, dereference it */
ObDereferenceObject(ReferencedDirectory);
ReferencedDirectory = NULL;
}
/* Check if we have a referenced parent directory */
if (ReferencedParentDirectory)
{
/* We do, dereference it */
ObDereferenceObject(ReferencedParentDirectory);
ReferencedParentDirectory = NULL;
}
/* Call the Parse Procedure */
ObpCalloutStart(&CalloutIrql);
Status = ParseRoutine(Object,
ObjectType,
AccessState,
AccessCheckMode,
Attributes,
ObjectName,
&RemainingName,
ParseContext,
SecurityQos,
&Object);
ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
/* Remove our extra reference */
ObDereferenceObject(&ObjectHeader->Body);
/* Check if we have to reparse */
if ((Status == STATUS_REPARSE) ||
(Status == STATUS_REPARSE_OBJECT))
{
/* Start over from root if we got sent back there */
if ((Status == STATUS_REPARSE_OBJECT) ||
(ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
{ {
/* Check if we got a root directory */ /* Check for traverse access */
if (RootHandle) if (!ObpCheckTraverseAccess(ParentDirectory,
DIRECTORY_TRAVERSE,
AccessState,
FALSE,
AccessCheckMode,
&Status))
{ {
/* Stop using it, because we have a new directory now */ /* We don't have it, fail */
ObDereferenceObject(RootDirectory); break;
RootHandle = NULL;
} }
}
}
/* Start at Root */ /* Check if we don't have a remaining name yet */
ParentDirectory = NULL; if (!RemainingName.Length)
RootDirectory = NameSpaceRoot; {
/* Check if we don't have a referenced directory yet */
if (!ReferencedDirectory)
{
/* Reference it */
ObReferenceObject(Directory);
ReferencedDirectory = Directory;
}
/* Check for reparse status */ /* Check if we are inserting an object */
if (Status == STATUS_REPARSE_OBJECT) if (InsertObject)
{
/* Lock the directory */
ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
}
}
/* Do the lookup */
Object = ObpLookupEntryDirectory(Directory,
&ComponentName,
Attributes,
InsertObject ? FALSE : TRUE,
LookupContext);
if (!Object)
{
/* We didn't find it... do we still have a path? */
if (RemainingName.Length)
{
/* Then tell the caller the path wasn't found */
Status = STATUS_OBJECT_PATH_NOT_FOUND;
break;
}
else if (!InsertObject)
{
/* Otherwise, we have a path, but the name isn't valid */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
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;
}
ReparseObject:
/* We found it, so now get its header */
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 = ObjectHeader->Type->TypeInfo.ParseProcedure;
if ((ParseRoutine) &&
(!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
{
/* Use the Root Directory next time */
Directory = NULL;
/* Increment the pointer count */
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
/* Cleanup from the first lookup */
ObpCleanupDirectoryLookup(LookupContext);
/* Check if we have a referenced directory */
if (ReferencedDirectory)
{
/* We do, dereference it */
ObDereferenceObject(ReferencedDirectory);
ReferencedDirectory = NULL;
}
/* Check if we have a referenced parent directory */
if (ReferencedParentDirectory)
{
/* We do, dereference it */
ObDereferenceObject(ReferencedParentDirectory);
ReferencedParentDirectory = NULL;
}
/* Call the Parse Procedure */
ObpCalloutStart(&CalloutIrql);
Status = ParseRoutine(Object,
ObjectType,
AccessState,
AccessCheckMode,
Attributes,
ObjectName,
&RemainingName,
ParseContext,
SecurityQos,
&Object);
ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
/* Remove our extra reference */
ObDereferenceObject(&ObjectHeader->Body);
/* Check if we have to reparse */
if ((Status == STATUS_REPARSE) ||
(Status == STATUS_REPARSE_OBJECT))
{
/* Reparse again */
Reparse = TRUE;
/* Start over from root if we got sent back there */
if ((Status == STATUS_REPARSE_OBJECT) ||
(ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
{ {
/* Did we actually get an object to which to reparse? */ /* Check if we got a root directory */
if (!Object) if (RootHandle)
{ {
/* We didn't, so set a failure status */ /* Stop using it, because we have a new directory now */
Status = STATUS_OBJECT_NAME_NOT_FOUND; ObDereferenceObject(RootDirectory);
RootHandle = NULL;
}
/* Start at Root */
ParentDirectory = NULL;
RootDirectory = NameSpaceRoot;
/* Check for reparse status */
if (Status == STATUS_REPARSE_OBJECT)
{
/* Don't reparse again */
Reparse = FALSE;
/* Did we actually get an object to which to reparse? */
if (!Object)
{
/* We didn't, so set a failure status */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
else
{
/* We did, so we're free to parse the new object */
goto ReparseObject;
}
} }
else else
{ {
/* We did, so we're free to parse the new object */ /* This is a symbolic link */
InsideRoot = TRUE; SymLink = TRUE;
goto Reparse; goto ParseFromRoot;
} }
} }
else if (RootDirectory == NameSpaceRoot)
/* Restart the search */ {
goto ReparseNewDir; /* We got STATUS_REPARSE but are at the Root Directory */
Object = NULL;
Status = STATUS_OBJECT_NAME_NOT_FOUND;
Reparse = FALSE;
}
} }
else if (RootDirectory == NameSpaceRoot) else if (!NT_SUCCESS(Status))
{ {
/* We got STATUS_REPARSE but are at the Root Directory */ /* Total failure */
Object = NULL; Object = NULL;
}
else if (!Object)
{
/* We didn't reparse but we didn't find the Object Either */
Status = STATUS_OBJECT_NAME_NOT_FOUND; Status = STATUS_OBJECT_NAME_NOT_FOUND;
} }
}
else if (!NT_SUCCESS(Status))
{
/* Total failure */
Object = NULL;
}
else if (!Object)
{
/* We didn't reparse but we didn't find the Object Either */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
/* Break out of the loop */ /* Break out of the loop */
break;
}
else
{
/* No parse routine...do we still have a remaining name? */
if (!RemainingName.Length)
{
/* Are we creating an object? */
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)) Object = NULL;
}
/* And get out of the reparse loop */
break; break;
} }
else else
{ {
/* We still have a name; check if this is a directory object */ /* No parse routine...do we still have a remaining name? */
if (ObjectHeader->Type == ObDirectoryType) if (!RemainingName.Length)
{ {
/* Check if we have a referenced parent directory */ /* Are we creating an object? */
if (ReferencedParentDirectory) if (!InsertObject)
{ {
/* Dereference it */ /* Check if this is a user-mode call that needs to traverse */
ObDereferenceObject(ReferencedParentDirectory); 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)) Object = NULL;
} }
/* Restart the lookup from this directory */ /* And get out of the reparse loop */
ReferencedParentDirectory = ReferencedDirectory; break;
ParentDirectory = Directory;
Directory = Object;
ReferencedDirectory = NULL;
} }
else else
{ {
/* We still have a name, but no parse routine for it */ /* We still have a name; check if this is a directory object */
Status = STATUS_OBJECT_TYPE_MISMATCH; if (ObjectHeader->Type == ObDirectoryType)
Object = NULL; {
break; /* Check if we have a referenced parent directory */
if (ReferencedParentDirectory)
{
/* Dereference it */
ObDereferenceObject(ReferencedParentDirectory);
}
/* Restart the lookup from this directory */
ReferencedParentDirectory = ReferencedDirectory;
ParentDirectory = Directory;
Directory = Object;
ReferencedDirectory = NULL;
}
else
{
/* We still have a name, but no parse routine for it */
Status = STATUS_OBJECT_TYPE_MISMATCH;
Object = NULL;
break;
}
} }
} }
} }