- Fix Symbolic Link implementation:

- Use OBJECT_SYMBOLIC_LINK structure as used by Windows NT (and added the structure to the NDK)
  - Changed code to use the new names in the structure
  - Only free the symlink's name if it has one, to avoid a bugcheck.
  - Optimize parsing: if the new name is actually shorter then the target name, then don't allocate from pool, but re-use the buffer. This improves symlink parsing speed. Also fix a bug which made it depend on the incorrect implementation of NtCreateSymbolicLinkObject
  - Re-align the link target maximum length in NtCreateSymbolicLinkObject if it's odd, and fail if the length is odd, smaller then the maximum, or if the maximum is zero.
  - Originally allocate the symlink name in Paged Pool.
  - Initialize new members of the structure.
  - Fail in no-memory case, instead of continuing.
  - Properly probe the LinkTarget in NtQuerySymbolicLinkObject.
  - Properly handle which length is chosen for the copy and for the return in NtQuerySymbolicObject.
  - Lock the symbolic link object type while querying it. Eventually many more parts of Ob need to do this kind of locking.
  - SymLinkTest now only gives 2 failures.
- Fix some NDK bugs

svn path=/trunk/; revision=22000
This commit is contained in:
Alex Ionescu 2006-05-24 02:45:06 +00:00
parent 4b6154cfbf
commit 8a80070849
7 changed files with 231 additions and 107 deletions

View file

@ -858,7 +858,6 @@ ZwSetDefaultHardErrorPort(
IN HANDLE PortHandle IN HANDLE PortHandle
); );
NTSYSAPI
NTSYSAPI NTSYSAPI
NTSTATUS NTSTATUS
NTAPI NTAPI

View file

@ -384,15 +384,29 @@ typedef struct _OBJECT_DIRECTORY_ENTRY
{ {
struct _OBJECT_DIRECTORY_ENTRY *ChainLink; struct _OBJECT_DIRECTORY_ENTRY *ChainLink;
PVOID Object; PVOID Object;
#if (NTDDI_VERSION >= NTDDI_WS03)
ULONG HashValue; ULONG HashValue;
#endif
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY; } OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
typedef struct _OBJECT_DIRECTORY typedef struct _OBJECT_DIRECTORY
{ {
struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[NUMBER_HASH_BUCKETS]; struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[NUMBER_HASH_BUCKETS];
struct _EX_PUSH_LOCK *Lock; #if (NTDDI_VERSION < NTDDI_WINXP)
PERESOURCE Lock;
#elif (NTDDI_VERSION >= NTDDI_WINXP)
EX_PUSH_LOCK Lock;
#endif
#if (NTDDI_VERSION < NTDDI_WINXP)
BOOLEAN CurrentEntryValid;
#else
struct _DEVICE_MAP *DeviceMap; struct _DEVICE_MAP *DeviceMap;
#endif
ULONG SessionId; ULONG SessionId;
#if (NTDDI_VERSION == NTDDI_WINXP)
USHORT Reserved;
USHORT SymbolicLinkUsageCount;
#endif
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY; } OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
// //
@ -407,6 +421,18 @@ typedef struct _DEVICE_MAP
UCHAR DriveType[32]; UCHAR DriveType[32];
} DEVICE_MAP, *PDEVICE_MAP; } DEVICE_MAP, *PDEVICE_MAP;
//
// Symbolic Link Object
//
typedef struct _OBJECT_SYMBOLIC_LINK
{
LARGE_INTEGER CreationTime;
UNICODE_STRING LinkTarget;
UNICODE_STRING LinkTargetRemaining;
PVOID LinkTargetObject;
ULONG DosDeviceDriveIndex;
} OBJECT_SYMBOLIC_LINK, *POBJECT_SYMBOLIC_LINK;
// //
// Kernel Exports // Kernel Exports
// //

View file

@ -297,7 +297,6 @@ NtSetInformationProcess(
IN ULONG ProcessInformationLength IN ULONG ProcessInformationLength
); );
NTSYSCALLAPI
NTSYSCALLAPI NTSYSCALLAPI
NTSTATUS NTSTATUS
NTAPI NTAPI

View file

