mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 19:43:04 +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
|
IN HANDLE PortHandle
|
||||||
);
|
);
|
||||||
|
|
||||||
NTSYSAPI
|
|
||||||
NTSYSAPI
|
NTSYSAPI
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
@ -297,7 +297,6 @@ NtSetInformationProcess(
|
||||||
IN ULONG ProcessInformationLength
|
IN ULONG ProcessInformationLength
|
||||||
);
|
);
|
||||||
|
|
||||||
NTSYSCALLAPI
|
|
||||||
NTSYSCALLAPI
|
NTSYSCALLAPI
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget,
|
|
||||||
PreviousMode,
|
|
||||||
LinkTarget);
|
|
||||||
if(!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
|
/* No need to capture */
|
||||||
return Status;
|
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,
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue