mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-11-03 20:48:08 -06:00 
			
		
		
		
	sys: initial ProcessBuffer implementation
This commit is contained in:
		@@ -174,6 +174,7 @@
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\lockctl.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\meta.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\name.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\psbuffer.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\read.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\security.c" />
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\shutdown.c" />
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,9 @@
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\statistics.c">
 | 
			
		||||
      <Filter>Source</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\sys\psbuffer.c">
 | 
			
		||||
      <Filter>Source</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ClInclude Include="..\..\src\sys\driver.h">
 | 
			
		||||
 
 | 
			
		||||
@@ -148,7 +148,8 @@ typedef struct
 | 
			
		||||
    /* kernel-mode flags */
 | 
			
		||||
    UINT32 PostCleanupWhenModifiedOnly:1;   /* post Cleanup when a file was modified/deleted */
 | 
			
		||||
    UINT32 PassQueryDirectoryPattern:1;     /* pass Pattern during QueryDirectory operations */
 | 
			
		||||
    UINT32 KmReservedFlags:4;
 | 
			
		||||
    UINT32 AlwaysUseDoubleBuffering:1;
 | 
			
		||||
    UINT32 KmReservedFlags:3;
 | 
			
		||||
    /* user-mode flags */
 | 
			
		||||
    UINT32 UmFileContextIsUserContext2:1;   /* user mode: FileContext parameter is UserContext2 */
 | 
			
		||||
    UINT32 UmFileContextIsFullContext:1;    /* user mode: FileContext parameter is FullContext */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										162
									
								
								src/sys/dirctl.c
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								src/sys/dirctl.c
									
									
									
									
									
								
							@@ -78,6 +78,7 @@ enum
 | 
			
		||||
{
 | 
			
		||||
    /* QueryDirectory */
 | 
			
		||||
    RequestIrp                          = 0,
 | 
			
		||||
    RequestCookie                       = 1,
 | 
			
		||||
    RequestMdl                          = 1,
 | 
			
		||||
    RequestAddress                      = 2,
 | 
			
		||||
    RequestProcess                      = 3,
 | 
			
		||||
@@ -833,41 +834,68 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
 | 
			
		||||
{
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    NTSTATUS Result;
 | 
			
		||||
    PMDL Mdl = 0;
 | 
			
		||||
    PVOID Address;
 | 
			
		||||
    PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
    Mdl = IoAllocateMdl(
 | 
			
		||||
        Irp->AssociatedIrp.SystemBuffer,
 | 
			
		||||
        Request->Req.QueryDirectory.Length,
 | 
			
		||||
        FALSE, FALSE, 0);
 | 
			
		||||
    if (0 == Mdl)
 | 
			
		||||
        return STATUS_INSUFFICIENT_RESOURCES;
 | 
			
		||||
 | 
			
		||||
    MmBuildMdlForNonPagedPool(Mdl);
 | 
			
		||||
 | 
			
		||||
    /* map the MDL into user-mode */
 | 
			
		||||
    Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
    if (FspFsvolDeviceQueryDirectoryShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.QueryDirectory.Length))
 | 
			
		||||
    {
 | 
			
		||||
        if (0 != Mdl)
 | 
			
		||||
            IoFreeMdl(Mdl);
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        PVOID Cookie;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
        return Result;
 | 
			
		||||
        Result = FspProcessBufferAcquire(Request->Req.QueryDirectory.Length, &Cookie, &Address);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
            return Result;
 | 
			
		||||
 | 
			
		||||
        /* get a pointer to the current process so that we can release the buffer later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestCookie) = Cookie;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        PMDL Mdl = 0;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
    /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
    Process = PsGetCurrentProcess();
 | 
			
		||||
    ObReferenceObject(Process);
 | 
			
		||||
        Mdl = IoAllocateMdl(
 | 
			
		||||
            Irp->AssociatedIrp.SystemBuffer,
 | 
			
		||||
            Request->Req.QueryDirectory.Length,
 | 
			
		||||
            FALSE, FALSE, 0);
 | 
			
		||||
        if (0 == Mdl)
 | 
			
		||||
            return STATUS_INSUFFICIENT_RESOURCES;
 | 
			
		||||
 | 
			
		||||
    Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
        MmBuildMdlForNonPagedPool(Mdl);
 | 
			
		||||
 | 
			
		||||
    FspIopRequestContext(Request, RequestMdl) = Mdl;
 | 
			
		||||
    FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
    FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
        /* map the MDL into user-mode */
 | 
			
		||||
        Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
        {
 | 
			
		||||
            if (0 != Mdl)
 | 
			
		||||
                IoFreeMdl(Mdl);
 | 
			
		||||
 | 
			
		||||
    return STATUS_SUCCESS;
 | 
			
		||||
            return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestMdl) = Mdl;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NTSTATUS FspFsvolDirectoryControlComplete(
 | 
			
		||||
@@ -910,6 +938,24 @@ NTSTATUS FspFsvolDirectoryControlComplete(
 | 
			
		||||
 | 
			
		||||
    if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
 | 
			
		||||
    {
 | 
			
		||||
        if (FspFsvolDeviceQueryDirectoryShouldUseProcessBuffer(
 | 
			
		||||
            IrpSp->DeviceObject, Request->Req.QueryDirectory.Length))
 | 
			
		||||
        {
 | 
			
		||||
            PVOID Address = FspIopRequestContext(Request, RequestAddress);
 | 
			
		||||
 | 
			
		||||
            ASSERT(0 != Address);
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Address, Response->IoStatus.Information);
 | 
			
		||||
            }
 | 
			
		||||
            except (EXCEPTION_EXECUTE_HANDLER)
 | 
			
		||||
            {
 | 
			
		||||
                Result = GetExceptionCode();
 | 
			
		||||
                Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
 | 
			
		||||
                FSP_RETURN();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
 | 
			
		||||
        Request->Kind = FspFsctlTransactReservedKind;
 | 
			
		||||
        FspIopResetRequest(Request, 0);
 | 
			
		||||
@@ -1010,29 +1056,57 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    PIRP Irp = Context[RequestIrp];
 | 
			
		||||
    PMDL Mdl = Context[RequestMdl];
 | 
			
		||||
    PVOID Address = Context[RequestAddress];
 | 
			
		||||
    PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != Address)
 | 
			
		||||
    if (0 != Irp && FspFsvolDeviceQueryDirectoryShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.QueryDirectory.Length))
 | 
			
		||||
    {
 | 
			
		||||
        KAPC_STATE ApcState;
 | 
			
		||||
        BOOLEAN Attach;
 | 
			
		||||
        PVOID Cookie = Context[RequestCookie];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
        ASSERT(0 != Process);
 | 
			
		||||
        Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
        MmUnmapLockedPages(Address, Mdl);
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
        ObDereferenceObject(Process);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            FspProcessBufferRelease(Cookie, Address);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        PMDL Mdl = Context[RequestMdl];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != Mdl)
 | 
			
		||||
        IoFreeMdl(Mdl);
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            MmUnmapLockedPages(Address, Mdl);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 != Mdl)
 | 
			
		||||
            IoFreeMdl(Mdl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != Irp)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,10 @@ NTSTATUS DriverEntry(
 | 
			
		||||
 | 
			
		||||
    FspDriverMultiVersionInitialize();
 | 
			
		||||
 | 
			
		||||
    Result = FspProcessBufferInitialize();
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
        FSP_RETURN();
 | 
			
		||||
 | 
			
		||||
    FspDriverObject = DriverObject;
 | 
			
		||||
    ExInitializeResourceLite(&FspDeviceGlobalResource);
 | 
			
		||||
 | 
			
		||||
@@ -59,14 +63,21 @@ NTSTATUS DriverEntry(
 | 
			
		||||
        &DeviceSddl, &FspFsctlDeviceClassGuid,
 | 
			
		||||
        &FspFsctlDiskDeviceObject);
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
    {
 | 
			
		||||
        FspProcessBufferFinalize();
 | 
			
		||||
        FSP_RETURN();
 | 
			
		||||
    }
 | 
			
		||||
    RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
 | 
			
		||||
    Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
 | 
			
		||||
        &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
 | 
			
		||||
        &DeviceSddl, &FspFsctlDeviceClassGuid,
 | 
			
		||||
        &FspFsctlNetDeviceObject);
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
        FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
 | 
			
		||||
    {
 | 
			
		||||
        FspDeviceDelete(FspFsctlDiskDeviceObject);
 | 
			
		||||
        FspProcessBufferFinalize();
 | 
			
		||||
        FSP_RETURN();
 | 
			
		||||
    }
 | 
			
		||||
    Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
 | 
			
		||||
    ASSERT(STATUS_SUCCESS == Result);
 | 
			
		||||
    Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
 | 
			
		||||
@@ -207,6 +218,8 @@ VOID FspUnload(
 | 
			
		||||
    ExDeleteResourceLite(&FspDeviceGlobalResource);
 | 
			
		||||
    FspDriverObject = 0;
 | 
			
		||||
 | 
			
		||||
    FspProcessBufferFinalize();
 | 
			
		||||
 | 
			
		||||
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
 | 
			
		||||
    FSP_LEAVE_VOID("DriverName=\"%wZ\"",
 | 
			
		||||
        &DriverObject->DriverName);
 | 
			
		||||
 
 | 
			
		||||
@@ -601,6 +601,14 @@ VOID FspIrpHookReset(PIRP Irp);
 | 
			
		||||
PVOID FspIrpHookContext(PVOID Context);
 | 
			
		||||
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
 | 
			
		||||
 | 
			
		||||
/* process buffers */
 | 
			
		||||
#define FspProcessBufferSizeMax         (64 * 1024)
 | 
			
		||||
NTSTATUS FspProcessBufferInitialize(VOID);
 | 
			
		||||
VOID FspProcessBufferFinalize(VOID);
 | 
			
		||||
VOID FspProcessBufferCollect(HANDLE ProcessId);
 | 
			
		||||
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer);
 | 
			
		||||
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer);
 | 
			
		||||
 | 
			
		||||
/* IRP context */
 | 
			
		||||
#define FspIrpTimestampInfinity         ((ULONG)-1L)
 | 
			
		||||
#define FspIrpTimestamp(Irp)            \
 | 
			
		||||
@@ -1048,6 +1056,23 @@ FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject)
 | 
			
		||||
    ASSERT(FspFsvolDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
 | 
			
		||||
    return DeviceObject->DeviceExtension;
 | 
			
		||||
}
 | 
			
		||||
static inline
 | 
			
		||||
BOOLEAN FspFsvolDeviceReadShouldUseProcessBuffer(PDEVICE_OBJECT FsvolDeviceObject, SIZE_T BufferSize)
 | 
			
		||||
{
 | 
			
		||||
    return FspProcessBufferSizeMax >= BufferSize ||
 | 
			
		||||
        FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.AlwaysUseDoubleBuffering;
 | 
			
		||||
}
 | 
			
		||||
static inline
 | 
			
		||||
BOOLEAN FspFsvolDeviceWriteShouldUseProcessBuffer(PDEVICE_OBJECT FsvolDeviceObject, SIZE_T BufferSize)
 | 
			
		||||
{
 | 
			
		||||
    return FspProcessBufferSizeMax >= BufferSize ||
 | 
			
		||||
        FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.AlwaysUseDoubleBuffering;
 | 
			
		||||
}
 | 
			
		||||
static inline
 | 
			
		||||
BOOLEAN FspFsvolDeviceQueryDirectoryShouldUseProcessBuffer(PDEVICE_OBJECT FsvolDeviceObject, SIZE_T BufferSize)
 | 
			
		||||
{
 | 
			
		||||
    return FspFsvolDeviceReadShouldUseProcessBuffer(FsvolDeviceObject, BufferSize);
 | 
			
		||||
}
 | 
			
		||||
NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
 | 
			
		||||
    PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics,
 | 
			
		||||
    PUNICODE_STRING DeviceSddl, LPCGUID DeviceClassGuid,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										280
									
								
								src/sys/psbuffer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								src/sys/psbuffer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file sys/psbuffer.c
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright 2015-2017 Bill Zissimopoulos
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * This file is part of WinFsp.
 | 
			
		||||
 *
 | 
			
		||||
 * You can redistribute it and/or modify it under the terms of the GNU
 | 
			
		||||
 * General Public License version 3 as published by the Free Software
 | 
			
		||||
 * Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensees holding a valid commercial license may use this file in
 | 
			
		||||
 * accordance with the commercial license agreement provided with the
 | 
			
		||||
 * software.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/driver.h>
 | 
			
		||||
 | 
			
		||||
#define SafeGetCurrentProcessId()       (PsGetProcessId(PsGetCurrentProcess()))
 | 
			
		||||
 | 
			
		||||
#define FspProcessBufferCountMax        (2 >= FspProcessorCount ? 2 : (8 <= FspProcessorCount ? 8 : FspProcessorCount))
 | 
			
		||||
#define ProcessBufferBucketCount        61  /* are you going to have that many file systems? */
 | 
			
		||||
 | 
			
		||||
typedef struct _FSP_PROCESS_BUFFER_ITEM
 | 
			
		||||
{
 | 
			
		||||
    struct _FSP_PROCESS_BUFFER_ITEM *DictNext;
 | 
			
		||||
    struct _FSP_PROCESS_BUFFER_LIST_ENTRY *BufferList;
 | 
			
		||||
    ULONG BufferCount;
 | 
			
		||||
    HANDLE ProcessId;
 | 
			
		||||
} FSP_PROCESS_BUFFER_ITEM;
 | 
			
		||||
 | 
			
		||||
typedef struct _FSP_PROCESS_BUFFER_LIST_ENTRY
 | 
			
		||||
{
 | 
			
		||||
    struct _FSP_PROCESS_BUFFER_LIST_ENTRY *Next;
 | 
			
		||||
    PVOID Buffer;
 | 
			
		||||
} FSP_PROCESS_BUFFER_LIST_ENTRY;
 | 
			
		||||
 | 
			
		||||
static KSPIN_LOCK ProcessBufferLock;
 | 
			
		||||
