sys,dll: reparse point testing

This commit is contained in:
Bill Zissimopoulos
2016-09-10 23:00:55 -07:00
parent 0d25e73364
commit af2cc10c15
8 changed files with 171 additions and 112 deletions

View File

@ -486,8 +486,8 @@ NTSTATUS FspFsvolCreateComplete(
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
FSP_FILE_NODE *OpenedFileNode;
UNICODE_STRING ReparseFileName;
PREPARSE_DATA_BUFFER ReparseData;
UNICODE_STRING ReparseTargetPrefix, ReparseTargetPath;
if (FspFsctlTransactCreateKind == Request->Kind)
{
@ -505,32 +505,74 @@ NTSTATUS FspFsvolCreateComplete(
if (IO_REMOUNT == Response->IoStatus.Information)
{
Irp->IoStatus.Information = IO_REMOUNT;
Result = STATUS_REPARSE;
FSP_RETURN();
FSP_RETURN(Result = STATUS_REPARSE);
}
else if (IO_REPARSE == Response->IoStatus.Information)
else
if (IO_REPARSE == Response->IoStatus.Information ||
IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information)
{
ReparseFileName.Buffer =
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
ReparseFileName.Length = ReparseFileName.MaximumLength =
Response->Rsp.Create.Reparse.FileName.Size;
/*
* IO_REPARSE means that the user-mode file system has returned a device-relative
* path. Prefix it with our device name and send it to the IO Manager.
*
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
* symbolic link reparse buffer. In this case send the target path to the IO Manager
* without prefixing it with our device name as it is expected to be absolute in the
* NT namespace.
*/
if ((PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
(PUINT8)Response + Response->Size ||
0 == ReparseFileName.Length)
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
if (IO_REPARSE == Response->IoStatus.Information)
{
PVOID Buffer = FspAllocExternal(ReparseFileName.Length);
RtlCopyMemory(&ReparseTargetPrefix, &FsvolDeviceExtension->VolumeName,
sizeof ReparseTargetPrefix);
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
Response->Rsp.Create.Reparse.FileName.Size;
ReparseTargetPath.Buffer =
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
if ((PUINT8)ReparseTargetPath.Buffer + ReparseTargetPath.Length >
(PUINT8)Response + Response->Size || 0 == ReparseTargetPath.Length)
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
}
else
{
ASSERT(IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information);
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Data.Offset);
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size >
(PUINT8)Response + Response->Size)
FSP_RETURN(Result = STATUS_IO_REPARSE_DATA_INVALID);
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size,
ReparseData);
if (!NT_SUCCESS(Result))
FSP_RETURN();
RtlZeroMemory(&ReparseTargetPrefix, sizeof ReparseTargetPrefix);
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
}
if (ReparseTargetPrefix.Length + ReparseTargetPath.Length >
FileObject->FileName.MaximumLength)
{
PVOID Buffer = FspAllocExternal(
ReparseTargetPrefix.Length + ReparseTargetPath.Length);
if (0 == Buffer)
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
FspFreeExternal(FileObject->FileName.Buffer);
FileObject->FileName.MaximumLength = ReparseFileName.Length;
FileObject->FileName.MaximumLength =
ReparseTargetPrefix.Length + ReparseTargetPath.Length;
FileObject->FileName.Buffer = Buffer;
}
FileObject->FileName.Length = 0;
RtlCopyUnicodeString(&FileObject->FileName, &ReparseFileName);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPath);
/*
* The RelatedFileObject does not need to be changed according to:
@ -548,8 +590,7 @@ NTSTATUS FspFsvolCreateComplete(
*/
Irp->IoStatus.Information = IO_REPARSE;
Result = STATUS_REPARSE;
FSP_RETURN();
FSP_RETURN(Result = STATUS_REPARSE);
}
else
{
@ -557,10 +598,7 @@ NTSTATUS FspFsvolCreateComplete(
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size >
(PUINT8)Response + Response->Size)
{
Result = STATUS_IO_REPARSE_DATA_INVALID;
FSP_RETURN();
}
FSP_RETURN(Result = STATUS_IO_REPARSE_DATA_INVALID);
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size,
ReparseData);
@ -571,17 +609,13 @@ NTSTATUS FspFsvolCreateComplete(
Irp->Tail.Overlay.AuxiliaryBuffer = FspAllocNonPagedExternal(
Response->Rsp.Create.Reparse.Data.Size);
if (0 == Irp->Tail.Overlay.AuxiliaryBuffer)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
FSP_RETURN();
}
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
RtlCopyMemory(Irp->Tail.Overlay.AuxiliaryBuffer, ReparseData,
Response->Rsp.Create.Reparse.Data.Size);
Irp->IoStatus.Information = ReparseData->ReparseTag;
Result = STATUS_REPARSE;
FSP_RETURN();
FSP_RETURN(Result = STATUS_REPARSE);
}
}

View File

