Guest User

swapBuffers.c

a guest
Mar 3rd, 2024
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 37.56 KB | None | 0 0
  1. /*++
  2.  
  3. Copyright (c) 1999 - 2002  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     SwapBuffers.c
  8.  
  9. Abstract:
  10.  
  11.     This is a sample filter which demonstrates proper access of data buffer
  12.     and a general guideline of how to swap buffers.
  13.     For now it only swaps buffers for:
  14.  
  15.     IRP_MJ_READ
  16.     IRP_MJ_WRITE
  17.     IRP_MJ_DIRECTORY_CONTROL
  18.  
  19.     By default this filter attaches to all volumes it is notified about.  It
  20.     does support having multiple instances on a given volume.
  21.  
  22. Environment:
  23.  
  24.     Kernel mode
  25.  
  26. --*/
  27.  
  28. #include <fltKernel.h>
  29. #include <dontuse.h>
  30. #include <suppress.h>
  31.  
  32. #pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")
  33.  
  34.  
  35. PFLT_FILTER gFilterHandle;
  36.  
  37. /*************************************************************************
  38.     Pool Tags
  39. *************************************************************************/
  40.  
  41. #define BUFFER_SWAP_TAG     'bdBS'
  42. #define CONTEXT_TAG         'xcBS'
  43. #define NAME_TAG            'mnBS'
  44. #define PRE_2_POST_TAG      'ppBS'
  45.  
  46. /*************************************************************************
  47.     Local structures
  48. *************************************************************************/
  49.  
  50. //
  51. //  This is a volume context, one of these are attached to each volume
  52. //  we monitor.  This is used to get a "DOS" name for debug display.
  53. //
  54.  
  55. typedef struct _VOLUME_CONTEXT {
  56.  
  57.     //
  58.     //  Holds the name to display
  59.     //
  60.  
  61.     UNICODE_STRING Name;
  62.  
  63.     //
  64.     //  Holds the sector size for this volume.
  65.     //
  66.  
  67.     ULONG SectorSize;
  68.  
  69. } VOLUME_CONTEXT, *PVOLUME_CONTEXT;
  70.  
  71. #define MIN_SECTOR_SIZE 0x200
  72.  
  73.  
  74. //
  75. //  This is a context structure that is used to pass state from our
  76. //  pre-operation callback to our post-operation callback.
  77. //
  78.  
  79. typedef struct _PRE_2_POST_CONTEXT {
  80.  
  81.     //
  82.     //  Pointer to our volume context structure.  We always get the context
  83.     //  in the preOperation path because you can not safely get it at DPC
  84.     //  level.  We then release it in the postOperation path.  It is safe
  85.     //  to release contexts at DPC level.
  86.     //
  87.  
  88.     PVOLUME_CONTEXT VolCtx;
  89.  
  90.     //
  91.     //  Since the post-operation parameters always receive the "original"
  92.     //  parameters passed to the operation, we need to pass our new destination
  93.     //  buffer to our post operation routine so we can free it.
  94.     //
  95.  
  96.     PVOID SwappedBuffer;
  97.     ULONG Length;
  98.  
  99. } PRE_2_POST_CONTEXT, *PPRE_2_POST_CONTEXT;
  100.  
  101. //
  102. //  This is a lookAside list used to allocate our pre-2-post structure.
  103. //
  104.  
  105. NPAGED_LOOKASIDE_LIST Pre2PostContextList;
  106.  
  107. /*************************************************************************
  108.     Prototypes
  109. *************************************************************************/
  110.  
  111. #pragma region CoreCodeHeaders
  112. NTSTATUS
  113. InstanceSetup(
  114.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  115.     _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
  116.     _In_ DEVICE_TYPE VolumeDeviceType,
  117.     _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
  118. );
  119.  
  120. VOID
  121. CleanupVolumeContext(
  122.     _In_ PFLT_CONTEXT Context,
  123.     _In_ FLT_CONTEXT_TYPE ContextType
  124. );
  125.  
  126. NTSTATUS
  127. InstanceQueryTeardown(
  128.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  129.     _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
  130. );
  131.  
  132. DRIVER_INITIALIZE DriverEntry;
  133. NTSTATUS
  134. DriverEntry(
  135.     _In_ PDRIVER_OBJECT DriverObject,
  136.     _In_ PUNICODE_STRING RegistryPath
  137. );
  138.  
  139. NTSTATUS
  140. FilterUnload(
  141.     _In_ FLT_FILTER_UNLOAD_FLAGS Flags
  142. );
  143. #pragma endregion
  144.  
  145. FLT_PREOP_CALLBACK_STATUS
  146. SwapPreReadBuffers(
  147.     _Inout_ PFLT_CALLBACK_DATA Data,
  148.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  149.     _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
  150.     );
  151.  
  152. FLT_POSTOP_CALLBACK_STATUS
  153. SwapPostReadBuffers(
  154.     _Inout_ PFLT_CALLBACK_DATA Data,
  155.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  156.     _In_ PVOID CompletionContext,
  157.     _In_ FLT_POST_OPERATION_FLAGS Flags
  158.     );
  159.  
  160. FLT_POSTOP_CALLBACK_STATUS
  161. SwapPostReadBuffersWhenSafe (
  162.     _Inout_ PFLT_CALLBACK_DATA Data,
  163.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  164.     _In_ PVOID CompletionContext,
  165.     _In_ FLT_POST_OPERATION_FLAGS Flags
  166.     );
  167.  
  168. FLT_PREOP_CALLBACK_STATUS
  169. SwapPreQueryInformation(
  170.     _Inout_ PFLT_CALLBACK_DATA Data,
  171.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  172.     _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
  173. );
  174.  
  175. FLT_POSTOP_CALLBACK_STATUS
  176. SwapPostQueryInformation(
  177.     _Inout_ PFLT_CALLBACK_DATA Data,
  178.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  179.     _In_ PVOID CompletionContext,
  180.     _In_ FLT_POST_OPERATION_FLAGS Flags
  181. );
  182.  
  183. VOID
  184. ReadDriverParameters (
  185.     _In_ PUNICODE_STRING RegistryPath
  186.     );
  187.  
  188. //
  189. //  Assign text sections for each routine.
  190. //
  191.  
  192. #ifdef ALLOC_PRAGMA
  193. #pragma alloc_text(PAGE, InstanceSetup)
  194. #pragma alloc_text(PAGE, CleanupVolumeContext)
  195. #pragma alloc_text(PAGE, InstanceQueryTeardown)
  196. #pragma alloc_text(INIT, DriverEntry)
  197. #pragma alloc_text(INIT, ReadDriverParameters)
  198. #pragma alloc_text(PAGE, FilterUnload)
  199. #endif
  200.  
  201. //
  202. //  Operation we currently care about.
  203. //
  204.  
  205. CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
  206.     { IRP_MJ_READ,
  207.       0,
  208.       SwapPreReadBuffers,
  209.       SwapPostReadBuffers },
  210.  
  211.     { IRP_MJ_OPERATION_END }
  212. };
  213.  
  214. //
  215. //  Context definitions we currently care about.  Note that the system will
  216. //  create a lookAside list for the volume context because an explicit size
  217. //  of the context is specified.
  218. //
  219.  
  220. CONST FLT_CONTEXT_REGISTRATION ContextNotifications[] = {
  221.  
  222.      { FLT_VOLUME_CONTEXT,
  223.        0,
  224.        CleanupVolumeContext,
  225.        sizeof(VOLUME_CONTEXT),
  226.        CONTEXT_TAG },
  227.  
  228.      { FLT_CONTEXT_END }
  229. };
  230.  
  231. //
  232. //  This defines what we want to filter with FltMgr
  233. //
  234.  
  235. CONST FLT_REGISTRATION FilterRegistration = {
  236.  
  237.     sizeof( FLT_REGISTRATION ),         //  Size
  238.     FLT_REGISTRATION_VERSION,           //  Version
  239.     0,                                  //  Flags
  240.  
  241.     ContextNotifications,               //  Context
  242.     Callbacks,                          //  Operation callbacks
  243.  
  244.     FilterUnload,                       //  MiniFilterUnload
  245.  
  246.     InstanceSetup,                      //  InstanceSetup
  247.     InstanceQueryTeardown,              //  InstanceQueryTeardown
  248.     NULL,                               //  InstanceTeardownStart
  249.     NULL,                               //  InstanceTeardownComplete
  250.  
  251.     NULL,                               //  GenerateFileName
  252.     NULL,                               //  GenerateDestinationFileName
  253.     NULL                                //  NormalizeNameComponent
  254.  
  255. };
  256.  
  257. /*************************************************************************
  258.     Debug tracing information
  259. *************************************************************************/
  260.  
  261. //
  262. //  Definitions to display log messages.  The registry DWORD entry:
  263. //  "hklm\system\CurrentControlSet\Services\Swapbuffers\DebugFlags" defines
  264. //  the default state of these logging flags
  265. //
  266.  
  267. #define LOGFL_ERRORS    0x00000001  // if set, display error messages
  268. #define LOGFL_READ      0x00000002  // if set, display READ operation info
  269. #define LOGFL_WRITE     0x00000004  // if set, display WRITE operation info
  270. #define LOGFL_DIRCTRL   0x00000008  // if set, display DIRCTRL operation info
  271. #define LOGFL_VOLCTX    0x00000010  // if set, display VOLCTX operation info
  272.  
  273. ULONG LoggingFlags = 0;             // all disabled by default
  274.  
  275. #define LOG_PRINT( _logFlag, _string )                              \
  276.     (FlagOn(LoggingFlags,(_logFlag)) ?                              \
  277.         DbgPrint _string  :                                         \
  278.         ((int)0))
  279.  
  280. //////////////////////////////////////////////////////////////////////////////
  281. //////////////////////////////////////////////////////////////////////////////
  282. //
  283. //                      Routines
  284. //
  285. //////////////////////////////////////////////////////////////////////////////
  286. //////////////////////////////////////////////////////////////////////////////
  287.  
  288.  
  289. #pragma region CoreCode
  290. NTSTATUS
  291. InstanceSetup(
  292.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  293.     _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
  294.     _In_ DEVICE_TYPE VolumeDeviceType,
  295.     _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
  296. )
  297. /*++
  298.  
  299. Routine Description:
  300.  
  301.     This routine is called whenever a new instance is created on a volume.
  302.  
  303.     By default we want to attach to all volumes.  This routine will try and
  304.     get a "DOS" name for the given volume.  If it can't, it will try and
  305.     get the "NT" name for the volume (which is what happens on network
  306.     volumes).  If a name is retrieved a volume context will be created with
  307.     that name.
  308.  
  309. Arguments:
  310.  
  311.     FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
  312.         opaque handles to this filter, instance and its associated volume.
  313.  
  314.     Flags - Flags describing the reason for this attach request.
  315.  
  316. Return Value:
  317.  
  318.     STATUS_SUCCESS - attach
  319.     STATUS_FLT_DO_NOT_ATTACH - do not attach
  320.  
  321. --*/
  322. {
  323.     PDEVICE_OBJECT devObj = NULL;
  324.     PVOLUME_CONTEXT ctx = NULL;
  325.     NTSTATUS status = STATUS_SUCCESS;
  326.     ULONG retLen;
  327.     PUNICODE_STRING workingName;
  328.     USHORT size;
  329.     UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES) + 512];
  330.     PFLT_VOLUME_PROPERTIES volProp = (PFLT_VOLUME_PROPERTIES)volPropBuffer;
  331.  
  332.     PAGED_CODE();
  333.  
  334.     UNREFERENCED_PARAMETER(Flags);
  335.     UNREFERENCED_PARAMETER(VolumeDeviceType);
  336.     UNREFERENCED_PARAMETER(VolumeFilesystemType);
  337.  
  338.     try {
  339.  
  340.         //
  341.         //  Allocate a volume context structure.
  342.         //
  343.  
  344.         status = FltAllocateContext(FltObjects->Filter,
  345.             FLT_VOLUME_CONTEXT,
  346.             sizeof(VOLUME_CONTEXT),
  347.             NonPagedPool,
  348.             &ctx);
  349.  
  350.         if (!NT_SUCCESS(status)) {
  351.  
  352.             //
  353.             //  We could not allocate a context, quit now
  354.             //
  355.  
  356.             leave;
  357.         }
  358.  
  359.         //
  360.         //  Always get the volume properties, so I can get a sector size
  361.         //
  362.  
  363.         status = FltGetVolumeProperties(FltObjects->Volume,
  364.             volProp,
  365.             sizeof(volPropBuffer),
  366.             &retLen);
  367.  
  368.         if (!NT_SUCCESS(status)) {
  369.  
  370.             leave;
  371.         }
  372.  
  373.         //
  374.         //  Save the sector size in the context for later use.  Note that
  375.         //  we will pick a minimum sector size if a sector size is not
  376.         //  specified.
  377.         //
  378.  
  379.         FLT_ASSERT((volProp->SectorSize == 0) || (volProp->SectorSize >= MIN_SECTOR_SIZE));
  380.  
  381.         ctx->SectorSize = max(volProp->SectorSize, MIN_SECTOR_SIZE);
  382.  
  383.         //
  384.         //  Init the buffer field (which may be allocated later).
  385.         //
  386.  
  387.         ctx->Name.Buffer = NULL;
  388.  
  389.         //
  390.         //  Get the storage device object we want a name for.
  391.         //
  392.  
  393.         status = FltGetDiskDeviceObject(FltObjects->Volume, &devObj);
  394.  
  395.         if (NT_SUCCESS(status)) {
  396.  
  397.             //
  398.             //  Try and get the DOS name.  If it succeeds we will have
  399.             //  an allocated name buffer.  If not, it will be NULL
  400.             //
  401.  
  402.             status = IoVolumeDeviceToDosName(devObj, &ctx->Name);
  403.         }
  404.  
  405.         //
  406.         //  If we could not get a DOS name, get the NT name.
  407.         //
  408.  
  409.         if (!NT_SUCCESS(status)) {
  410.  
  411.             FLT_ASSERT(ctx->Name.Buffer == NULL);
  412.  
  413.             //
  414.             //  Figure out which name to use from the properties
  415.             //
  416.  
  417.             if (volProp->RealDeviceName.Length > 0) {
  418.  
  419.                 workingName = &volProp->RealDeviceName;
  420.  
  421.             }
  422.             else if (volProp->FileSystemDeviceName.Length > 0) {
  423.  
  424.                 workingName = &volProp->FileSystemDeviceName;
  425.  
  426.             }
  427.             else {
  428.  
  429.                 //
  430.                 //  No name, don't save the context
  431.                 //
  432.  
  433.                 status = STATUS_FLT_DO_NOT_ATTACH;
  434.                 leave;
  435.             }
  436.  
  437.             //
  438.             //  Get size of buffer to allocate.  This is the length of the
  439.             //  string plus room for a trailing colon.
  440.             //
  441.  
  442.             size = workingName->Length + sizeof(WCHAR);
  443.  
  444.             //
  445.             //  Now allocate a buffer to hold this name
  446.             //
  447.  
  448. #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "ctx->Name.Buffer will not be leaked because it is freed in CleanupVolumeContext")
  449.             ctx->Name.Buffer = ExAllocatePoolZero(NonPagedPool,
  450.                 size,
  451.                 NAME_TAG);
  452.             if (ctx->Name.Buffer == NULL) {
  453.  
  454.                 status = STATUS_INSUFFICIENT_RESOURCES;
  455.                 leave;
  456.             }
  457.  
  458.             //
  459.             //  Init the rest of the fields
  460.             //
  461.  
  462.             ctx->Name.Length = 0;
  463.             ctx->Name.MaximumLength = size;
  464.  
  465.             //
  466.             //  Copy the name in
  467.             //
  468.  
  469.             RtlCopyUnicodeString(&ctx->Name,
  470.                 workingName);
  471.  
  472.             //
  473.             //  Put a trailing colon to make the display look good
  474.             //
  475.  
  476.             RtlAppendUnicodeToString(&ctx->Name,
  477.                 L":");
  478.         }
  479.  
  480.         //
  481.         //  Set the context
  482.         //
  483.  
  484.         status = FltSetVolumeContext(FltObjects->Volume,
  485.             FLT_SET_CONTEXT_KEEP_IF_EXISTS,
  486.             ctx,
  487.             NULL);
  488.  
  489.         //
  490.         //  Log debug info
  491.         //
  492.  
  493.         LOG_PRINT(LOGFL_VOLCTX,
  494.             ("SwapBuffers!InstanceSetup:                  Real SectSize=0x%04x, Used SectSize=0x%04x, Name=\"%wZ\"\n",
  495.                 volProp->SectorSize,
  496.                 ctx->SectorSize,
  497.                 &ctx->Name));
  498.  
  499.         //
  500.         //  It is OK for the context to already be defined.
  501.         //
  502.  
  503.         if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
  504.  
  505.             status = STATUS_SUCCESS;
  506.         }
  507.  
  508.     }
  509.     finally {
  510.  
  511.         //
  512.         //  Always release the context.  If the set failed, it will free the
  513.         //  context.  If not, it will remove the reference added by the set.
  514.         //  Note that the name buffer in the ctx will get freed by the context
  515.         //  cleanup routine.
  516.         //
  517.  
  518.         if (ctx) {
  519.  
  520.             FltReleaseContext(ctx);
  521.         }
  522.  
  523.         //
  524.         //  Remove the reference added to the device object by
  525.         //  FltGetDiskDeviceObject.
  526.         //
  527.  
  528.         if (devObj) {
  529.  
  530.             ObDereferenceObject(devObj);
  531.         }
  532.     }
  533.  
  534.     return status;
  535. }
  536.  
  537.  
  538. VOID
  539. CleanupVolumeContext(
  540.     _In_ PFLT_CONTEXT Context,
  541.     _In_ FLT_CONTEXT_TYPE ContextType
  542. )
  543. /*++
  544.  
  545. Routine Description:
  546.  
  547.     The given context is being freed.
  548.     Free the allocated name buffer if there one.
  549.  
  550. Arguments:
  551.  
  552.     Context - The context being freed
  553.  
  554.     ContextType - The type of context this is
  555.  
  556. Return Value:
  557.  
  558.     None
  559.  
  560. --*/
  561. {
  562.     PVOLUME_CONTEXT ctx = Context;
  563.  
  564.     PAGED_CODE();
  565.  
  566.     UNREFERENCED_PARAMETER(ContextType);
  567.  
  568.     FLT_ASSERT(ContextType == FLT_VOLUME_CONTEXT);
  569.  
  570.     if (ctx->Name.Buffer != NULL) {
  571.  
  572.         ExFreePool(ctx->Name.Buffer);
  573.         ctx->Name.Buffer = NULL;
  574.     }
  575. }
  576.  
  577.  
  578. NTSTATUS
  579. InstanceQueryTeardown(
  580.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  581.     _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
  582. )
  583. /*++
  584.  
  585. Routine Description:
  586.  
  587.     This is called when an instance is being manually deleted by a
  588.     call to FltDetachVolume or FilterDetach.  We always return it is OK to
  589.     detach.
  590.  
  591. Arguments:
  592.  
  593.     FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
  594.         opaque handles to this filter, instance and its associated volume.
  595.  
  596.     Flags - Indicating where this detach request came from.
  597.  
  598. Return Value:
  599.  
  600.     Always succeed.
  601.  
  602. --*/
  603. {
  604.     PAGED_CODE();
  605.  
  606.     UNREFERENCED_PARAMETER(FltObjects);
  607.     UNREFERENCED_PARAMETER(Flags);
  608.  
  609.     return STATUS_SUCCESS;
  610. }
  611.  
  612.  
  613. /*************************************************************************
  614.     Initialization and unload routines.
  615. *************************************************************************/
  616.  
  617. NTSTATUS
  618. DriverEntry(
  619.     _In_ PDRIVER_OBJECT DriverObject,
  620.     _In_ PUNICODE_STRING RegistryPath
  621. )
  622. /*++
  623.  
  624. Routine Description:
  625.  
  626.     This is the initialization routine.  This registers with FltMgr and
  627.     initializes all global data structures.
  628.  
  629. Arguments:
  630.  
  631.     DriverObject - Pointer to driver object created by the system to
  632.         represent this driver.
  633.  
  634.     RegistryPath - Unicode string identifying where the parameters for this
  635.         driver are located in the registry.
  636.  
  637. Return Value:
  638.  
  639.     Status of the operation
  640.  
  641. --*/
  642. {
  643.     NTSTATUS status;
  644.  
  645.     //
  646.     //  Default to NonPagedPoolNx for non paged pool allocations where supported.
  647.     //
  648.  
  649.     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
  650.  
  651.     //
  652.     //  Get debug trace flags
  653.     //
  654.  
  655.     ReadDriverParameters(RegistryPath);
  656.  
  657.     //
  658.     //  Init lookaside list used to allocate our context structure used to
  659.     //  pass information from out preOperation callback to our postOperation
  660.     //  callback.
  661.     //
  662.  
  663.     ExInitializeNPagedLookasideList(&Pre2PostContextList,
  664.         NULL,
  665.         NULL,
  666.         0,
  667.         sizeof(PRE_2_POST_CONTEXT),
  668.         PRE_2_POST_TAG,
  669.         0);
  670.  
  671.     //
  672.     //  Register with FltMgr
  673.     //
  674.  
  675.     status = FltRegisterFilter(DriverObject,
  676.         &FilterRegistration,
  677.         &gFilterHandle);
  678.  
  679.     if (!NT_SUCCESS(status)) {
  680.  
  681.         goto SwapDriverEntryExit;
  682.     }
  683.  
  684.     //
  685.     //  Start filtering i/o
  686.     //
  687.  
  688.     status = FltStartFiltering(gFilterHandle);
  689.  
  690.     if (!NT_SUCCESS(status)) {
  691.  
  692.         FltUnregisterFilter(gFilterHandle);
  693.         goto SwapDriverEntryExit;
  694.     }
  695.  
  696. SwapDriverEntryExit:
  697.  
  698.     if (!NT_SUCCESS(status)) {
  699.  
  700.         ExDeleteNPagedLookasideList(&Pre2PostContextList);
  701.     }
  702.  
  703.     return status;
  704. }
  705.  
  706.  
  707. NTSTATUS
  708. FilterUnload(
  709.     _In_ FLT_FILTER_UNLOAD_FLAGS Flags
  710. )
  711. /*++
  712.  
  713. Routine Description:
  714.  
  715.     Called when this mini-filter is about to be unloaded.  We unregister
  716.     from the FltMgr and then return it is OK to unload
  717.  
  718. Arguments:
  719.  
  720.     Flags - Indicating if this is a mandatory unload.
  721.  
  722. Return Value:
  723.  
  724.     Returns the final status of this operation.
  725.  
  726. --*/
  727. {
  728.     PAGED_CODE();
  729.  
  730.     UNREFERENCED_PARAMETER(Flags);
  731.  
  732.     //
  733.     //  Unregister from FLT mgr
  734.     //
  735.  
  736.     FltUnregisterFilter(gFilterHandle);
  737.  
  738.     //
  739.     //  Delete lookaside list
  740.     //
  741.  
  742.     ExDeleteNPagedLookasideList(&Pre2PostContextList);
  743.  
  744.     return STATUS_SUCCESS;
  745. }
  746. #pragma endregion
  747.  
  748.  
  749. /*************************************************************************
  750.     MiniFilter callback routines.
  751. *************************************************************************/
  752.  
  753. FLT_PREOP_CALLBACK_STATUS
  754. SwapPreReadBuffers(
  755.     _Inout_ PFLT_CALLBACK_DATA Data,
  756.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  757.     _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
  758.     )
  759. /*++
  760.  
  761. Routine Description:
  762.  
  763.     This routine demonstrates how to swap buffers for the READ operation.
  764.  
  765.     Note that it handles all errors by simply not doing the buffer swap.
  766.  
  767. Arguments:
  768.  
  769.     Data - Pointer to the filter callbackData that is passed to us.
  770.  
  771.     FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
  772.         opaque handles to this filter, instance, its associated volume and
  773.         file object.
  774.  
  775.     CompletionContext - Receives the context that will be passed to the
  776.         post-operation callback.
  777.  
  778. Return Value:
  779.  
  780.     FLT_PREOP_SUCCESS_WITH_CALLBACK - we want a postOpeation callback
  781.     FLT_PREOP_SUCCESS_NO_CALLBACK - we don't want a postOperation callback
  782.  
  783. --*/
  784. {
  785.     PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
  786.     FLT_PREOP_CALLBACK_STATUS retValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
  787.     PVOID newBuf = NULL;
  788.     PMDL newMdl = NULL;
  789.     PVOLUME_CONTEXT volCtx = NULL;
  790.     PPRE_2_POST_CONTEXT p2pCtx;
  791.     NTSTATUS status;
  792.     ULONG readLen = iopb->Parameters.Read.Length;
  793.  
  794.     PFLT_FILE_NAME_INFORMATION filenameInfo = NULL;
  795.  
  796.     try {
  797.         //
  798.         //  If they are trying to read ZERO bytes, then don't do anything and
  799.         //  we don't need a post-operation callback.
  800.         //
  801.  
  802.         if (readLen == 0) {
  803.  
  804.             leave;
  805.         }
  806.         if (Data->RequestorMode == KernelMode)
  807.             return FLT_PREOP_SUCCESS_NO_CALLBACK;
  808.  
  809.         status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT | FLT_FILE_NAME_DO_NOT_CACHE, &filenameInfo);
  810.  
  811.         int diff = wcsncmp(filenameInfo->Name.Buffer, L"\\Device\\HarddiskVolume3\\Users\\owner\\Desktop\\a.txt", wcslen(filenameInfo->Name.Buffer));
  812.         if (diff != 0) {
  813.             leave;
  814.         }
  815.  
  816.         //
  817.         //  Get our volume context so we can display our volume name in the
  818.         //  debug output.
  819.         //
  820.  
  821.         status = FltGetVolumeContext( FltObjects->Filter,
  822.                                       FltObjects->Volume,
  823.                                       &volCtx );
  824.  
  825.         if (!NT_SUCCESS(status)) {
  826.  
  827.             LOG_PRINT( LOGFL_ERRORS,
  828.                        ("SwapBuffers!SwapPreReadBuffers:             Error getting volume context, status=%x\n",
  829.                         status) );
  830.  
  831.             leave;
  832.         }
  833.  
  834.         //
  835.         //  If this is a non-cached I/O we need to round the length up to the
  836.         //  sector size for this device.  We must do this because the file
  837.         //  systems do this and we need to make sure our buffer is as big
  838.         //  as they are expecting.
  839.         //
  840.  
  841.         if (FlagOn(IRP_NOCACHE,iopb->IrpFlags)) {
  842.             //nocache = 1;
  843.             readLen = (ULONG)ROUND_TO_SIZE(readLen,volCtx->SectorSize);
  844.         }
  845.  
  846.         //
  847.         //  Allocate aligned nonPaged memory for the buffer we are swapping
  848.         //  to. This is really only necessary for noncached IO but we always
  849.         //  do it here for simplification. If we fail to get the memory, just
  850.         //  don't swap buffers on this operation.
  851.         //
  852.  
  853.         newBuf = FltAllocatePoolAlignedWithTag( FltObjects->Instance,
  854.                                                 NonPagedPool,
  855.                                                 (SIZE_T) readLen,
  856.                                                 BUFFER_SWAP_TAG );
  857.         if (newBuf == NULL) {
  858.  
  859.             LOG_PRINT( LOGFL_ERRORS,
  860.                        ("SwapBuffers!SwapPreReadBuffers:             %wZ Failed to allocate %d bytes of memory\n",
  861.                         &volCtx->Name,
  862.                         readLen) );
  863.  
  864.             leave;
  865.         }
  866.  
  867.         //
  868.         //  We only need to build a MDL for IRP operations.  We don't need to
  869.         //  do this for a FASTIO operation since the FASTIO interface has no
  870.         //  parameter for passing the MDL to the file system.
  871.         //
  872.  
  873.         if (FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_IRP_OPERATION)) {
  874.             //mdl = 1;
  875.  
  876.             //
  877.             //  Allocate a MDL for the new allocated memory.  If we fail
  878.             //  the MDL allocation then we won't swap buffer for this operation
  879.             //
  880.  
  881.             newMdl = IoAllocateMdl( newBuf,
  882.                                     readLen,
  883.                                     FALSE,
  884.                                     FALSE,
  885.                                     NULL );
  886.  
  887.             if (newMdl == NULL) {
  888.  
  889.                 LOG_PRINT( LOGFL_ERRORS,
  890.                            ("SwapBuffers!SwapPreReadBuffers:             %wZ Failed to allocate MDL\n",
  891.                             &volCtx->Name) );
  892.  
  893.                 leave;
  894.             }
  895.  
  896.             //
  897.             //  setup the MDL for the non-paged pool we just allocated
  898.             //
  899.  
  900.             MmBuildMdlForNonPagedPool( newMdl );
  901.         }
  902.  
  903.         //
  904.         //  We are ready to swap buffers, get a pre2Post context structure.
  905.         //  We need it to pass the volume context and the allocate memory
  906.         //  buffer to the post operation callback.
  907.         //
  908.  
  909.         p2pCtx = ExAllocateFromNPagedLookasideList( &Pre2PostContextList );
  910.  
  911.         if (p2pCtx == NULL) {
  912.  
  913.             LOG_PRINT( LOGFL_ERRORS,
  914.                        ("SwapBuffers!SwapPreReadBuffers:             %wZ Failed to allocate pre2Post context structure\n",
  915.                         &volCtx->Name) );
  916.  
  917.             leave;
  918.         }
  919.  
  920.         //
  921.         //  Log that we are swapping
  922.         //
  923.  
  924.         LOG_PRINT( LOGFL_READ,
  925.                    ("SwapBuffers!SwapPreReadBuffers:             %wZ newB=%p newMdl=%p oldB=%p oldMdl=%p len=%d\n",
  926.                     &volCtx->Name,
  927.                     newBuf,
  928.                     newMdl,
  929.                     iopb->Parameters.Read.ReadBuffer,
  930.                     iopb->Parameters.Read.MdlAddress,
  931.                     readLen) );
  932.  
  933.         //
  934.         //  Update the buffer pointers and MDL address, mark we have changed
  935.         //  something.
  936.         //
  937.  
  938.         iopb->Parameters.Read.ReadBuffer = newBuf;
  939.         iopb->Parameters.Read.MdlAddress = newMdl;
  940.  
  941.         FltSetCallbackDataDirty( Data );
  942.  
  943.         //
  944.         //  Pass state to our post-operation callback.
  945.         //
  946.  
  947.         p2pCtx->SwappedBuffer = newBuf;
  948.         p2pCtx->VolCtx = volCtx;
  949.         p2pCtx->Length = readLen;
  950.  
  951.         *CompletionContext = p2pCtx;
  952.  
  953.         //
  954.         //  Return we want a post-operation callback
  955.         //
  956.  
  957.         retValue = FLT_PREOP_SUCCESS_WITH_CALLBACK;
  958.  
  959.     } finally {
  960.  
  961.         //
  962.         //  If we don't want a post-operation callback, then cleanup state.
  963.         //
  964.  
  965.         if (retValue != FLT_PREOP_SUCCESS_WITH_CALLBACK) {
  966.  
  967.             if (newBuf != NULL) {
  968.  
  969.                 FltFreePoolAlignedWithTag( FltObjects->Instance,
  970.                                            newBuf,
  971.                                            BUFFER_SWAP_TAG );
  972.             }
  973.  
  974.             if (newMdl != NULL) {
  975.  
  976.                 IoFreeMdl( newMdl );
  977.             }
  978.  
  979.             if (volCtx != NULL) {
  980.  
  981.                 FltReleaseContext( volCtx );
  982.             }
  983.         }
  984.     }
  985.  
  986.     return retValue;
  987. }
  988.  
  989.  
  990. FLT_POSTOP_CALLBACK_STATUS
  991. SwapPostReadBuffers(
  992.     _Inout_ PFLT_CALLBACK_DATA Data,
  993.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  994.     _In_ PVOID CompletionContext,
  995.     _In_ FLT_POST_OPERATION_FLAGS Flags
  996.     )
  997. /*++
  998.  
  999. Routine Description:
  1000.  
  1001.     This routine does postRead buffer swap handling
  1002.  
  1003. Arguments:
  1004.  
  1005.     Data - Pointer to the filter callbackData that is passed to us.
  1006.  
  1007.     FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
  1008.         opaque handles to this filter, instance, its associated volume and
  1009.         file object.
  1010.  
  1011.     CompletionContext - The completion context set in the pre-operation routine.
  1012.  
  1013.     Flags - Denotes whether the completion is successful or is being drained.
  1014.  
  1015. Return Value:
  1016.  
  1017.     FLT_POSTOP_FINISHED_PROCESSING
  1018.     FLT_POSTOP_MORE_PROCESSING_REQUIRED
  1019.  
  1020. --*/
  1021. {
  1022.     PVOID origBuf;
  1023.     PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
  1024.     FLT_POSTOP_CALLBACK_STATUS retValue = FLT_POSTOP_FINISHED_PROCESSING;
  1025.     PPRE_2_POST_CONTEXT p2pCtx = CompletionContext;
  1026.     BOOLEAN cleanupAllocatedBuffer = TRUE;
  1027.  
  1028.     //
  1029.     //  This system won't draining an operation with swapped buffers, verify
  1030.     //  the draining flag is not set.
  1031.     //
  1032.  
  1033.     FLT_ASSERT(!FlagOn(Flags, FLTFL_POST_OPERATION_DRAINING));
  1034.  
  1035.     try {
  1036.  
  1037.         //
  1038.         //  If the operation failed or the count is zero, there is no data to
  1039.         //  copy so just return now.
  1040.         //
  1041.  
  1042.         if (!NT_SUCCESS(Data->IoStatus.Status) ||
  1043.             (Data->IoStatus.Information == 0)) {
  1044.  
  1045.             LOG_PRINT( LOGFL_READ,
  1046.                        ("SwapBuffers!SwapPostReadBuffers:            %wZ newB=%p No data read, status=%x, info=%Iu\n",
  1047.                         &p2pCtx->VolCtx->Name,
  1048.                         p2pCtx->SwappedBuffer,
  1049.                         Data->IoStatus.Status,
  1050.                         Data->IoStatus.Information) );
  1051.  
  1052.             leave;
  1053.         }
  1054.  
  1055.         //
  1056.         //  We need to copy the read data back into the users buffer.  Note
  1057.         //  that the parameters passed in are for the users original buffers
  1058.         //  not our swapped buffers.
  1059.         //
  1060.  
  1061.         if (iopb->Parameters.Read.MdlAddress != NULL) {
  1062.  
  1063.             //
  1064.             //  This should be a simple MDL. We don't expect chained MDLs
  1065.             //  this high up the stack
  1066.             //
  1067.  
  1068.             FLT_ASSERT( ((PMDL)iopb->Parameters.Read.MdlAddress)->Next == NULL);
  1069.  
  1070.             //
  1071.             //  Since there is a MDL defined for the original buffer, get a
  1072.             //  system address for it so we can copy the data back to it.
  1073.             //  We must do this because we don't know what thread context
  1074.             //  we are in.
  1075.             //
  1076.  
  1077.             origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.Read.MdlAddress,
  1078.                                                     NormalPagePriority | MdlMappingNoExecute );
  1079.  
  1080.             if (origBuf == NULL) {
  1081.  
  1082.                 LOG_PRINT( LOGFL_ERRORS,
  1083.                            ("SwapBuffers!SwapPostReadBuffers:            %wZ Failed to get system address for MDL: %p\n",
  1084.                             &p2pCtx->VolCtx->Name,
  1085.                             iopb->Parameters.Read.MdlAddress) );
  1086.  
  1087.                 //
  1088.                 //  If we failed to get a SYSTEM address, mark that the read
  1089.                 //  failed and return.
  1090.                 //
  1091.  
  1092.                 Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1093.                 Data->IoStatus.Information = 0;
  1094.                 leave;
  1095.             }
  1096.  
  1097.         } else if (FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_SYSTEM_BUFFER) ||
  1098.                    FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_FAST_IO_OPERATION)) {
  1099.  
  1100.             //
  1101.             //  If this is a system buffer, just use the given address because
  1102.             //      it is valid in all thread contexts.
  1103.             //  If this is a FASTIO operation, we can just use the
  1104.             //      buffer (inside a try/except) since we know we are in
  1105.             //      the correct thread context (you can't pend FASTIO's).
  1106.             //
  1107.  
  1108.             origBuf = iopb->Parameters.Read.ReadBuffer;
  1109.  
  1110.         } else {
  1111.  
  1112.             //
  1113.             //  They don't have a MDL and this is not a system buffer
  1114.             //  or a fastio so this is probably some arbitrary user
  1115.             //  buffer.  We can not do the processing at DPC level so
  1116.             //  try and get to a safe IRQL so we can do the processing.
  1117.             //
  1118.  
  1119.             if (FltDoCompletionProcessingWhenSafe( Data,
  1120.                                                    FltObjects,
  1121.                                                    CompletionContext,
  1122.                                                    Flags,
  1123.                                                    SwapPostReadBuffersWhenSafe,
  1124.                                                    &retValue )) {
  1125.  
  1126.                 //
  1127.                 //  This operation has been moved to a safe IRQL, the called
  1128.                 //  routine will do (or has done) the freeing so don't do it
  1129.                 //  in our routine.
  1130.                 //
  1131.  
  1132.                 cleanupAllocatedBuffer = FALSE;
  1133.  
  1134.             } else {
  1135.  
  1136.                 //
  1137.                 //  We are in a state where we can not get to a safe IRQL and
  1138.                 //  we do not have a MDL.  There is nothing we can do to safely
  1139.                 //  copy the data back to the users buffer, fail the operation
  1140.                 //  and return.  This shouldn't ever happen because in those
  1141.                 //  situations where it is not safe to post, we should have
  1142.                 //  a MDL.
  1143.                 //
  1144.  
  1145.                 LOG_PRINT( LOGFL_ERRORS,
  1146.                            ("SwapBuffers!SwapPostReadBuffers:            %wZ Unable to post to a safe IRQL\n",
  1147.                             &p2pCtx->VolCtx->Name) );
  1148.  
  1149.                 Data->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1150.                 Data->IoStatus.Information = 0;
  1151.             }
  1152.  
  1153.             leave;
  1154.         }
  1155.  
  1156.         //
  1157.         //  We either have a system buffer or this is a fastio operation
  1158.         //  so we are in the proper context.  Copy the data handling an
  1159.         //  exception.
  1160.         //
  1161.  
  1162.         DbgBreakPoint();
  1163.  
  1164.         try {
  1165.             char* str = "Hello World!\0";
  1166.             size_t strLen = strnlen(str, p2pCtx->Length);
  1167.             strncpy(p2pCtx->SwappedBuffer, str, strLen);
  1168.  
  1169.             RtlCopyMemory(origBuf,
  1170.                 p2pCtx->SwappedBuffer,
  1171.                 Data->IoStatus.Information);
  1172.  
  1173.             Data->IoStatus.Information = strLen;
  1174.             Data->IoStatus.Status = STATUS_SUCCESS;
  1175.  
  1176.         } except (EXCEPTION_EXECUTE_HANDLER) {
  1177.  
  1178.             //
  1179.             //  The copy failed, return an error, failing the operation.
  1180.             //
  1181.  
  1182.             Data->IoStatus.Status = GetExceptionCode();
  1183.             Data->IoStatus.Information = 0;
  1184.  
  1185.             LOG_PRINT( LOGFL_ERRORS,
  1186.                        ("SwapBuffers!SwapPostReadBuffers:            %wZ Invalid user buffer, oldB=%p, status=%x\n",
  1187.                         &p2pCtx->VolCtx->Name,
  1188.                         origBuf,
  1189.                         Data->IoStatus.Status) );
  1190.         }
  1191.  
  1192.     } finally {
  1193.  
  1194.         //
  1195.         //  If we are supposed to, cleanup the allocated memory and release
  1196.         //  the volume context.  The freeing of the MDL (if there is one) is
  1197.         //  handled by FltMgr.
  1198.         //
  1199.  
  1200.         if (cleanupAllocatedBuffer) {
  1201.  
  1202.             LOG_PRINT( LOGFL_READ,
  1203.                        ("SwapBuffers!SwapPostReadBuffers:            %wZ newB=%p info=%Iu Freeing\n",
  1204.                         &p2pCtx->VolCtx->Name,
  1205.                         p2pCtx->SwappedBuffer,
  1206.                         Data->IoStatus.Information) );
  1207.  
  1208.             FltFreePoolAlignedWithTag( FltObjects->Instance,
  1209.                                        p2pCtx->SwappedBuffer,
  1210.                                        BUFFER_SWAP_TAG );
  1211.  
  1212.             FltReleaseContext( p2pCtx->VolCtx );
  1213.  
  1214.             ExFreeToNPagedLookasideList( &Pre2PostContextList,
  1215.                                          p2pCtx );
  1216.         }
  1217.     }
  1218.  
  1219.     return retValue;
  1220. }
  1221.  
  1222.  
  1223. FLT_POSTOP_CALLBACK_STATUS
  1224. SwapPostReadBuffersWhenSafe (
  1225.     _Inout_ PFLT_CALLBACK_DATA Data,
  1226.     _In_ PCFLT_RELATED_OBJECTS FltObjects,
  1227.     _In_ PVOID CompletionContext,
  1228.     _In_ FLT_POST_OPERATION_FLAGS Flags
  1229.     )
  1230. /*++
  1231.  
  1232. Routine Description:
  1233.  
  1234.     We had an arbitrary users buffer without a MDL so we needed to get
  1235.     to a safe IRQL so we could lock it and then copy the data.
  1236.  
  1237. Arguments:
  1238.  
  1239.     Data - Pointer to the filter callbackData that is passed to us.
  1240.  
  1241.     FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
  1242.         opaque handles to this filter, instance, its associated volume and
  1243.         file object.
  1244.  
  1245.     CompletionContext - Contains state from our PreOperation callback
  1246.  
  1247.     Flags - Denotes whether the completion is successful or is being drained.
  1248.  
  1249. Return Value:
  1250.  
  1251.     FLT_POSTOP_FINISHED_PROCESSING - This is always returned.
  1252.  
  1253. --*/
  1254. {
  1255.     PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
  1256.     PPRE_2_POST_CONTEXT p2pCtx = CompletionContext;
  1257.     PVOID origBuf;
  1258.     NTSTATUS status;
  1259.  
  1260.     UNREFERENCED_PARAMETER( FltObjects );
  1261.     UNREFERENCED_PARAMETER( Flags );
  1262.     FLT_ASSERT(Data->IoStatus.Information != 0);
  1263.  
  1264.     DbgBreakPoint();
  1265.  
  1266.     //
  1267.     //  This is some sort of user buffer without a MDL, lock the user buffer
  1268.     //  so we can access it.  This will create a MDL for it.
  1269.     //
  1270.  
  1271.     status = FltLockUserBuffer( Data );
  1272.  
  1273.     if (!NT_SUCCESS(status)) {
  1274.  
  1275.         LOG_PRINT( LOGFL_ERRORS,
  1276.                    ("SwapBuffers!SwapPostReadBuffersWhenSafe:    %wZ Could not lock user buffer, oldB=%p, status=%x\n",
  1277.                     &p2pCtx->VolCtx->Name,
  1278.                     iopb->Parameters.Read.ReadBuffer,
  1279.                     status) );
  1280.  
  1281.         //
  1282.         //  If we can't lock the buffer, fail the operation
  1283.         //
  1284.  
  1285.         Data->IoStatus.Status = status;
  1286.         Data->IoStatus.Information = 0;
  1287.  
  1288.     } else {
  1289.  
  1290.         //
  1291.         //  Get a system address for this buffer.
  1292.         //
  1293.  
  1294.         origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.Read.MdlAddress,
  1295.                                                 NormalPagePriority | MdlMappingNoExecute );
  1296.  
  1297.         if (origBuf == NULL) {
  1298.  
  1299.             LOG_PRINT( LOGFL_ERRORS,
  1300.                        ("SwapBuffers!SwapPostReadBuffersWhenSafe:    %wZ Failed to get system address for MDL: %p\n",
  1301.                         &p2pCtx->VolCtx->Name,
  1302.                         iopb->Parameters.Read.MdlAddress) );
  1303.  
  1304.             //
  1305.             //  If we couldn't get a SYSTEM buffer address, fail the operation
  1306.             //
  1307.  
  1308.             Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1309.             Data->IoStatus.Information = 0;
  1310.  
  1311.         } else {
  1312.             //
  1313.             //  Copy the data back to the original buffer.  Note that we
  1314.             //  don't need a try/except because we will always have a system
  1315.             //  buffer address.
  1316.             //
  1317.  
  1318.             char* str = "Hello World!";
  1319.             size_t strLen = strnlen(str, p2pCtx->Length);
  1320.             strncpy(p2pCtx->SwappedBuffer, str, strLen);
  1321.  
  1322.             RtlCopyMemory( origBuf,
  1323.                            p2pCtx->SwappedBuffer,
  1324.                            Data->IoStatus.Information );
  1325.  
  1326.             Data->IoStatus.Information = strLen;
  1327.             Data->IoStatus.Status = STATUS_SUCCESS;
  1328.         }
  1329.     }
  1330.  
  1331.     //
  1332.     //  Free allocated memory and release the volume context
  1333.     //
  1334.  
  1335.     LOG_PRINT( LOGFL_READ,
  1336.                ("SwapBuffers!SwapPostReadBuffersWhenSafe:    %wZ newB=%p info=%Iu Freeing\n",
  1337.                 &p2pCtx->VolCtx->Name,
  1338.                 p2pCtx->SwappedBuffer,
  1339.                 Data->IoStatus.Information) );
  1340.  
  1341.     FltFreePoolAlignedWithTag( FltObjects->Instance,
  1342.                                p2pCtx->SwappedBuffer,
  1343.                                BUFFER_SWAP_TAG );
  1344.  
  1345.     FltReleaseContext( p2pCtx->VolCtx );
  1346.  
  1347.     ExFreeToNPagedLookasideList( &Pre2PostContextList,
  1348.                                  p2pCtx );
  1349.  
  1350.     return FLT_POSTOP_FINISHED_PROCESSING;
  1351. }
Add Comment
Please, Sign In to add comment