static FSP_PROCESS_BUFFER_ITEM *ProcessBufferBuckets[ProcessBufferBucketCount];
 | 
			
		||||
 | 
			
		||||
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create);
 | 
			
		||||
 | 
			
		||||
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferLookupItemAtDpcLevel(HANDLE ProcessId)
 | 
			
		||||
{
 | 
			
		||||
    FSP_PROCESS_BUFFER_ITEM *Item = 0;
 | 
			
		||||
    ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
 | 
			
		||||
    for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
 | 
			
		||||
        if (ItemX->ProcessId == ProcessId)
 | 
			
		||||
        {
 | 
			
		||||
            Item = ItemX;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    return Item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VOID FspProcessBufferAddItemAtDpcLevel(FSP_PROCESS_BUFFER_ITEM *Item)
 | 
			
		||||
{
 | 
			
		||||
    ULONG HashIndex = FspHashMixPointer(Item->ProcessId) % ProcessBufferBucketCount;
 | 
			
		||||
#if DBG
 | 
			
		||||
    for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
 | 
			
		||||
        ASSERT(ItemX->ProcessId != Item->ProcessId);
 | 
			
		||||
#endif
 | 
			
		||||
    Item->DictNext = ProcessBufferBuckets[HashIndex];
 | 
			
		||||
    ProcessBufferBuckets[HashIndex] = Item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferRemoveItemAtDpcLevel(HANDLE ProcessId)
 | 
			
		||||
{
 | 
			
		||||
    FSP_PROCESS_BUFFER_ITEM *Item = 0;
 | 
			
		||||
    ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
 | 
			
		||||
    for (FSP_PROCESS_BUFFER_ITEM **P = &ProcessBufferBuckets[HashIndex]; *P; P = &(*P)->DictNext)
 | 
			
		||||
        if ((*P)->ProcessId == ProcessId)
 | 
			
		||||
        {
 | 
			
		||||
            Item = *P;
 | 
			
		||||
            *P = (*P)->DictNext;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    return Item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VOID FspProcessBufferReuseEntry(HANDLE ProcessId,
 | 
			
		||||
    FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry)
 | 
			
		||||
{
 | 
			
		||||
    KIRQL Irql;
 | 
			
		||||
    FSP_PROCESS_BUFFER_ITEM *Item;
 | 
			
		||||
 | 
			
		||||
    KeAcquireSpinLock(&ProcessBufferLock, &Irql);
 | 
			
		||||
 | 
			
		||||
    Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
 | 
			
		||||
 | 
			
		||||
    if (0 != Item)
 | 
			
		||||
    {
 | 
			
		||||
        BufferEntry->Next = Item->BufferList;
 | 
			
		||||
        Item->BufferList = BufferEntry;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    KeReleaseSpinLock(&ProcessBufferLock, Irql);
 | 
			
		||||
 | 
			
		||||
    if (0 == Item)
 | 
			
		||||
    {
 | 
			
		||||
        if (0 != BufferEntry->Buffer)
 | 
			
		||||
        {
 | 
			
		||||
            SIZE_T BufferSize = 0;
 | 
			
		||||
            ZwFreeVirtualMemory(ZwCurrentProcess(), BufferEntry->Buffer, &BufferSize, MEM_RELEASE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FspFree(BufferEntry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NTSTATUS FspProcessBufferInitialize(VOID)
 | 
			
		||||
{
 | 
			
		||||
    KeInitializeSpinLock(&ProcessBufferLock);
 | 
			
		||||
 | 
			
		||||
    return PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VOID FspProcessBufferFinalize(VOID)
 | 
			
		||||
{
 | 
			
		||||
    PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
 | 
			
		||||
{
 | 
			
		||||
    if (!Create)
 | 
			
		||||
        FspProcessBufferCollect(ProcessId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VOID FspProcessBufferCollect(HANDLE ProcessId)
 | 
			
		||||
{
 | 
			
		||||
    KIRQL Irql;
 | 
			
		||||
    FSP_PROCESS_BUFFER_ITEM *Item = 0;
 | 
			
		||||
 | 
			
		||||
    KeAcquireSpinLock(&ProcessBufferLock, &Irql);
 | 
			
		||||
 | 
			
		||||
    Item = FspProcessBufferRemoveItemAtDpcLevel(ProcessId);
 | 
			
		||||
 | 
			
		||||
    KeReleaseSpinLock(&ProcessBufferLock, Irql);
 | 
			
		||||
 | 
			
		||||
    if (0 != Item)
 | 
			
		||||
    {
 | 
			
		||||
        DEBUGLOG("pid=%ld", (ULONG)(UINT_PTR)ProcessId);
 | 
			
		||||
 | 
			
		||||
        for (FSP_PROCESS_BUFFER_LIST_ENTRY *P = Item->BufferList, *Next; P; P = Next)
 | 
			
		||||
        {
 | 
			
		||||
            Next = P->Next;
 | 
			
		||||
            FspFree(P);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FspFree(Item);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer)
 | 
			
		||||
{
 | 
			
		||||
    if (FspProcessBufferSizeMax >= BufferSize)
 | 
			
		||||
    {
 | 
			
		||||
        HANDLE ProcessId = SafeGetCurrentProcessId();
 | 
			
		||||
        KIRQL Irql;
 | 
			
		||||
        FSP_PROCESS_BUFFER_ITEM *Item, *NewItem;
 | 
			
		||||
        FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = 0;
 | 
			
		||||
        BOOLEAN AllocNoReuse;
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
 | 
			
		||||
        KeAcquireSpinLock(&ProcessBufferLock, &Irql);
 | 
			
		||||
 | 
			
		||||
        Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
 | 
			
		||||
 | 
			
		||||
        if (0 != Item)
 | 
			
		||||
        {
 | 
			
		||||
            BufferEntry = Item->BufferList;
 | 
			
		||||
            if (0 != BufferEntry)
 | 
			
		||||
                Item->BufferList = BufferEntry->Next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AllocNoReuse = 0 == BufferEntry &&
 | 
			
		||||
            (0 != Item && FspProcessBufferCountMax <= Item->BufferCount);
 | 
			
		||||
 | 
			
		||||
        KeReleaseSpinLock(&ProcessBufferLock, Irql);
 | 
			
		||||
 | 
			
		||||
        if (AllocNoReuse)
 | 
			
		||||
            goto alloc_no_reuse;
 | 
			
		||||
 | 
			
		||||
        if (0 == BufferEntry)
 | 
			
		||||
        {
 | 
			
		||||
            *PBufferCookie = 0;
 | 
			
		||||
            *PBuffer = 0;
 | 
			
		||||
 | 
			
		||||
            BufferEntry = FspAllocNonPaged(sizeof *BufferEntry);
 | 
			
		||||
            if (0 == BufferEntry)
 | 
			
		||||
                return STATUS_INSUFFICIENT_RESOURCES;
 | 
			
		||||
            RtlZeroMemory(BufferEntry, sizeof *BufferEntry);
 | 
			
		||||
 | 
			
		||||
            NewItem = FspAllocNonPaged(sizeof *NewItem);
 | 
			
		||||
            if (0 == NewItem)
 | 
			
		||||
            {
 | 
			
		||||
                FspFree(BufferEntry);
 | 
			
		||||
                return STATUS_INSUFFICIENT_RESOURCES;
 | 
			
		||||
            }
 | 
			
		||||
            RtlZeroMemory(NewItem, sizeof *NewItem);
 | 
			
		||||
 | 
			
		||||
            KeAcquireSpinLock(&ProcessBufferLock, &Irql);
 | 
			
		||||
 | 
			
		||||
            Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
 | 
			
		||||
 | 
			
		||||
            if (0 == Item)
 | 
			
		||||
            {
 | 
			
		||||
                Item = NewItem;
 | 
			
		||||
                NewItem = 0;
 | 
			
		||||
                Item->BufferCount = 1;
 | 
			
		||||
                Item->ProcessId = ProcessId;
 | 
			
		||||
                FspProcessBufferAddItemAtDpcLevel(Item);
 | 
			
		||||
            }
 | 
			
		||||
            else if (FspProcessBufferCountMax > Item->BufferCount)
 | 
			
		||||
                Item->BufferCount++;
 | 
			
		||||
            else
 | 
			
		||||
                AllocNoReuse = TRUE;
 | 
			
		||||
 | 
			
		||||
            KeReleaseSpinLock(&ProcessBufferLock, Irql);
 | 
			
		||||
 | 
			
		||||
            if (0 != NewItem)
 | 
			
		||||
                FspFree(NewItem);
 | 
			
		||||
 | 
			
		||||
            if (AllocNoReuse)
 | 
			
		||||
            {
 | 
			
		||||
                FspFree(BufferEntry);
 | 
			
		||||
                goto alloc_no_reuse;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 == BufferEntry->Buffer)
 | 
			
		||||
        {
 | 
			
		||||
            BufferSize = FspProcessBufferSizeMax;
 | 
			
		||||
            Result = ZwAllocateVirtualMemory(ZwCurrentProcess(),
 | 
			
		||||
                &BufferEntry->Buffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
 | 
			
		||||
            if (!NT_SUCCESS(Result))
 | 
			
		||||
            {
 | 
			
		||||
                /* failed to allocate actual buffer; reuse BufferEntry */
 | 
			
		||||
                FspProcessBufferReuseEntry(ProcessId, BufferEntry);
 | 
			
		||||
 | 
			
		||||
                return Result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *PBufferCookie = BufferEntry;
 | 
			
		||||
        *PBuffer = BufferEntry->Buffer;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
    alloc_no_reuse:
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
 | 
			
		||||
        *PBufferCookie = 0;
 | 
			
		||||
        Result = ZwAllocateVirtualMemory(ZwCurrentProcess(),
 | 
			
		||||
            PBuffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
 | 
			
		||||
 | 
			
		||||
        return Result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer)
 | 
			
		||||
{
 | 
			
		||||
    if (0 != BufferCookie)
 | 
			
		||||
    {
 | 
			
		||||
        HANDLE ProcessId = SafeGetCurrentProcessId();
 | 
			
		||||
        FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = BufferCookie;
 | 
			
		||||
 | 
			
		||||
        ASSERT(Buffer == BufferEntry->Buffer);
 | 
			
		||||
 | 
			
		||||
        FspProcessBufferReuseEntry(ProcessId, BufferEntry);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        SIZE_T BufferSize = 0;
 | 
			
		||||
        ZwFreeVirtualMemory(ZwCurrentProcess(), Buffer, &BufferSize, MEM_RELEASE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										177
									
								
								src/sys/read.c
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								src/sys/read.c
									
									
									
									
									
								
							@@ -44,6 +44,7 @@ enum
 | 
			
		||||
{
 | 
			
		||||
    /* ReadNonCached */
 | 
			
		||||
    RequestIrp                          = 0,
 | 
			
		||||
    RequestCookie                       = 1,
 | 
			
		||||
    RequestSafeMdl                      = 1,
 | 
			
		||||
    RequestAddress                      = 2,
 | 
			
		||||
    RequestProcess                      = 3,
 | 
			
		||||
@@ -346,41 +347,71 @@ NTSTATUS FspFsvolReadPrepare(
 | 
			
		||||
{
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    NTSTATUS Result;
 | 
			
		||||
    FSP_SAFE_MDL *SafeMdl = 0;
 | 
			
		||||
    PVOID Address;
 | 
			
		||||
    PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
    /* create a "safe" MDL if necessary */
 | 
			
		||||
    if (!FspSafeMdlCheck(Irp->MdlAddress))
 | 
			
		||||
    if (FspFsvolDeviceReadShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.Read.Length))
 | 
			
		||||
    {
 | 
			
		||||
        Result = FspSafeMdlCreate(Irp->MdlAddress, IoWriteAccess, &SafeMdl);
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        PVOID Cookie;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
        if (0 == MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))
 | 
			
		||||
            return STATUS_INSUFFICIENT_RESOURCES; /* something is seriously screwy! */
 | 
			
		||||
 | 
			
		||||
        Result = FspProcessBufferAcquire(Request->Req.Read.Length, &Cookie, &Address);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
            return Result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* map the MDL into user-mode */
 | 
			
		||||
    Result = FspMapLockedPagesInUserMode(
 | 
			
		||||
        0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, 0);
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
        /* get a pointer to the current process so that we can release the buffer later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestCookie) = Cookie;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (0 != SafeMdl)
 | 
			
		||||
            FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        FSP_SAFE_MDL *SafeMdl = 0;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
        return Result;
 | 
			
		||||
        /* create a "safe" MDL if necessary */
 | 
			
		||||
        if (!FspSafeMdlCheck(Irp->MdlAddress))
 | 
			
		||||
        {
 | 
			
		||||
            Result = FspSafeMdlCreate(Irp->MdlAddress, IoWriteAccess, &SafeMdl);
 | 
			
		||||
            if (!NT_SUCCESS(Result))
 | 
			
		||||
                return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* map the MDL into user-mode */
 | 
			
		||||
        Result = FspMapLockedPagesInUserMode(
 | 
			
		||||
            0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, 0);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
        {
 | 
			
		||||
            if (0 != SafeMdl)
 | 
			
		||||
                FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
 | 
			
		||||
            return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
    Process = PsGetCurrentProcess();
 | 
			
		||||
    ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
    Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
    FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
 | 
			
		||||
    FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
    FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
    return STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NTSTATUS FspFsvolReadComplete(
 | 
			
		||||
@@ -400,15 +431,37 @@ NTSTATUS FspFsvolReadComplete(
 | 
			
		||||
    if (Response->IoStatus.Information > Request->Req.Read.Length)
 | 
			
		||||
        FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
 | 
			
		||||
 | 
			
		||||
    FSP_SAFE_MDL *SafeMdl = FspIopRequestContext(Request, RequestSafeMdl);
 | 
			
		||||
    if (FspFsvolDeviceReadShouldUseProcessBuffer(
 | 
			
		||||
        IrpSp->DeviceObject, Request->Req.Read.Length))
 | 
			
		||||
    {
 | 
			
		||||
        PVOID Address = FspIopRequestContext(Request, RequestAddress);
 | 
			
		||||
        PVOID SystemAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
 | 
			
		||||
 | 
			
		||||
        ASSERT(0 != Address);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            RtlCopyMemory(SystemAddress, Address, Response->IoStatus.Information);
 | 
			
		||||
        }
 | 
			
		||||
        except (EXCEPTION_EXECUTE_HANDLER)
 | 
			
		||||
        {
 | 
			
		||||
            Result = GetExceptionCode();
 | 
			
		||||
            Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
 | 
			
		||||
            FSP_RETURN();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        FSP_SAFE_MDL *SafeMdl = FspIopRequestContext(Request, RequestSafeMdl);
 | 
			
		||||
 | 
			
		||||
        if (0 != SafeMdl)
 | 
			
		||||
            FspSafeMdlCopyBack(SafeMdl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PFILE_OBJECT FileObject = IrpSp->FileObject;
 | 
			
		||||
    LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
 | 
			
		||||
    BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
 | 
			
		||||
    BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
 | 
			
		||||
 | 
			
		||||
    if (0 != SafeMdl)
 | 
			
		||||
        FspSafeMdlCopyBack(SafeMdl);
 | 
			
		||||
 | 
			
		||||
    /* if we are top-level */
 | 
			
		||||
    if (0 == FspIrpTopFlags(Irp))
 | 
			
		||||
    {
 | 
			
		||||
@@ -442,29 +495,57 @@ static VOID FspFsvolReadNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    PIRP Irp = Context[RequestIrp];
 | 
			
		||||
    FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
 | 
			
		||||
    PVOID Address = Context[RequestAddress];
 | 
			
		||||
    PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != Address)
 | 
			
		||||
    if (0 != Irp && FspFsvolDeviceReadShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.Read.Length))
 | 
			
		||||
    {
 | 
			
		||||
        KAPC_STATE ApcState;
 | 
			
		||||
        BOOLEAN Attach;
 | 
			
		||||
        PVOID Cookie = Context[RequestCookie];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
        ASSERT(0 != Process);
 | 
			
		||||
        Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
        MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
        ObDereferenceObject(Process);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            FspProcessBufferRelease(Cookie, Address);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != SafeMdl)
 | 
			
		||||
        FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 != SafeMdl)
 | 
			
		||||
            FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != Irp)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										163
									
								
								src/sys/write.c
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								src/sys/write.c
									
									
									
									
									
								
							@@ -45,6 +45,7 @@ enum
 | 
			
		||||
{
 | 
			
		||||
    /* WriteNonCached */
 | 
			
		||||
    RequestIrp                          = 0,
 | 
			
		||||
    RequestCookie                       = 1,
 | 
			
		||||
    RequestSafeMdl                      = 1,
 | 
			
		||||
    RequestAddress                      = 2,
 | 
			
		||||
    RequestProcess                      = 3,
 | 
			
		||||
@@ -416,41 +417,87 @@ NTSTATUS FspFsvolWritePrepare(
 | 
			
		||||
{
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    NTSTATUS Result;
 | 
			
		||||
    FSP_SAFE_MDL *SafeMdl = 0;
 | 
			
		||||
    PVOID Address;
 | 
			
		||||
    PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
    /* create a "safe" MDL if necessary */
 | 
			
		||||
    if (!FspSafeMdlCheck(Irp->MdlAddress))
 | 
			
		||||
    if (FspFsvolDeviceWriteShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.Write.Length))
 | 
			
		||||
    {
 | 
			
		||||
        Result = FspSafeMdlCreate(Irp->MdlAddress, IoReadAccess, &SafeMdl);
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        PVOID Cookie;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
        PVOID SystemAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
 | 
			
		||||
 | 
			
		||||
        if (0 == SystemAddress)
 | 
			
		||||
            return STATUS_INSUFFICIENT_RESOURCES; /* something is seriously screwy! */
 | 
			
		||||
 | 
			
		||||
        Result = FspProcessBufferAcquire(Request->Req.Write.Length, &Cookie, &Address);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
            return Result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* map the MDL into user-mode */
 | 
			
		||||
    Result = FspMapLockedPagesInUserMode(
 | 
			
		||||
        0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, FspMvMdlMappingNoWrite);
 | 
			
		||||
    if (!NT_SUCCESS(Result))
 | 
			
		||||
        ASSERT(0 != Address);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            RtlCopyMemory(Address, SystemAddress, Request->Req.Write.Length);
 | 
			
		||||
        }
 | 
			
		||||
        except (EXCEPTION_EXECUTE_HANDLER)
 | 
			
		||||
        {
 | 
			
		||||
            Result = GetExceptionCode();
 | 
			
		||||
            Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
 | 
			
		||||
 | 
			
		||||
            FspProcessBufferRelease(Cookie, Address);
 | 
			
		||||
 | 
			
		||||
            return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* get a pointer to the current process so that we can release the buffer later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestCookie) = Cookie;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (0 != SafeMdl)
 | 
			
		||||
            FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
        NTSTATUS Result;
 | 
			
		||||
        FSP_SAFE_MDL *SafeMdl = 0;
 | 
			
		||||
        PVOID Address;
 | 
			
		||||
        PEPROCESS Process;
 | 
			
		||||
 | 
			
		||||
        return Result;
 | 
			
		||||
        /* create a "safe" MDL if necessary */
 | 
			
		||||
        if (!FspSafeMdlCheck(Irp->MdlAddress))
 | 
			
		||||
        {
 | 
			
		||||
            Result = FspSafeMdlCreate(Irp->MdlAddress, IoReadAccess, &SafeMdl);
 | 
			
		||||
            if (!NT_SUCCESS(Result))
 | 
			
		||||
                return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* map the MDL into user-mode */
 | 
			
		||||
        Result = FspMapLockedPagesInUserMode(
 | 
			
		||||
            0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, FspMvMdlMappingNoWrite);
 | 
			
		||||
        if (!NT_SUCCESS(Result))
 | 
			
		||||
        {
 | 
			
		||||
            if (0 != SafeMdl)
 | 
			
		||||
                FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
 | 
			
		||||
            return Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
        Process = PsGetCurrentProcess();
 | 
			
		||||
        ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
        Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
        FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
 | 
			
		||||
        FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
        FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
        return STATUS_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* get a pointer to the current process so that we can unmap the address later */
 | 
			
		||||
    Process = PsGetCurrentProcess();
 | 
			
		||||
    ObReferenceObject(Process);
 | 
			
		||||
 | 
			
		||||
    Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
 | 
			
		||||
 | 
			
		||||
    FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
 | 
			
		||||
    FspIopRequestContext(Request, RequestAddress) = Address;
 | 
			
		||||
    FspIopRequestContext(Request, RequestProcess) = Process;
 | 
			
		||||
 | 
			
		||||
    return STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NTSTATUS FspFsvolWriteComplete(
 | 
			
		||||
@@ -524,29 +571,57 @@ static VOID FspFsvolWriteNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
 | 
			
		||||
    PAGED_CODE();
 | 
			
		||||
 | 
			
		||||
    PIRP Irp = Context[RequestIrp];
 | 
			
		||||
    FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
 | 
			
		||||
    PVOID Address = Context[RequestAddress];
 | 
			
		||||
    PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != Address)
 | 
			
		||||
    if (0 != Irp && FspFsvolDeviceWriteShouldUseProcessBuffer(
 | 
			
		||||
        IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Request->Req.Write.Length))
 | 
			
		||||
    {
 | 
			
		||||
        KAPC_STATE ApcState;
 | 
			
		||||
        BOOLEAN Attach;
 | 
			
		||||
        PVOID Cookie = Context[RequestCookie];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
        ASSERT(0 != Process);
 | 
			
		||||
        Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
        MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
 | 
			
		||||
        if (Attach)
 | 
			
		||||
            KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
        ObDereferenceObject(Process);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            FspProcessBufferRelease(Cookie, Address);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
 | 
			
		||||
        PVOID Address = Context[RequestAddress];
 | 
			
		||||
        PEPROCESS Process = Context[RequestProcess];
 | 
			
		||||
 | 
			
		||||
    if (0 != SafeMdl)
 | 
			
		||||
        FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
        if (0 != Address)
 | 
			
		||||
        {
 | 
			
		||||
            KAPC_STATE ApcState;
 | 
			
		||||
            BOOLEAN Attach;
 | 
			
		||||
 | 
			
		||||
            ASSERT(0 != Process);
 | 
			
		||||
            Attach = Process != PsGetCurrentProcess();
 | 
			
		||||
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeStackAttachProcess(Process, &ApcState);
 | 
			
		||||
            MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
 | 
			
		||||
            if (Attach)
 | 
			
		||||
                KeUnstackDetachProcess(&ApcState);
 | 
			
		||||
 | 
			
		||||
            ObDereferenceObject(Process);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 != SafeMdl)
 | 
			
		||||
            FspSafeMdlDelete(SafeMdl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != Irp)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,9 +45,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
 | 
			
		||||
/*
 | 
			
		||||
 * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
 | 
			
		||||
 * a check for the Write buffer to ensure that it is read-only.
 | 
			
		||||
 *
 | 
			
		||||
 * Since ProcessBuffer support in the FSD, this is no longer a guarantee.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(NDEBUG)
 | 
			
		||||
#define DEBUG_BUFFER_CHECK
 | 
			
		||||
//#define DEBUG_BUFFER_CHECK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MEMFS_SECTOR_SIZE               512
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user