@ -427,6 +427,8 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectByName(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);

View File

@ -109,8 +109,9 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PREPARSE_DATA_BUFFER ReparseData;
PWSTR PathBuffer;
BOOLEAN TargetOnFileSystem = FALSE;
PWSTR ReparseTargetPath;
USHORT ReparseTargetPathLength;
UINT16 TargetOnFileSystem = 0;
FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode);
@ -139,36 +140,28 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
return STATUS_PRIVILEGE_NOT_HELD;
}
/* determine if target resides on same device as link (convenience for user mode) */
PathBuffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
if (ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength > 4 * sizeof(WCHAR) &&
'\\' == PathBuffer[0] &&
'?' == PathBuffer[1] &&
'?' == PathBuffer[2] &&
'\\' == PathBuffer[3])
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
/* is this an absolute path? determine if target resides on same device as link */
if (ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
{
UNICODE_STRING TargetDeviceName;
PFILE_OBJECT TargetDeviceFile;
UNICODE_STRING TargetObjectName;
PDEVICE_OBJECT TargetDeviceObject;
ULONG TargetFileNameIndex;
RtlInitEmptyUnicodeString(&TargetDeviceName,
PathBuffer,
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
TargetObjectName.Length = TargetObjectName.MaximumLength = ReparseTargetPathLength;
TargetObjectName.Buffer = ReparseTargetPath;
/* the first path component is assumed to be the device name */
TargetDeviceName.Length = 4 * sizeof(WCHAR);
while (TargetDeviceName.Length < TargetDeviceName.MaximumLength &&
'\\' != TargetDeviceName.Buffer[TargetDeviceName.Length / sizeof(WCHAR)])
TargetDeviceName.Length += sizeof(WCHAR);
Result = IoGetDeviceObjectPointer(&TargetDeviceName,
FILE_READ_ATTRIBUTES, &TargetDeviceFile, &TargetDeviceObject);
Result = FspGetDeviceObjectByName(&TargetObjectName, FILE_READ_DATA,
&TargetFileNameIndex, &TargetDeviceObject);
if (!NT_SUCCESS(Result))
goto target_check_exit;
TargetOnFileSystem = IoGetRelatedDeviceObject(FileObject) == TargetDeviceObject;
ObDereferenceObject(TargetDeviceFile);
TargetOnFileSystem = IoGetRelatedDeviceObject(FileObject) == TargetDeviceObject ?
(UINT16)TargetFileNameIndex : 0;
ObDereferenceObject(TargetDeviceObject);
target_check_exit:
;

View File

@ -20,6 +20,8 @@
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectByName(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
static NTSTATUS FspSendSetInformationIrpCompletion(
@ -88,6 +90,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#pragma alloc_text(PAGE, FspUnicodePathIsValid)
#pragma alloc_text(PAGE, FspUnicodePathSuffix)
#pragma alloc_text(PAGE, FspCreateGuid)
#pragma alloc_text(PAGE, FspGetDeviceObjectByName)
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
#pragma alloc_text(PAGE, FspBufferUserBuffer)
#pragma alloc_text(PAGE, FspLockUserBuffer)
@ -243,6 +246,55 @@ NTSTATUS FspCreateGuid(GUID *Guid)
return Result;
}
NTSTATUS FspGetDeviceObjectByName(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PDEVICE_OBJECT *PDeviceObject)
{
UNICODE_STRING PartialName;
PFILE_OBJECT FileObject;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Handle;
NTSTATUS Result;
PartialName.Length = 0;
PartialName.MaximumLength = ObjectName->Length;
PartialName.Buffer = ObjectName->Buffer;
Result = STATUS_NO_SUCH_DEVICE;
while (PartialName.MaximumLength > PartialName.Length)
{
while (PartialName.MaximumLength > PartialName.Length &&
L'\\' == PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
PartialName.Length += sizeof(WCHAR);
while (PartialName.MaximumLength > PartialName.Length &&
L'\\' != PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
PartialName.Length += sizeof(WCHAR);
Result = IoGetDeviceObjectPointer(&PartialName, DesiredAccess, &FileObject, PDeviceObject);
if (NT_SUCCESS(Result))
{
*PFileNameIndex = PartialName.Length;
ObReferenceObject(*PDeviceObject);
ObDereferenceObject(FileObject);
break;
}
InitializeObjectAttributes(&ObjectAttributes, &PartialName, OBJ_KERNEL_HANDLE, 0, 0);
Result = ZwOpenDirectoryObject(&Handle, 0, &ObjectAttributes);
if (!NT_SUCCESS(Result))
{
Result = ZwOpenSymbolicLinkObject(&Handle, 0, &ObjectAttributes);
if (!NT_SUCCESS(Result))
{
Result = STATUS_NO_SUCH_DEVICE;
break;
}
}
ZwClose(Handle);
}
return Result;
}
typedef struct
{
IO_STATUS_BLOCK IoStatus;