@ -171,6 +171,42 @@ Author:
#define NLS_MB_CODE_PAGE_TAG NlsMbCodePageTag #define NLS_MB_CODE_PAGE_TAG NlsMbCodePageTag
#define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag #define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag
#define NLS_OEM_LEAD_BYTE_INFO NlsOemLeadByteInfo #define NLS_OEM_LEAD_BYTE_INFO NlsOemLeadByteInfo
//
// C++ CONST casting
//
#if defined(__cplusplus)
#define RTL_CONST_CAST(type) const_cast<type>
#else
#define RTL_CONST_CAST(type) (type)
#endif
//
// Constant String Macro
//
#define RTL_CONSTANT_STRING(__SOURCE_STRING__) \
{ \
sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]), \
sizeof(__SOURCE_STRING__), \
(__SOURCE_STRING__) \
}
//
// Constant Object Attributes Macro
//
#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) \
{ \
sizeof(OBJECT_ATTRIBUTES), \
NULL, \
RTL_CONST_CAST(PUNICODE_STRING)(n), \
a, \
NULL, \
NULL \
}
#define RTL_INIT_OBJECT_ATTRIBUTES(n, a) \
RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)
#else #else
// //
// Message Resource Flag // Message Resource Flag

View file

@ -23,14 +23,6 @@ typedef struct _DIRECTORY_OBJECT
KSPIN_LOCK Lock; KSPIN_LOCK Lock;
} DIRECTORY_OBJECT, *PDIRECTORY_OBJECT; } DIRECTORY_OBJECT, *PDIRECTORY_OBJECT;
typedef struct _SYMLINK_OBJECT
{
CSHORT Type;
CSHORT Size;
UNICODE_STRING TargetName;
LARGE_INTEGER CreateTime;
} SYMLINK_OBJECT, *PSYMLINK_OBJECT;
typedef struct _ROS_OBJECT_HEADER typedef struct _ROS_OBJECT_HEADER
{ {
LIST_ENTRY Entry; LIST_ENTRY Entry;

View file

@ -210,7 +210,7 @@ NtQueryObject(IN HANDLE ObjectHandle,
if (ObjectHeader->Type == ObSymbolicLinkType) if (ObjectHeader->Type == ObSymbolicLinkType)
{ {
BasicInfo->CreateTime.QuadPart = BasicInfo->CreateTime.QuadPart =
((PSYMLINK_OBJECT)Object)->CreateTime.QuadPart; ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
} }
else else
{ {

View file

@ -48,8 +48,15 @@ VOID
NTAPI NTAPI
ObpDeleteSymbolicLink(PVOID ObjectBody) ObpDeleteSymbolicLink(PVOID ObjectBody)
{ {
PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody; POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody;
ExFreePool(SymlinkObject->TargetName.Buffer);
/* Make sure that the symbolic link has a name */
if (SymlinkObject->LinkTarget.Buffer)
{
/* Free the name */
ExFreePool(SymlinkObject->LinkTarget.Buffer);
SymlinkObject->LinkTarget.Buffer = NULL;
}
} }
/*++ /*++
@ -85,10 +92,10 @@ ObpParseSymbolicLink(PVOID Object,
PWSTR * RemainingPath, PWSTR * RemainingPath,
ULONG Attributes) ULONG Attributes)
{ {
PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object; POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)Object;
UNICODE_STRING TargetPath; PUNICODE_STRING TargetPath;
PWSTR NewTargetPath;
DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath); ULONG LengthUsed, MaximumLength, RemainLength;
/* /*
* Stop parsing if the entire path has been parsed and * Stop parsing if the entire path has been parsed and
@ -97,33 +104,51 @@ ObpParseSymbolicLink(PVOID Object,
if (((*RemainingPath == NULL) || (**RemainingPath == 0)) && if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
(Attributes & OBJ_OPENLINK)) (Attributes & OBJ_OPENLINK))
{ {
DPRINT("Parsing stopped!\n");
*NextObject = NULL; *NextObject = NULL;
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
/* Build the expanded path */ /* Set the target path and length */
TargetPath.MaximumLength = SymlinkObject->TargetName.Length + TargetPath = &SymlinkObject->LinkTarget;
sizeof(WCHAR); RemainLength = *RemainingPath ? wcslen(*RemainingPath) * sizeof(WCHAR) : 0;
if (RemainingPath && *RemainingPath) LengthUsed = TargetPath->Length + RemainLength;
/* Optimization: check if the new name is shorter */
if (FullPath->MaximumLength <= LengthUsed)
{ {
TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR)); /* It's not, allocate a new one */
} MaximumLength = LengthUsed + sizeof(WCHAR);
TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR); NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, MaximumLength,
TargetPath.MaximumLength,
TAG_SYMLINK_TTARGET); TAG_SYMLINK_TTARGET);
wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer); }
if (RemainingPath && *RemainingPath) else
{ {
wcscat(TargetPath.Buffer, *RemainingPath); /* It is! Reuse the name... */
MaximumLength = FullPath->MaximumLength;
NewTargetPath = FullPath->Buffer;
} }
/* Transfer target path buffer into FullPath */ /* Make sure we have a length */
ExFreePool(FullPath->Buffer); if (RemainLength)
FullPath->Length = TargetPath.Length; {
FullPath->MaximumLength = TargetPath.MaximumLength; /* Copy the new path */
FullPath->Buffer = TargetPath.Buffer; RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TargetPath->Length),
*RemainingPath,
RemainLength);
}
/* Copy the target path and null-terminate it */
RtlMoveMemory(NewTargetPath, TargetPath->Buffer, TargetPath->Length);
NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL;
/* If the optimization didn't work, free the old buffer */
if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer);
/* Update the path values */
FullPath->Length = LengthUsed;
FullPath->MaximumLength = MaximumLength;
FullPath->Buffer = NewTargetPath;
/* Reinitialize RemainingPath for reparsing */ /* Reinitialize RemainingPath for reparsing */
*RemainingPath = FullPath->Buffer; *RemainingPath = FullPath->Buffer;
@ -152,13 +177,11 @@ ObInitSymbolicLinkImplementation(VOID)
UNICODE_STRING Name; UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
DPRINT("Creating SymLink Object Type\n");
/* Initialize the Directory type */ /* Initialize the Directory type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"SymbolicLink"); RtlInitUnicodeString(&Name, L"SymbolicLink");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK);
ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping; ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
@ -201,72 +224,99 @@ NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
IN PUNICODE_STRING LinkTarget) IN PUNICODE_STRING LinkTarget)
{ {
HANDLE hLink; HANDLE hLink;
PSYMLINK_OBJECT SymbolicLink; POBJECT_SYMBOLIC_LINK SymbolicLink;
UNICODE_STRING CapturedLinkTarget; UNICODE_STRING CapturedLinkTarget;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE(); PAGED_CODE();
DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul" /* Check if we need to probe parameters */
", ObjectAttributes %p, LinkTarget %wZ)\n",
LinkHandle,
DesiredAccess,
ObjectAttributes,
LinkTarget);
if(PreviousMode != KernelMode) if(PreviousMode != KernelMode)
{ {
_SEH_TRY _SEH_TRY
{ {
/* Probe the target */
ProbeForRead(LinkTarget, sizeof(UNICODE_STRING), sizeof(WCHAR));
CapturedLinkTarget = *LinkTarget;
ProbeForRead(CapturedLinkTarget.Buffer,
CapturedLinkTarget.MaximumLength,
sizeof(WCHAR));
/* Probe the return handle */
ProbeForWriteHandle(LinkHandle); ProbeForWriteHandle(LinkHandle);
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Exception, get the error code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
if(!NT_SUCCESS(Status)) /* Probing failed, return the error code */
{ if(!NT_SUCCESS(Status)) return Status;
return Status;
} }
else
{
/* No need to capture */
CapturedLinkTarget = *LinkTarget;
} }
Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget, /* Check if the maximum length is odd */
PreviousMode, if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR))
LinkTarget);
if(!NT_SUCCESS(Status))
{ {
DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n"); /* Round it down */
return Status; CapturedLinkTarget.MaximumLength =
ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR);
} }
/* Fail if the length is odd, or if the maximum is smaller or 0 */
if ((CapturedLinkTarget.Length % sizeof(WCHAR)) ||
(CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) ||
!(CapturedLinkTarget.MaximumLength))
{
/* This message is displayed on the debugger in Windows */
DbgPrint("OB: Invalid symbolic link target - %wZ\n",
&CapturedLinkTarget);
return STATUS_INVALID_PARAMETER;
}
/* Create the object */
Status = ObCreateObject(PreviousMode, Status = ObCreateObject(PreviousMode,
ObSymbolicLinkType, ObSymbolicLinkType,
ObjectAttributes, ObjectAttributes,
PreviousMode, PreviousMode,
NULL, NULL,
sizeof(SYMLINK_OBJECT), sizeof(OBJECT_SYMBOLIC_LINK),
0, 0,
0, 0,
(PVOID*)&SymbolicLink); (PVOID*)&SymbolicLink);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
SymbolicLink->TargetName.Length = 0; /* Success! Fill in the creation time immediately */
SymbolicLink->TargetName.MaximumLength = CapturedLinkTarget.Length + KeQuerySystemTime(&SymbolicLink->CreationTime);
/* Setup the target name */
SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.Length +
sizeof(WCHAR); sizeof(WCHAR);
SymbolicLink->TargetName.Buffer = SymbolicLink->LinkTarget.Buffer =
ExAllocatePoolWithTag(NonPagedPool, ExAllocatePoolWithTag(PagedPool,
SymbolicLink->TargetName.MaximumLength, CapturedLinkTarget.MaximumLength,
TAG_SYMLINK_TARGET); TAG_SYMLINK_TARGET);
if (!SymbolicLink->LinkTarget.Buffer) return STATUS_NO_MEMORY;
RtlCopyUnicodeString(&SymbolicLink->TargetName, &CapturedLinkTarget); /* Copy it */
RtlMoveMemory(SymbolicLink->LinkTarget.Buffer,
CapturedLinkTarget.Buffer,
CapturedLinkTarget.MaximumLength);
DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer); /* Initialize the remaining name, dos drive index and target object */
SymbolicLink->LinkTargetObject = NULL;
SymbolicLink->DosDeviceDriveIndex = 0;
RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL);
ZwQuerySystemTime (&SymbolicLink->CreateTime); /* Insert it into the object tree */
Status = ObInsertObject(SymbolicLink,
Status = ObInsertObject((PVOID)SymbolicLink,
NULL, NULL,
DesiredAccess, DesiredAccess,
0, 0,
@ -276,18 +326,22 @@ NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
{ {
_SEH_TRY _SEH_TRY
{ {
/* Return the handle to caller */
*LinkHandle = hLink; *LinkHandle = hLink;
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Get exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
} }
/* ReactOS Hack: Our ObInsertObject references an object twice */
ObDereferenceObject(SymbolicLink); ObDereferenceObject(SymbolicLink);
} }
ReleaseCapturedUnicodeString(&CapturedLinkTarget, PreviousMode); /* Return status to caller */
return Status; return Status;
} }
@ -322,27 +376,26 @@ NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE(); PAGED_CODE();
/* Check if we need to probe parameters */
if(PreviousMode != KernelMode) if(PreviousMode != KernelMode)
{ {
_SEH_TRY _SEH_TRY
{ {
/* Probe the return handle */
ProbeForWriteHandle(LinkHandle); ProbeForWriteHandle(LinkHandle);
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Exception, get the error code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
if(!NT_SUCCESS(Status)) /* Probing failed, return the error code */
{ if(!NT_SUCCESS(Status)) return Status;
return Status;
}
} }
DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n", /* Open the object */
ObjectAttributes->ObjectName);
Status = ObOpenObjectByName(ObjectAttributes, Status = ObOpenObjectByName(ObjectAttributes,
ObSymbolicLinkType, ObSymbolicLinkType,
NULL, NULL,
@ -350,19 +403,22 @@ NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
DesiredAccess, DesiredAccess,
NULL, NULL,
&hLink); &hLink);
if(NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
_SEH_TRY _SEH_TRY
{ {
/* Return the handle to caller */
*LinkHandle = hLink; *LinkHandle = hLink;
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Get exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
} }
/* Return status to caller */
return Status; return Status;
} }
@ -393,46 +449,47 @@ NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
OUT PULONG ResultLength OPTIONAL) OUT PULONG ResultLength OPTIONAL)
{ {
UNICODE_STRING SafeLinkTarget; UNICODE_STRING SafeLinkTarget;
PSYMLINK_OBJECT SymlinkObject; POBJECT_SYMBOLIC_LINK SymlinkObject;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
ULONG LengthRequired; ULONG LengthUsed;
PAGED_CODE(); PAGED_CODE();
if(PreviousMode != KernelMode) if(PreviousMode != KernelMode)
{ {
_SEH_TRY _SEH_TRY
{ {
/* probe the unicode string and buffers supplied */ /* Probe the unicode string for read and write */
ProbeForWrite(LinkTarget, sizeof(UNICODE_STRING), sizeof(ULONG)); ProbeForRead(LinkTarget, sizeof(UNICODE_STRING), sizeof(WCHAR));
ProbeForWriteUshort(&LinkTarget->Length);
ProbeForWriteUshort(&LinkTarget->MaximumLength);
/* Probe the unicode string's buffer for write */
SafeLinkTarget = *LinkTarget; SafeLinkTarget = *LinkTarget;
ProbeForWrite(SafeLinkTarget.Buffer, ProbeForWrite(SafeLinkTarget.Buffer,
SafeLinkTarget.MaximumLength, SafeLinkTarget.MaximumLength,
sizeof(WCHAR)); sizeof(CHAR));
if(ResultLength != NULL) /* Probe the return length */
{ if(ResultLength) ProbeForWriteUlong(ResultLength);
ProbeForWriteUlong(ResultLength);
}
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Probe failure: get exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
if(!NT_SUCCESS(Status)) /* Probe failed, return status */
{ if(!NT_SUCCESS(Status)) return Status;
return Status;
}
} }
else else
{ {
/* No need to probe */
SafeLinkTarget = *LinkTarget; SafeLinkTarget = *LinkTarget;
} }
/* Reference the object */
Status = ObReferenceObjectByHandle(LinkHandle, Status = ObReferenceObjectByHandle(LinkHandle,
SYMBOLIC_LINK_QUERY, SYMBOLIC_LINK_QUERY,
ObSymbolicLinkType, ObSymbolicLinkType,
@ -441,44 +498,59 @@ NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
NULL); NULL);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR); /* Lock the object type */
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&ObSymbolicLinkType->Mutex, TRUE);
/*
* So here's the thing: If you specify a return length, then the
* implementation will use the maximum length. If you don't, then
* it will use the length.
*/
LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength :
SymlinkObject->LinkTarget.Length;
/* Enter SEH so we can safely copy */
_SEH_TRY _SEH_TRY
{ {
if(SafeLinkTarget.MaximumLength >= LengthRequired) /* Make sure our buffer will fit */
if (LengthUsed <= SafeLinkTarget.MaximumLength)
{ {
/* /* Copy the buffer */
* Don't pass TargetLink to RtlCopyUnicodeString here because RtlMoveMemory(SafeLinkTarget.Buffer,
* the caller might have modified the structure which could SymlinkObject->LinkTarget.Buffer,
* lead to a copy into kernel memory! LengthUsed);
*/
RtlCopyUnicodeString(&SafeLinkTarget,
&SymlinkObject->TargetName);
SafeLinkTarget.Buffer[SafeLinkTarget.Length /
sizeof(WCHAR)] = UNICODE_NULL;
/* Copy back the new UNICODE_STRING structure */ /* Copy the new length */
*LinkTarget = SafeLinkTarget; LinkTarget->Length = SymlinkObject->LinkTarget.Length;
} }
else else
{ {
/* Otherwise set the failure status */
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
if(ResultLength != NULL) /* In both cases, check if the required length was requested */
if (ResultLength)
{ {
*ResultLength = LengthRequired; /* Then return it */
*ResultLength = SymlinkObject->LinkTarget.MaximumLength;
} }
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Get the error code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
/* Unlock the object type and reference the object */
ExReleaseResourceLite(&ObSymbolicLinkType->Mutex);
KeLeaveCriticalRegion();
ObDereferenceObject(SymlinkObject); ObDereferenceObject(SymlinkObject);
} }
/* Return query status */
return Status; return Status;
} }