mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 10:01:43 +00:00
- 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:
parent
4b6154cfbf
commit
8a80070849
7 changed files with 231 additions and 107 deletions
|
@ -858,7 +858,6 @@ ZwSetDefaultHardErrorPort(
|
|||
IN HANDLE PortHandle
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
NTSYSAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
|
|
|
@ -384,15 +384,29 @@ typedef struct _OBJECT_DIRECTORY_ENTRY
|
|||
{
|
||||
struct _OBJECT_DIRECTORY_ENTRY *ChainLink;
|
||||
PVOID Object;
|
||||
#if (NTDDI_VERSION >= NTDDI_WS03)
|
||||
ULONG HashValue;
|
||||
#endif
|
||||
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
|
||||
|
||||
typedef struct _OBJECT_DIRECTORY
|
||||
{
|
||||
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;
|
||||
#endif
|
||||
ULONG SessionId;
|
||||
#if (NTDDI_VERSION == NTDDI_WINXP)
|
||||
USHORT Reserved;
|
||||
USHORT SymbolicLinkUsageCount;
|
||||
#endif
|
||||
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
|
||||
|
||||
//
|
||||
|
@ -407,6 +421,18 @@ typedef struct _DEVICE_MAP
|
|||
UCHAR DriveType[32];
|
||||
} 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
|
||||
//
|
||||
|
|
|
@ -297,7 +297,6 @@ NtSetInformationProcess(
|
|||
IN ULONG ProcessInformationLength
|
||||
);
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
|
|
|
@ -171,6 +171,42 @@ Author:
|
|||
#define NLS_MB_CODE_PAGE_TAG NlsMbCodePageTag
|
||||
#define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag
|
||||
#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
|
||||
//
|
||||
// Message Resource Flag
|
||||
|
|
|
@ -23,14 +23,6 @@ typedef struct _DIRECTORY_OBJECT
|
|||
KSPIN_LOCK Lock;
|
||||
} 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
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
|
|
|
@ -210,7 +210,7 @@ NtQueryObject(IN HANDLE ObjectHandle,
|
|||
if (ObjectHeader->Type == ObSymbolicLinkType)
|
||||
{
|
||||
BasicInfo->CreateTime.QuadPart =
|
||||
((PSYMLINK_OBJECT)Object)->CreateTime.QuadPart;
|
||||
((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -48,8 +48,15 @@ VOID
|
|||
NTAPI
|
||||
ObpDeleteSymbolicLink(PVOID ObjectBody)
|
||||
{
|
||||
PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody;
|
||||
ExFreePool(SymlinkObject->TargetName.Buffer);
|
||||
POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody;
|
||||
|
||||
/* 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,
|
||||
ULONG Attributes)
|
||||
{
|
||||
PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object;
|
||||
UNICODE_STRING TargetPath;
|
||||
|
||||
DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
|
||||
POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)Object;
|
||||
PUNICODE_STRING TargetPath;
|
||||
PWSTR NewTargetPath;
|
||||
ULONG LengthUsed, MaximumLength, RemainLength;
|
||||
|
||||
/*
|
||||
* Stop parsing if the entire path has been parsed and
|
||||
|
@ -97,33 +104,51 @@ ObpParseSymbolicLink(PVOID Object,
|
|||
if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
|
||||
(Attributes & OBJ_OPENLINK))
|
||||
{
|
||||
DPRINT("Parsing stopped!\n");
|
||||
*NextObject = NULL;
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
/* Build the expanded path */
|
||||
TargetPath.MaximumLength = SymlinkObject->TargetName.Length +
|
||||
sizeof(WCHAR);
|
||||
if (RemainingPath && *RemainingPath)
|
||||
/* Set the target path and length */
|
||||
TargetPath = &SymlinkObject->LinkTarget;
|
||||
RemainLength = *RemainingPath ? wcslen(*RemainingPath) * sizeof(WCHAR) : 0;
|
||||
LengthUsed = TargetPath->Length + RemainLength;
|
||||
|
||||
/* Optimization: check if the new name is shorter */
|
||||
if (FullPath->MaximumLength <= LengthUsed)
|
||||
{
|
||||
TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
|
||||
}
|
||||
TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
|
||||
TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
|
||||
TargetPath.MaximumLength,
|
||||
/* It's not, allocate a new one */
|
||||
MaximumLength = LengthUsed + sizeof(WCHAR);
|
||||
NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
|
||||
MaximumLength,
|
||||
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 */
|
||||
ExFreePool(FullPath->Buffer);
|
||||
FullPath->Length = TargetPath.Length;
|
||||
FullPath->MaximumLength = TargetPath.MaximumLength;
|
||||
FullPath->Buffer = TargetPath.Buffer;
|
||||
/* Make sure we have a length */
|
||||
if (RemainLength)
|
||||
{
|
||||
/* Copy the new path */
|
||||
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 */
|
||||
*RemainingPath = FullPath->Buffer;
|
||||
|
@ -152,13 +177,11 @@ ObInitSymbolicLinkImplementation(VOID)
|
|||
UNICODE_STRING Name;
|
||||
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
||||
|
||||
DPRINT("Creating SymLink Object Type\n");
|
||||
|
||||
/* Initialize the Directory type */
|
||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||
RtlInitUnicodeString(&Name, L"SymbolicLink");
|
||||
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
||||
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT);
|
||||
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK);
|
||||
ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
|
||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||
ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
|
||||
|
@ -201,72 +224,99 @@ NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
|||
IN PUNICODE_STRING LinkTarget)
|
||||
{
|
||||
HANDLE hLink;
|
||||
PSYMLINK_OBJECT SymbolicLink;
|
||||
POBJECT_SYMBOLIC_LINK SymbolicLink;
|
||||
UNICODE_STRING CapturedLinkTarget;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul"
|
||||
", ObjectAttributes %p, LinkTarget %wZ)\n",
|
||||
LinkHandle,
|
||||
DesiredAccess,
|
||||
ObjectAttributes,
|
||||
LinkTarget);
|
||||
|
||||
/* Check if we need to probe parameters */
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Exception, get the error code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
/* Probing failed, return the error code */
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget,
|
||||
PreviousMode,
|
||||
LinkTarget);
|
||||
if(!NT_SUCCESS(Status))
|
||||
else
|
||||
{
|
||||
DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
|
||||
return Status;
|
||||
/* No need to capture */
|
||||
CapturedLinkTarget = *LinkTarget;
|
||||
}
|
||||
|
||||
/* Check if the maximum length is odd */
|
||||
if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR))
|
||||
{
|
||||
/* Round it down */
|
||||
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,
|
||||
ObSymbolicLinkType,
|
||||
ObjectAttributes,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(SYMLINK_OBJECT),
|
||||
sizeof(OBJECT_SYMBOLIC_LINK),
|
||||
0,
|
||||
0,
|
||||
(PVOID*)&SymbolicLink);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
SymbolicLink->TargetName.Length = 0;
|
||||
SymbolicLink->TargetName.MaximumLength = CapturedLinkTarget.Length +
|
||||
/* Success! Fill in the creation time immediately */
|
||||
KeQuerySystemTime(&SymbolicLink->CreationTime);
|
||||
|
||||
/* Setup the target name */
|
||||
SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
|
||||
SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.Length +
|
||||
sizeof(WCHAR);
|
||||
SymbolicLink->TargetName.Buffer =
|
||||
ExAllocatePoolWithTag(NonPagedPool,
|
||||
SymbolicLink->TargetName.MaximumLength,
|
||||
SymbolicLink->LinkTarget.Buffer =
|
||||
ExAllocatePoolWithTag(PagedPool,
|
||||
CapturedLinkTarget.MaximumLength,
|
||||
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);
|
||||
|
||||
Status = ObInsertObject((PVOID)SymbolicLink,
|
||||
/* Insert it into the object tree */
|
||||
Status = ObInsertObject(SymbolicLink,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
0,
|
||||
|
@ -276,18 +326,22 @@ NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
|||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
/* Return the handle to caller */
|
||||
*LinkHandle = hLink;
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Get exception code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
}
|
||||
|
||||
/* ReactOS Hack: Our ObInsertObject references an object twice */
|
||||
ObDereferenceObject(SymbolicLink);
|
||||
}
|
||||
|
||||
ReleaseCapturedUnicodeString(&CapturedLinkTarget, PreviousMode);
|
||||
/* Return status to caller */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -322,27 +376,26 @@ NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
|||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Check if we need to probe parameters */
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
/* Probe the return handle */
|
||||
ProbeForWriteHandle(LinkHandle);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Exception, get the error code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
/* Probing failed, return the error code */
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
|
||||
ObjectAttributes->ObjectName);
|
||||
|
||||
/* Open the object */
|
||||
Status = ObOpenObjectByName(ObjectAttributes,
|
||||
ObSymbolicLinkType,
|
||||
NULL,
|
||||
|
@ -350,19 +403,22 @@ NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
|||
DesiredAccess,
|
||||
NULL,
|
||||
&hLink);
|
||||
if(NT_SUCCESS(Status))
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
/* Return the handle to caller */
|
||||
*LinkHandle = hLink;
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Get exception code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
}
|
||||
|
||||
/* Return status to caller */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -393,46 +449,47 @@ NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
|
|||
OUT PULONG ResultLength OPTIONAL)
|
||||
{
|
||||
UNICODE_STRING SafeLinkTarget;
|
||||
PSYMLINK_OBJECT SymlinkObject;
|
||||
POBJECT_SYMBOLIC_LINK SymlinkObject;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG LengthRequired;
|
||||
ULONG LengthUsed;
|
||||
PAGED_CODE();
|
||||
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
/* probe the unicode string and buffers supplied */
|
||||
ProbeForWrite(LinkTarget, sizeof(UNICODE_STRING), sizeof(ULONG));
|
||||
/* Probe the unicode string for read and write */
|
||||
ProbeForRead(LinkTarget, sizeof(UNICODE_STRING), sizeof(WCHAR));
|
||||
ProbeForWriteUshort(&LinkTarget->Length);
|
||||
ProbeForWriteUshort(&LinkTarget->MaximumLength);
|
||||
|
||||
/* Probe the unicode string's buffer for write */
|
||||
SafeLinkTarget = *LinkTarget;
|
||||
|
||||
ProbeForWrite(SafeLinkTarget.Buffer,
|
||||
SafeLinkTarget.MaximumLength,
|
||||
sizeof(WCHAR));
|
||||
sizeof(CHAR));
|
||||
|
||||
if(ResultLength != NULL)
|
||||
{
|
||||
ProbeForWriteUlong(ResultLength);
|
||||
}
|
||||
/* Probe the return length */
|
||||
if(ResultLength) ProbeForWriteUlong(ResultLength);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Probe failure: get exception code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
/* Probe failed, return status */
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need to probe */
|
||||
SafeLinkTarget = *LinkTarget;
|
||||
}
|
||||
|
||||
/* Reference the object */
|
||||
Status = ObReferenceObjectByHandle(LinkHandle,
|
||||
SYMBOLIC_LINK_QUERY,
|
||||
ObSymbolicLinkType,
|
||||
|
@ -441,44 +498,59 @@ NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
|
|||
NULL);
|
||||
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
|
||||
{
|
||||
if(SafeLinkTarget.MaximumLength >= LengthRequired)
|
||||
/* Make sure our buffer will fit */
|
||||
if (LengthUsed <= SafeLinkTarget.MaximumLength)
|
||||
{
|
||||
/*
|
||||
* Don't pass TargetLink to RtlCopyUnicodeString here because
|
||||
* the caller might have modified the structure which could
|
||||
* lead to a copy into kernel memory!
|
||||
*/
|
||||
RtlCopyUnicodeString(&SafeLinkTarget,
|
||||
&SymlinkObject->TargetName);
|
||||
SafeLinkTarget.Buffer[SafeLinkTarget.Length /
|
||||
sizeof(WCHAR)] = UNICODE_NULL;
|
||||
/* Copy the buffer */
|
||||
RtlMoveMemory(SafeLinkTarget.Buffer,
|
||||
SymlinkObject->LinkTarget.Buffer,
|
||||
LengthUsed);
|
||||
|
||||
/* Copy back the new UNICODE_STRING structure */
|
||||
*LinkTarget = SafeLinkTarget;
|
||||
/* Copy the new length */
|
||||
LinkTarget->Length = SymlinkObject->LinkTarget.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise set the failure status */
|
||||
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
|
||||
{
|
||||
/* Get the error code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
/* Unlock the object type and reference the object */
|
||||
ExReleaseResourceLite(&ObSymbolicLinkType->Mutex);
|
||||
KeLeaveCriticalRegion();
|
||||
ObDereferenceObject(SymlinkObject);
|
||||
}
|
||||
|
||||
/* Return query status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue