sys, dll: mount manager support

This commit is contained in:
Bill Zissimopoulos 2019-09-06 14:24:00 -07:00
parent 565caebe4c
commit 4655926d03
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
9 changed files with 223 additions and 46 deletions

View File

@ -601,7 +601,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
PHANDLE PVolumeHandle);
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
BOOLEAN Persistent);
BOOLEAN Persistent, GUID *UniqueId);
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
PVOID ResponseBuf, SIZE_T ResponseBufSize,
PVOID RequestBuf, SIZE_T *PRequestBufSize,

View File

@ -455,12 +455,19 @@ static NTSTATUS FspFileSystemSetMountPoint_Mountmgr(PWSTR MountPoint, PWSTR Volu
USHORT DeviceNameLength;
} MOUNTMGR_CREATE_POINT_INPUT;
GUID UniqueId;
MOUNTMGR_CREATE_POINT_INPUT *Input = 0;
ULONG VolumeNameSize, InputSize;
HKEY RegKey;
LONG RegResult;
WCHAR RegValueName[MAX_PATH];
UINT8 RegValueData[sizeof UniqueId];
DWORD RegValueNameSize, RegValueDataSize;
DWORD RegType;
NTSTATUS Result;
/* transform our volume into one that can be used by the MountManager */
Result = FspFsctlMakeMountdev(VolumeHandle, FALSE);
Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId);
if (!NT_SUCCESS(Result))
goto exit;
@ -493,6 +500,36 @@ static NTSTATUS FspFileSystemSetMountPoint_Mountmgr(PWSTR MountPoint, PWSTR Volu
if (!NT_SUCCESS(Result))
goto exit;
/* HACK: delete the MountManager registry entries */
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices",
0, KEY_READ | KEY_WRITE, &RegKey);
if (ERROR_SUCCESS == RegResult)
{
for (DWORD I = 0;; I++)
{
RegValueNameSize = MAX_PATH;
RegValueDataSize = sizeof RegValueData;
RegResult = RegEnumValueW(RegKey,
I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize);
if (ERROR_NO_MORE_ITEMS == RegResult)
break;
else if (ERROR_SUCCESS != RegResult)
continue;
if (REG_BINARY == RegType &&
sizeof RegValueData == RegValueDataSize &&
InlineIsEqualGUID((GUID *)&RegValueData, &UniqueId))
{
RegResult = RegDeleteValueW(RegKey, RegValueName);
if (ERROR_SUCCESS == RegResult)
/* reset index after modifying key; only safe way to use RegEnumValueW with modifications */
I = -1;
}
}
RegCloseKey(RegKey);
}
Result = STATUS_SUCCESS;
exit:

View File

@ -108,13 +108,13 @@ exit:
}
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
BOOLEAN Persistent)
BOOLEAN Persistent, GUID *UniqueId)
{
DWORD Bytes;
if (!DeviceIoControl(VolumeHandle,
FSP_FSCTL_MOUNTDEV,
&Persistent, sizeof Persistent, 0, 0,
&Persistent, sizeof Persistent, UniqueId, sizeof *UniqueId,
&Bytes, 0))
return FspNtStatusFromWin32(GetLastError());

View File

@ -67,8 +67,6 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsmupDeviceFini(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspDeviceCopyList(
@ -102,8 +100,6 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceCompareContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceAllocateContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceFreeContextByName)
#pragma alloc_text(PAGE, FspFsvrtDeviceInit)
#pragma alloc_text(PAGE, FspFsvrtDeviceFini)
#pragma alloc_text(PAGE, FspFsmupDeviceInit)
#pragma alloc_text(PAGE, FspFsmupDeviceFini)
#pragma alloc_text(PAGE, FspDeviceCopyList)
@ -191,7 +187,7 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
Result = FspFsvolDeviceInit(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
Result = FspFsvrtDeviceInit(DeviceObject);
Result = STATUS_SUCCESS;
break;
case FspFsmupDeviceExtensionKind:
Result = FspFsmupDeviceInit(DeviceObject);
@ -222,7 +218,6 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
FspFsvolDeviceFini(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
FspFsvrtDeviceFini(DeviceObject);
break;
case FspFsmupDeviceExtensionKind:
FspFsmupDeviceFini(DeviceObject);
@ -950,20 +945,6 @@ VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject)
KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql);
}
static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
return STATUS_SUCCESS;
}
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FspMountdevFini(DeviceObject);
}
static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();

View File

@ -514,6 +514,8 @@ NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileO
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags);

View File

@ -154,7 +154,7 @@ NTSTATUS FspMountdevMake(
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
return Persistent == FsvrtDeviceExtension->Persistent ?
STATUS_SUCCESS : STATUS_ACCESS_DENIED;
STATUS_TOO_LATE : STATUS_ACCESS_DENIED;
FsvrtDeviceExtension->Persistent = Persistent;
@ -188,4 +188,39 @@ exit:
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
PVOID Buffer = 0;
ULONG Length = 4096;
MOUNTMGR_MOUNT_POINT *MountPoint;
NTSTATUS Result;
if (0 == InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
return;
if (FsvrtDeviceExtension->Persistent)
/* if the mountdev is marked as persistent do not purge the MountManager */
return;
Buffer = FspAllocNonPaged(Length);
if (0 == Buffer)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
MountPoint = Buffer;
RtlZeroMemory(MountPoint, sizeof *MountPoint);
MountPoint->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
MountPoint->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
RtlCopyMemory((PUINT8)MountPoint + MountPoint->UniqueIdOffset,
&FsvrtDeviceExtension->UniqueId, MountPoint->UniqueIdLength);
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_DELETE_POINTS,
Buffer, MountPoint->UniqueIdOffset + MountPoint->UniqueIdLength, &Length);
exit:
if (0 != Buffer)
FspFree(Buffer);
}

View File

@ -35,6 +35,8 @@ NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileO
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
static NTSTATUS FspSendIrpCompletion(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
@ -136,6 +138,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
#pragma alloc_text(PAGE, FspSendQuerySecurityIrp)
#pragma alloc_text(PAGE, FspSendQueryEaIrp)
#pragma alloc_text(PAGE, FspSendMountmgrDeviceControlIrp)
#pragma alloc_text(PAGE, FspBufferUserBuffer)
#pragma alloc_text(PAGE, FspLockUserBuffer)
#pragma alloc_text(PAGE, FspMapLockedPagesInUserMode)
@ -444,6 +447,63 @@ NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
return Context.IoStatus.Status;
}
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength)
{
PAGED_CODE();
ASSERT(METHOD_BUFFERED == (IoControlCode & 3));
NTSTATUS Result;
UNICODE_STRING DeviceName;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
FSP_SEND_IRP_CONTEXT Context;
ULONG OutputBufferLength = 0;
if (0 == POutputBufferLength)
POutputBufferLength = &OutputBufferLength;
RtlInitUnicodeString(&DeviceName, MOUNTMGR_DEVICE_NAME);
Result = IoGetDeviceObjectPointer(&DeviceName, FILE_READ_ATTRIBUTES,
&FileObject, &DeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (0 == Irp)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
IrpSp = IoGetNextIrpStackLocation(Irp);
Irp->RequestorMode = KernelMode;
Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = *POutputBufferLength;
IrpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
IrpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
Result = IoCallDriver(DeviceObject, Irp);
if (STATUS_PENDING == Result)
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
*POutputBufferLength = (ULONG)Context.IoStatus.Information;
Result = Context.IoStatus.Status;
exit:
if (0 != FileObject)
ObDereferenceObject(FileObject);
return Result;
}
static NTSTATUS FspSendIrpCompletion(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0)
{

View File

@ -36,8 +36,6 @@ static NTSTATUS FspVolumeMountNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeMakeMountdev(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeMakeMountdevNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetName(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetNameList(
@ -62,7 +60,6 @@ NTSTATUS FspVolumeWork(
// ! #pragma alloc_text(PAGE, FspVolumeMount)
// ! #pragma alloc_text(PAGE, FspVolumeMountNoLock)
#pragma alloc_text(PAGE, FspVolumeMakeMountdev)
#pragma alloc_text(PAGE, FspVolumeMakeMountdevNoLock)
#pragma alloc_text(PAGE, FspVolumeGetName)
#pragma alloc_text(PAGE, FspVolumeGetNameList)
#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock)
@ -327,10 +324,22 @@ VOID FspVolumeDelete(
// !PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
FSP_FILE_NODE **FileNodes;
ULONG FileNodeCount, Index;
NTSTATUS Result;
/*
* If we have an fsvrt that is a mountdev, finalize it now! Finalizing a mountdev
* involves interaction with the MountManager, which tries to open our devices.
* So if we delay this interaction and we do it during final fsvrt teardown (i.e.
* FspDeviceDelete time) we will fail such opens with STATUS_CANCELLED, which will
* confuse the MountManager.
*/
if (0 != FsvrtDeviceObject)
FspMountdevFini(FsvrtDeviceObject);
FspDeviceReference(FsvolDeviceObject);
FspDeviceGlobalLock();
@ -554,18 +563,6 @@ NTSTATUS FspVolumeMakeMountdev(
{
PAGED_CODE();
NTSTATUS Result;
FspDeviceGlobalLock();
Result = FspVolumeMakeMountdevNoLock(FsctlDeviceObject, Irp, IrpSp);
FspDeviceGlobalUnlock();
return Result;
}
NTSTATUS FspVolumeMakeMountdevNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(FSP_FSCTL_MOUNTDEV == IrpSp->Parameters.FileSystemControl.FsControlCode);
@ -575,13 +572,65 @@ NTSTATUS FspVolumeMakeMountdevNoLock(
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
BOOLEAN Persistent = 0 < InputBufferLength ? !!*(PBOOLEAN)InputBuffer : FALSE;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
BOOLEAN Persistent = 0 < InputBufferLength ? !!*(PBOOLEAN)Irp->AssociatedIrp.SystemBuffer : FALSE;
MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount;
MOUNTMGR_SET_AUTO_MOUNT SetAutoMount;
union
{
MOUNTMGR_TARGET_NAME V;
UINT8 B[FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + FSP_FSCTL_VOLUME_NAME_SIZEMAX];
} TargetName;
ULONG Length;
NTSTATUS Result;
if (0 == FsvrtDeviceObject)
return STATUS_INVALID_PARAMETER;
if (sizeof(GUID) > OutputBufferLength)
return STATUS_INVALID_PARAMETER;
return FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent);
FspDeviceGlobalLock();
Result = FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent);
if (NT_SUCCESS(Result))
{
Length = sizeof QueryAutoMount;
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT,
&QueryAutoMount, 0, &Length);
if (!NT_SUCCESS(Result))
goto exit;
SetAutoMount.NewState = 0;
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_SET_AUTO_MOUNT,
&SetAutoMount, sizeof SetAutoMount, 0);
if (!NT_SUCCESS(Result))
goto exit;
TargetName.V.DeviceNameLength = FsvolDeviceExtension->VolumeName.Length;
RtlCopyMemory(TargetName.V.DeviceName,
FsvolDeviceExtension->VolumeName.Buffer, FsvolDeviceExtension->VolumeName.Length);
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
&TargetName.V, FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + TargetName.V.DeviceNameLength, 0);
SetAutoMount.NewState = QueryAutoMount.CurrentState;
FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_SET_AUTO_MOUNT,
&SetAutoMount, sizeof SetAutoMount, 0);
}
else if (STATUS_TOO_LATE == Result)
Result = STATUS_SUCCESS;
if (!NT_SUCCESS(Result))
goto exit;
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
&FspFsvrtDeviceExtension(FsvrtDeviceObject)->UniqueId, sizeof(GUID));
Irp->IoStatus.Information = sizeof(GUID);
Result = STATUS_SUCCESS;
exit:
FspDeviceGlobalUnlock();
return Result;
}
NTSTATUS FspVolumeGetName(

View File

@ -104,7 +104,7 @@ static void volpath_mount_dotest(ULONG Flags, PWSTR Prefix, PWSTR MountPoint)
HANDLE Handle;
BOOLEAN Success, VolumePathNameSuccess[8];
WCHAR FilePath[MAX_PATH];
WCHAR VolumePathName[MAX_PATH];
WCHAR VolumePathName[MAX_PATH], VolumeName[MAX_PATH];
Result = FspFileSystemSetMountPoint(MemfsFileSystem(memfs), MountPoint);
ASSERT(NT_SUCCESS(Result));
@ -129,16 +129,19 @@ static void volpath_mount_dotest(ULONG Flags, PWSTR Prefix, PWSTR MountPoint)
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
VolumePathNameSuccess[0] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
VolumePathNameSuccess[4] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
VolumePathNameSuccess[1] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
VolumePathNameSuccess[5] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
VolumePathNameSuccess[2] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
VolumePathNameSuccess[6] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
@ -152,10 +155,20 @@ static void volpath_mount_dotest(ULONG Flags, PWSTR Prefix, PWSTR MountPoint)
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
FspFileSystemRemoveMountPoint(MemfsFileSystem(memfs));
memfs_stop(memfs);
ASSERT(VolumePathNameSuccess[0] == VolumePathNameSuccess[1]);
ASSERT(VolumePathNameSuccess[1] == VolumePathNameSuccess[2]);
ASSERT(VolumePathNameSuccess[0]);
ASSERT(VolumePathNameSuccess[1]);
ASSERT(VolumePathNameSuccess[2]);
if (MemfsNet != Flags)
{
ASSERT(VolumePathNameSuccess[4]);
ASSERT(VolumePathNameSuccess[5]);
ASSERT(VolumePathNameSuccess[6]);
}
}
static void volpath_mount_test(void)