WDK Mini Filter Example
filter/avscan.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 2011 Microsoft Corporation
4 
5 Module Name:
6 
7  avscan.c
8 
9 Abstract:
10 
11  This is the main module of the avscan mini-filter driver.
12  This filter demonstrates how to implement a transaction-aware
13  anti-virus filter.
14 
15  Av prefix denotes "Anti-virus" module.
16 
17 Environment:
18 
19  Kernel mode
20 
21 --*/
22 
23 #include <initguid.h>
24 #include "avscan.h"
25 
26 /*************************************************************************
27  Local Function Prototypes
28 *************************************************************************/
29 
30 DRIVER_INITIALIZE DriverEntry;
31 NTSTATUS
33  _In_ PDRIVER_OBJECT DriverObject,
34  _In_ PUNICODE_STRING RegistryPath
35  );
36 
37 NTSTATUS
39  _In_ PUNICODE_STRING RegistryPath
40  );
41 
42 NTSTATUS
44  _In_ PCFLT_RELATED_OBJECTS FltObjects,
45  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
46  _In_ DEVICE_TYPE VolumeDeviceType,
47  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
48  );
49 
50 VOID
52  _In_ PCFLT_RELATED_OBJECTS FltObjects,
53  _Unreferenced_parameter_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
54  );
55 
56 VOID
58  _In_ PCFLT_RELATED_OBJECTS FltObjects,
59  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
60  );
61 
62 NTSTATUS
63 AvUnload (
64  _Unreferenced_parameter_ FLT_FILTER_UNLOAD_FLAGS Flags
65  );
66 
67 NTSTATUS
69  _In_ PCFLT_RELATED_OBJECTS FltObjects,
70  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
71  );
72 
73 FLT_PREOP_CALLBACK_STATUS
75  _Inout_ PFLT_CALLBACK_DATA Data,
76  _In_ PCFLT_RELATED_OBJECTS FltObjects,
77  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
78  );
79 
80 FLT_PREOP_CALLBACK_STATUS
82  _Inout_ PFLT_CALLBACK_DATA Data,
83  _In_ PCFLT_RELATED_OBJECTS FltObjects,
84  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
85  );
86 
87 FLT_POSTOP_CALLBACK_STATUS
89  _Inout_ PFLT_CALLBACK_DATA Data,
90  _In_ PCFLT_RELATED_OBJECTS FltObjects,
91  _In_opt_ PVOID CompletionContext,
92  _In_ FLT_POST_OPERATION_FLAGS Flags
93  );
94 
95 FLT_PREOP_CALLBACK_STATUS
97  _Inout_ PFLT_CALLBACK_DATA Data,
98  _In_ PCFLT_RELATED_OBJECTS FltObjects,
99  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
100  );
101 
102 FLT_PREOP_CALLBACK_STATUS
104  _Inout_ PFLT_CALLBACK_DATA Data,
105  _In_ PCFLT_RELATED_OBJECTS FltObjects,
106  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
107  );
108 
109 NTSTATUS
111  _Unreferenced_parameter_ PCFLT_RELATED_OBJECTS FltObjects,
112  _In_ PFLT_CONTEXT TransactionContext,
113  _In_ ULONG TransactionNotification
114  );
115 
116 NTSTATUS
118  _Unreferenced_parameter_ PFLT_INSTANCE Instance,
119  _In_ PFLT_CONTEXT Context,
120  _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data
121  );
122 
123 //
124 // Local routines
125 //
126 
127 BOOLEAN
129  _In_ PFLT_CALLBACK_DATA Data
130  );
131 
132 NTSTATUS
134  _In_ PKTRANSACTION Transaction,
135  _Out_ PULONG TxOutcome
136  );
137 
138 NTSTATUS
140  _In_ PCFLT_RELATED_OBJECTS FltObjects,
141  _Inout_ PAV_STREAM_CONTEXT StreamContext
142  );
143 
144 NTSTATUS
146  _Inout_ PAV_TRANSACTION_CONTEXT TransactionContext,
147  _In_ ULONG TransactionOutcome
148  );
149 
150 NTSTATUS
152  _In_ PFLT_INSTANCE Instance,
153  _In_ PAV_FILE_REFERENCE FileId,
154  _Out_ LONG volatile* State,
155  _Out_ PLONGLONG VolumeRevision,
156  _Out_ PLONGLONG CacheRevision,
157  _Out_ PLONGLONG FileRevision
158  );
159 
160 NTSTATUS
161 AvSyncCache (
162  _In_ PFLT_INSTANCE Instance,
163  _In_ PAV_STREAM_CONTEXT StreamContext
164  );
165 
166 BOOLEAN
168  _In_ PFLT_FILTER Filter,
169  _In_ PFLT_CALLBACK_DATA Data
170  );
171 
172 BOOLEAN
174  _Inout_ PFLT_CALLBACK_DATA Data
175  );
176 
177 NTSTATUS
178 AvScan (
179  _Inout_ PFLT_CALLBACK_DATA Data,
180  _In_ PCFLT_RELATED_OBJECTS FltObjects,
181  _In_ AV_SCAN_MODE ScanMode,
182  _In_ UCHAR IOMajorFunctionAtScan,
183  _In_ BOOLEAN IsInTxWriter,
184  _Inout_ PAV_STREAM_CONTEXT StreamContext
185  );
186 
187 VOID
189  _In_ PAV_SCAN_CONTEXT ScanContext,
190  _In_ PAV_SECTION_CONTEXT SectionContext
191  );
192 
193 NTSTATUS
195  VOID
196  );
197 
198 //
199 // Assign text sections for each routine.
200 //
201 
202 #ifdef ALLOC_PRAGMA
203 #pragma alloc_text(INIT, DriverEntry)
204 #pragma alloc_text(INIT, AvSetConfiguration)
205 #pragma alloc_text(PAGE, AvUnload)
206 #pragma alloc_text(PAGE, AvInstanceQueryTeardown)
207 #pragma alloc_text(PAGE, AvInstanceSetup)
208 #pragma alloc_text(PAGE, AvInstanceTeardownStart)
209 #pragma alloc_text(PAGE, AvInstanceTeardownComplete)
210 #pragma alloc_text(PAGE, AvPreCreate)
211 #pragma alloc_text(PAGE, AvPostCreate)
212 #pragma alloc_text(PAGE, AvPreFsControl)
213 #pragma alloc_text(PAGE, AvPreCleanup)
214 #pragma alloc_text(PAGE, AvKtmNotificationCallback)
215 #pragma alloc_text(PAGE, AvScanAbortCallbackAsync)
216 #pragma alloc_text(PAGE, AvOperationsModifyingFile)
217 #pragma alloc_text(PAGE, AvQueryTransactionOutcome)
218 #pragma alloc_text(PAGE, AvProcessPreviousTransaction)
219 #pragma alloc_text(PAGE, AvProcessTransactionOutcome)
220 #pragma alloc_text(PAGE, AvLoadFileStateFromCache)
221 #pragma alloc_text(PAGE, AvSyncCache)
222 #pragma alloc_text(PAGE, AvIsPrefetchEcpPresent)
223 #pragma alloc_text(PAGE, AvIsStreamAlternate)
224 #pragma alloc_text(PAGE, AvScan)
225 #pragma alloc_text(PAGE, AvDoCancelScanAndRelease)
226 #pragma alloc_text(PAGE, AvSendAbortToUser)
227 #pragma alloc_text(PAGE, AvSendUnloadingToUser)
228 #endif
229 
230 //
231 // operation registration
232 //
233 
234 CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
235  { IRP_MJ_CREATE,
236  0,
237  AvPreCreate,
238  AvPostCreate },
239 
240  { IRP_MJ_CLEANUP,
241  0,
242  AvPreCleanup,
243  NULL },
244 
245  { IRP_MJ_WRITE,
246  0,
248  NULL },
249 
251  0,
253  NULL },
254 
256  0,
258  NULL },
259 
260  { IRP_MJ_OPERATION_END }
261 };
262 
263 //
264 // Context registraction construct defined in context.c
265 //
266 
267 extern const FLT_CONTEXT_REGISTRATION ContextRegistration[];
268 
269 //
270 // This defines what we want to filter with FltMgr
271 //
272 
273 CONST FLT_REGISTRATION FilterRegistration = {
274 
275  sizeof( FLT_REGISTRATION ), // Size
276  FLT_REGISTRATION_VERSION, // Version
277  0, // Flags
278 
279  ContextRegistration, // Context
280  Callbacks, // Operation callbacks
281 
282  AvUnload, // MiniFilterUnload
283 
284  AvInstanceSetup, // InstanceSetup
285  AvInstanceQueryTeardown, // InstanceQueryTeardown
286  AvInstanceTeardownStart, // InstanceTeardownStart
287  AvInstanceTeardownComplete, // InstanceTeardownComplete
288 
289  NULL, // GenerateFileName
290  NULL, // NormalizeNameComponentCallback
291  NULL, // NormalizeContextCleanupCallback
292  AvKtmNotificationCallback, // TransactionNotificationCallback
293  NULL, // NormalizeNameComponentExCallback
294  AvScanAbortCallbackAsync // SectionNotificationCallback
295 };
296 
297 
298 
299 NTSTATUS
301  _In_ PCFLT_RELATED_OBJECTS FltObjects,
302  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
303  _In_ DEVICE_TYPE VolumeDeviceType,
304  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
305  )
306 /*++
307 
308 Routine Description:
309 
310  This routine is called whenever a new instance is created on a volume. This
311  gives us a chance to decide if we need to attach to this volume or not.
312 
313  If this routine is not defined in the registration structure, automatic
314  instances are alwasys created.
315 
316 Arguments:
317 
318  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
319  opaque handles to this filter, instance and its associated volume.
320 
321  Flags - Flags describing the reason for this attach request.
322 
323 Return Value:
324 
325  STATUS_SUCCESS - attach
326  STATUS_FLT_DO_NOT_ATTACH - do not attach
327 
328 --*/
329 {
330  NTSTATUS status;
331  PAV_INSTANCE_CONTEXT instanceContext = NULL;
332  BOOLEAN isOnCsv = FALSE;
333 
334  UNREFERENCED_PARAMETER( Flags );
335 
336  PAGED_CODE();
337 
338  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
339  ("[AV] AvInstanceSetup: Entered\n") );
340 
341  //
342  // Don't attach to network volumes.
343  //
344 
345  if (VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {
346 
347  return STATUS_FLT_DO_NOT_ATTACH;
348  }
349 
350  //
351  // Determine if the filter is attaching to the hidden NTFS volume
352  // that corresponds to a CSV volume. If so do not attach. Note
353  // that it would be feasible for the filter to attach to this
354  // volume as part of a distrubuted filter implementation but that
355  // is beyond the scope of this sample.
356  //
357 
358  if (VolumeFilesystemType == FLT_FSTYPE_NTFS) {
359  isOnCsv = AvIsVolumeOnCsvDisk( FltObjects->Volume );
360  if (isOnCsv) {
361 
362  return STATUS_FLT_DO_NOT_ATTACH;
363  }
364  }
365 
366  status = FltAllocateContext( Globals.Filter,
367  FLT_INSTANCE_CONTEXT,
369  NonPagedPoolNx,
370  &instanceContext );
371 
372  if (!NT_SUCCESS( status )) {
373 
374  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
375  ("[AV] AvInstanceSetup: allocate instance context failed. status = 0x%x\n", status) );
376 
377  return STATUS_FLT_DO_NOT_ATTACH;
378  }
379 
380  //
381  // Setup instance context
382  //
383 
384  RtlZeroMemory(instanceContext, AV_INSTANCE_CONTEXT_SIZE);
385  instanceContext->Volume = FltObjects->Volume;
386  instanceContext->Instance = FltObjects->Instance;
387  instanceContext->VolumeFSType = VolumeFilesystemType;
388  instanceContext->IsOnCsvMDS = isOnCsv;
389 
390  //
391  // There will be a file state cache table for each NTFS volume instance.
392  // As for other file systems, file id is not unique, and thus we do
393  // not have cache for other kinds of file systems. Since the cache
394  // table is not mandatory to implement an anti-virus filter, we
395  // only have the volatile cache for NTFS, CSVFS and REFS.
396  //
397  // It is worth mentioning that the table is potentially very large.
398  // We use an AVL tree to improve insertion and query times. We do not
399  // set an upper bound for the size of the tree which is not optimal.
400  // Consider limiting the size of the tree for a production filter.
401  //
402 
403  if (FS_SUPPORTS_FILE_STATE_CACHE( VolumeFilesystemType )) {
404 
405  //
406  // Initialize file state cache in the instance context.
407  //
408 
409  ExInitializeResourceLite( &instanceContext->Resource );
410 
411  RtlInitializeGenericTable( &instanceContext->FileStateCacheTable,
415  NULL );
416  }
417 
418  status = FltSetInstanceContext( FltObjects->Instance,
419  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
420  instanceContext,
421  NULL );
422 
423  //
424  // In all cases, we need to release the instance context at this time.
425  // If we hit an error, it will get freed now.
426  //
427 
428  FltReleaseContext( instanceContext );
429 
430  if (!NT_SUCCESS( status )) {
431 
432  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
433  ("[AV] AvInstanceSetup: set instance context failed. status = 0x%x\n", status) );
434  return STATUS_FLT_DO_NOT_ATTACH;
435  }
436 
437  //
438  // Register this instance as a datascan filter. If this call
439  // fails the underlying filesystem does not support using
440  // the filter manager datascan API. Currently only the
441  // the namedpipe and mailslot file systems are unsupported.
442  //
443 
444  status = FltRegisterForDataScan( FltObjects->Instance );
445 
446  if (!NT_SUCCESS( status )) {
447 
448  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
449  ("[AV] AvInstanceSetup: FltRegisterForDataScan failed. status = 0x%x\n", status) );
450  return STATUS_FLT_DO_NOT_ATTACH;
451 
452  }
453 
454  return STATUS_SUCCESS;
455 }
456 
457 NTSTATUS
459  _In_ PCFLT_RELATED_OBJECTS FltObjects,
460  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
461  )
462 /*++
463 
464 Routine Description:
465 
466  This is called when an instance is being manually deleted by a
467  call to FltDetachVolume or FilterDetach thereby giving us a
468  chance to fail that detach request.
469 
470  If this routine is not defined in the registration structure, explicit
471  detach requests via FltDetachVolume or FilterDetach will always be
472  failed.
473 
474 Arguments:
475 
476  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
477  opaque handles to this filter, instance and its associated volume.
478 
479  Flags - Indicating where this detach request came from.
480 
481 Return Value:
482 
483  Returns the status of this operation.
484 
485 --*/
486 {
487  UNREFERENCED_PARAMETER( FltObjects );
488  UNREFERENCED_PARAMETER( Flags );
489 
490  PAGED_CODE();
491 
492  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
493  ("[AV] AvInstanceQueryTeardown: Entered\n") );
494 
495  return STATUS_SUCCESS;
496 }
497 
498 VOID
500  _In_ PCFLT_RELATED_OBJECTS FltObjects,
501  _Unreferenced_parameter_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
502  )
503 /*++
504 
505 Routine Description:
506 
507  This routine is called at the start of instance teardown.
508  If we have cache table, we have to clean up the table at this point.
509 
510 Arguments:
511 
512  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
513  opaque handles to this filter, instance and its associated volume.
514 
515  Flags - Reason why this instance is been deleted.
516 
517 Return Value:
518 
519  None.
520 
521 --*/
522 {
523  NTSTATUS status;
524  PLIST_ENTRY scan;
525  PLIST_ENTRY next;
526  PAV_SCAN_CONTEXT scanCtx = NULL;
527  PAV_INSTANCE_CONTEXT instanceContext = NULL;
528 
529  UNREFERENCED_PARAMETER( Flags );
530 
531  PAGED_CODE();
532 
533  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
534  ("[AV] AvInstanceTeardownStart: Entered\n") );
535 
536  status = FltGetInstanceContext( FltObjects->Instance,
537  &instanceContext );
538 
539  if (!NT_SUCCESS( status )) {
540 
541  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
542  ("[AV] AvInstanceTeardownStart: FltGetInstanceContext failed. status = 0x%x\n", status) );
543  return;
544  }
545 
546  //
547  // Search the scan context from the global list.
548  //
549 
550  AvAcquireResourceExclusive( &Globals.ScanCtxListLock );
551 
552  LIST_FOR_EACH_SAFE( scan, next, &Globals.ScanCtxListHead ) {
553 
554  scanCtx = CONTAINING_RECORD( scan, AV_SCAN_CONTEXT, List );
555 
556  if (scanCtx->FilterInstance != FltObjects->Instance) {
557 
558  continue;
559  }
560 
561  //
562  // Notify the user scan thread to abort the scan.
563  //
564  status = AvSendAbortToUser(scanCtx->ScanThreadId,
565  scanCtx->ScanId);
566 
567 
568  //
569  // If we fail to send message to the user, then we
570  // do the cancel and cleanup by ourself; otherwise,
571  // the listening thread will call back to cleanup and
572  // I/O request thred will tear down the scan context.
573  //
574 
575  if (!NT_SUCCESS( status ) || status == STATUS_TIMEOUT) {
576 
577  AvFinalizeScanAndSection(scanCtx);
578  }
579  }
580 
581  AvReleaseResource( &Globals.ScanCtxListLock );
582 
583  //
584  // Clean up the cache table if the volume supports one.
585  //
586 
587  if (FS_SUPPORTS_FILE_STATE_CACHE( instanceContext->VolumeFSType )) {
589  AvAcquireResourceExclusive( &instanceContext->Resource );
590 
591  while (!RtlIsGenericTableEmpty( &instanceContext->FileStateCacheTable ) ) {
592  entry = RtlGetElementGenericTable(&instanceContext->FileStateCacheTable, 0);
593  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
594  ("[AV] AvInstanceTeardownStart: %I64x,%I64x requesting deletion, state:%d\n",
595  entry->FileId.FileId64.UpperZeroes,
596  entry->FileId.FileId64.Value,
597  entry->InfectedState) );
598  RtlDeleteElementGenericTable(&instanceContext->FileStateCacheTable, entry);
599  }
600 
601  AvReleaseResource( &instanceContext->Resource );
602  }
603 
604  FltReleaseContext( instanceContext );
605 
606  FltDeleteInstanceContext( FltObjects->Instance, NULL );
607 }
608 
609 VOID
611  _In_ PCFLT_RELATED_OBJECTS FltObjects,
612  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
613  )
614 /*++
615 
616 Routine Description:
617 
618  This routine is called at the end of instance teardown.
619 
620 Arguments:
621 
622  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
623  opaque handles to this filter, instance and its associated volume.
624 
625  Flags - Reason why this instance is been deleted.
626 
627 Return Value:
628 
629  None.
630 
631 --*/
632 {
633  UNREFERENCED_PARAMETER( FltObjects );
634  UNREFERENCED_PARAMETER( Flags );
635 
636  PAGED_CODE();
637 
638  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
639  ("[AV] AvInstanceTeardownComplete: Entered\n") );
640 }
641 
642 
643 /*************************************************************************
644  MiniFilter initialization and unload routines.
645 *************************************************************************/
646 
647 NTSTATUS
649  _In_ PDRIVER_OBJECT DriverObject,
650  _In_ PUNICODE_STRING RegistryPath
651  )
652 /*++
653 
654 Routine Description:
655 
656  This is the initialization routine for this miniFilter driver. This
657  registers with FltMgr and initializes all global data structures.
658 
659 Arguments:
660 
661  DriverObject - Pointer to driver object created by the system to
662  represent this driver.
663 
664  RegistryPath - Unicode string identifying where the parameters for this
665  driver are located in the registry.
666 
667 Return Value:
668 
669  Returns the final status of this operation.
670 
671 --*/
672 {
673  NTSTATUS status = STATUS_SUCCESS;
674  PSECURITY_DESCRIPTOR sd = NULL;
675 
676  UNREFERENCED_PARAMETER( RegistryPath );
677 
678  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
679  ("[AV] DriverEntry: Entered\n") );
680 
681  //
682  // Set default global configuration
683  //
684 
685  RtlZeroMemory( &Globals, sizeof(Globals) );
686  InitializeListHead( &Globals.ScanCtxListHead );
687  ExInitializeResourceLite( &Globals.ScanCtxListLock );
688 
690  Globals.LocalScanTimeout = 30000;
691  Globals.NetworkScanTimeout = 60000;
692 
693 #if DBG
694 
695  Globals.DebugLevel = 0xffffffff; // AVDBG_TRACE_ERROR | AVDBG_TRACE_DEBUG;
696 
697 #endif
698 
699  try {
700 
701  //
702  // Set the filter configuration based on registry keys
703  //
704 
705  status = AvSetConfiguration( RegistryPath );
706 
707  if (!NT_SUCCESS( status )) {
708 
709  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
710  ("[AV]: DriverEntry: SetConfiguration FAILED. status = 0x%x\n", status) );
711 
712  leave;
713  }
714 
715  //
716  // Register with FltMgr to tell it our callback routines
717  //
718 
719  status = FltRegisterFilter( DriverObject,
721  &Globals.Filter );
722 
723  if (!NT_SUCCESS( status )) {
724 
725  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
726  ("[AV] DriverEntry: FltRegisterFilter FAILED. status = 0x%x\n", status) );
727  leave;
728  }
729 
730  //
731  // Builds a default security descriptor for use with FltCreateCommunicationPort.
732  //
733 
734  status = FltBuildDefaultSecurityDescriptor( &sd,
735  FLT_PORT_ALL_ACCESS );
736 
737 
738  if (!NT_SUCCESS( status )) {
739 
740  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
741  ("[AV] DriverEntry: FltBuildDefaultSecurityDescriptor FAILED. status = 0x%x\n", status) );
742  leave;
743  }
744  //
745  // Prepare ports between kernel and user.
746  //
747 
748  status = AvPrepareServerPort( sd, AvConnectForScan );
749 
750  if (!NT_SUCCESS( status )) {
751 
752  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
753  ("[AV] DriverEntry: AvPrepareServerPort Scan Port FAILED. status = 0x%x\n", status) );
754  leave;
755  }
756 
757  status = AvPrepareServerPort( sd, AvConnectForAbort );
758 
759  if (!NT_SUCCESS( status )) {
760 
761  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
762  ("[AV] DriverEntry: AvPrepareServerPort Abort Port FAILED. status = 0x%x\n", status) );
763  leave;
764  }
765 
766  status = AvPrepareServerPort( sd, AvConnectForQuery );
767 
768  if (!NT_SUCCESS( status )) {
769 
770  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
771  ("[AV] DriverEntry: AvPrepareServerPort Query Port FAILED. status = 0x%x\n", status) );
772  leave;
773  }
774 
775  //
776  // Start filtering i/o
777  //
778 
779  status = FltStartFiltering( Globals.Filter );
780 
781  if (!NT_SUCCESS( status )) {
782 
783  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
784  ("[AV] DriverEntry: FltStartFiltering FAILED. status = 0x%x\n", status) );
785  leave;
786  }
787 
788  } finally {
789 
790  if ( sd != NULL ) {
791 
792  FltFreeSecurityDescriptor( sd );
793  }
794 
795  if (!NT_SUCCESS( status ) ) {
796 
797  if (NULL != Globals.ScanServerPort) {
798 
799  FltCloseCommunicationPort( Globals.ScanServerPort );
800  }
801  if (NULL != Globals.AbortServerPort) {
802 
803  FltCloseCommunicationPort( Globals.AbortServerPort );
804  }
805  if (NULL != Globals.QueryServerPort) {
806 
807  FltCloseCommunicationPort( Globals.QueryServerPort );
808  }
809  if (NULL != Globals.Filter) {
810 
811  FltUnregisterFilter( Globals.Filter );
812  Globals.Filter = NULL;
813  }
814 
815  ExDeleteResourceLite( &Globals.ScanCtxListLock );
816  }
817  }
818 
819  return status;
820 }
821 
822 NTSTATUS
824  _Unreferenced_parameter_ FLT_FILTER_UNLOAD_FLAGS Flags
825  )
826 /*++
827 
828 Routine Description:
829 
830  This is the unload routine for this miniFilter driver. This is called
831  when the minifilter is about to be unloaded. We can fail this unload
832  request if this is not a mandatory unloaded indicated by the Flags
833  parameter.
834 
835 Arguments:
836 
837  Flags - Indicating if this is a mandatory unload.
838 
839 Return Value:
840 
841  Returns the final status of this operation.
842 
843 --*/
844 {
845  PAGED_CODE();
846 
847  UNREFERENCED_PARAMETER( Flags );
848 
849  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
850  ("[AV] AvUnload: Entered\n") );
851 
852  //
853  // Traverse the scan context list, and cancel the scan if it exists.
854  //
855 
856  AvAcquireResourceExclusive( &Globals.ScanCtxListLock );
858  AvReleaseResource( &Globals.ScanCtxListLock );
859 
860  //
861  // This function will wait for the user to abort the outstanding scan and
862  // close the section
863  //
864 
866 
867  FltCloseCommunicationPort( Globals.ScanServerPort );
869  FltCloseCommunicationPort( Globals.AbortServerPort );
871  FltCloseCommunicationPort( Globals.QueryServerPort );
873  FltUnregisterFilter( Globals.Filter ); // This will typically trigger instance tear down.
874  Globals.Filter = NULL;
875 
876  ExDeleteResourceLite( &Globals.ScanCtxListLock );
877 
878  return STATUS_SUCCESS;
879 }
880 
881 
882 /*************************************************************************
883  Local utility routines.
884 *************************************************************************/
885 
886 BOOLEAN
888  _In_ PFLT_CALLBACK_DATA Data
889  )
890 /*++
891 
892 Routine Description:
893 
894  This identifies those operations we need to set the file to be modified.
895 
896 Arguments:
897 
898  Data - Pointer to the filter callbackData that is passed to us.
899 
900 Return Value:
901 
902  TRUE - If we want the file associated with the request to be modified.
903  FALSE - If we don't
904 
905 --*/
906 {
907  PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
908 
909  PAGED_CODE();
910 
911  switch(iopb->MajorFunction) {
912 
913  case IRP_MJ_WRITE:
914  return TRUE;
915 
917  switch ( iopb->Parameters.FileSystemControl.Common.FsControlCode ) {
918  case FSCTL_OFFLOAD_WRITE:
919  case FSCTL_WRITE_RAW_ENCRYPTED:
920  case FSCTL_SET_ZERO_DATA:
921  return TRUE;
922  default: break;
923  }
924  break;
925 
927  switch ( iopb->Parameters.SetFileInformation.FileInformationClass ) {
928  case FileEndOfFileInformation:
929  case FileValidDataLengthInformation:
930  return TRUE;
931  default: break;
932  }
933  break;
934  default:
935  break;
936  }
937  return FALSE;
938 }
939 
940 NTSTATUS
942  _In_ PKTRANSACTION Transaction,
943  _Out_ PULONG TxOutcome
944  )
945 /*++
946 
947 Routine Description:
948 
949  This is a helper function that qeury the KTM that how trasnaction was ended.
950 
951 Arguments:
952 
953  Transaction - Pointer to transaction object.
954 
955  TxOutcome - Output. Specifies the type of transaction outcome.
956 
957 Return Value:
958 
959  The status of the operation
960 --*/
961 {
962  HANDLE transactionHandle;
963  NTSTATUS status;
964  TRANSACTION_BASIC_INFORMATION txBasicInfo = {0};
965 
966  PAGED_CODE();
967 
968  status = ObOpenObjectByPointer( Transaction,
969  OBJ_KERNEL_HANDLE,
970  NULL,
971  GENERIC_READ,
972  *TmTransactionObjectType,
973  KernelMode,
974  &transactionHandle );
975 
976  if (!NT_SUCCESS(status)) {
977 
978  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
979  ("[AV] AvQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") );
980  return status;
981  }
982 
983  status = ZwQueryInformationTransaction( transactionHandle,
984  TransactionBasicInformation,
985  &txBasicInfo,
986  sizeof(TRANSACTION_BASIC_INFORMATION),
987  NULL );
988  if (!NT_SUCCESS(status)) {
989 
990  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
991  ("[AV] AvQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") );
992  goto Cleanup;
993  }
994 
995  *TxOutcome = txBasicInfo.Outcome;
996 
997 Cleanup:
998 
999  ZwClose(transactionHandle);
1000 
1001  return status;
1002 }
1003 
1004 FORCEINLINE
1005 VOID
1007  _Inout_ PAV_STREAM_CONTEXT StreamContext,
1008  _In_ ULONG TransactionOutcome
1009  )
1010 /*++
1011 
1012 Routine Description:
1013 
1014  An inline function that propagate the TxState to State in stream context.
1015 
1016 Arguments:
1017 
1018  StreamContext - The stream context to be propagated.
1019 
1020  TransactionOutcome - TRANSACTION_OUTCOME enumeration indicating how transaction was ended.
1021 
1022 
1023 Return Value:
1024 
1025  None.
1026 
1027 --*/
1028 {
1029  //
1030  // Only when the transaction was committed will we propagate the state.
1031  //
1032 
1033  if (TransactionOutcome == TransactionOutcomeCommitted) {
1034 
1035  AV_FILE_INFECTED_STATE oldTxState = InterlockedExchange( &StreamContext->TxState, AvFileModified );
1036  switch (oldTxState) {
1037  case AvFileModified:
1038  case AvFileInfected:
1039  case AvFileNotInfected:
1040 
1041  //
1042  // Propagate the file state from TxState to State.
1043  //
1044 
1045  InterlockedExchange( &StreamContext->State, oldTxState );
1046  break;
1047  case AvFileScanning:
1048 
1049  //
1050  // It is possible at KTM callback, file Tx state is still in scanning.
1051  // All we can do here is to be conservative, that is to assume that
1052  // this commit did involve the modification of the file.
1053  //
1054 
1055  InterlockedExchange( &StreamContext->State, AvFileModified );
1056  break;
1057  default:
1058  FLT_ASSERTMSG("AvPropagateFileState does not handle the state", FALSE);
1059  break;
1060  }
1061  }
1062 
1063  //
1064  // Either cleanup or commited, we need to reset TxState to be default state.
1065  //
1066 
1067  SET_FILE_TX_MODIFIED( StreamContext );
1068 }
1069 
1070 NTSTATUS
1072  _Inout_ PAV_TRANSACTION_CONTEXT TransactionContext,
1073  _In_ ULONG TransactionOutcome
1074  )
1075 /*++
1076 
1077 Routine Description:
1078 
1079  This is a helper function that process transaction commitment or rollback
1080 
1081 Arguments:
1082 
1083  TransactionContext - Pointer to the minifilter driver's transaction context
1084  set at PostCreate.
1085 
1086  TransactionOutcome - Specifies the type of notifications. Should be either
1087  TransactionOutcomeCommitted or TransactionOutcomeAborted
1088 
1089 Return Value:
1090 
1091  STATUS_SUCCESS - Returning this status value indicates that the minifilter
1092  driver is finished with the transaction. This is a success code.
1093 
1094 --*/
1095 {
1096  PLIST_ENTRY scan;
1097  PLIST_ENTRY next;
1098  PAV_STREAM_CONTEXT streamContext = NULL;
1099  PAV_TRANSACTION_CONTEXT oldTxCtx = NULL;
1100 
1101  PAGED_CODE();
1102 
1103  //
1104  // Tranversing the stream context list, and
1105  // sync the TxState -> State.
1106  //
1107  // Either commit or rollback, we need to cleanup the list
1108  // Tear down stream context list inside transactionContext
1109  //
1110 
1111  AvAcquireResourceExclusive( TransactionContext->Resource );
1112 
1113  LIST_FOR_EACH_SAFE( scan, next, &TransactionContext->ScListHead ) {
1114 
1115  streamContext = CONTAINING_RECORD( scan, AV_STREAM_CONTEXT, ListInTransaction );
1116  oldTxCtx = InterlockedCompareExchangePointer( &streamContext->TxContext, NULL, TransactionContext );
1117  if (oldTxCtx == TransactionContext) {
1118 
1119  //
1120  // The exchange pointer was successful
1121  //
1122 
1123  RemoveEntryList ( scan );
1124 
1125  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
1126  ("[AV] AvProcessTransactionOutcome: Requesting deletion of entry in transaction context: %I64x,%I64x, modified: %d\n",
1127  streamContext->FileId.FileId64.UpperZeroes,
1128  streamContext->FileId.FileId64.Value,
1129  IS_FILE_MODIFIED( streamContext ) ) );
1130  AvPropagateFileState( streamContext, TransactionOutcome );
1131  FltReleaseContext( oldTxCtx );
1132  FltReleaseContext( streamContext );
1133  }
1134  }
1135  SetFlag( TransactionContext->Flags, AV_TXCTX_LISTDRAINED );
1136  AvReleaseResource( TransactionContext->Resource );
1137 
1138  return STATUS_SUCCESS;
1139 }
1140 
1141 NTSTATUS
1143  _In_ PFLT_INSTANCE Instance,
1144  _In_ PAV_FILE_REFERENCE FileId,
1145  _Out_ LONG volatile *State,
1146  _Out_ PLONGLONG VolumeRevision,
1147  _Out_ PLONGLONG CacheRevision,
1148  _Out_ PLONGLONG FileRevision
1149  )
1150 /*++
1151 
1152 Routine Description:
1153 
1154  This routine lookups the file state in the cache table.
1155 
1156 Arguments:
1157 
1158  Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL.
1159 
1160  FileID - The ID to lookup in the cache
1161 
1162  State - The cached state for the file
1163 
1164 Return Value:
1165 
1166  Returns the final status of this operation.
1167 
1168 --*/
1169 {
1170  NTSTATUS status = STATUS_SUCCESS;
1171  PAV_INSTANCE_CONTEXT instanceContext = NULL;
1172  AV_GENERIC_TABLE_ENTRY query = {0};
1173  PAV_GENERIC_TABLE_ENTRY entry = NULL;
1174 
1175  PAGED_CODE();
1176 
1177  //
1178  // We should never be trying to cache with an invalid fileID.
1179  //
1180 
1181  ASSERT( !AV_INVALID_FILE_REFERENCE(*FileId) );
1182 
1183  status = FltGetInstanceContext( Instance,
1184  &instanceContext );
1185 
1186  if (!NT_SUCCESS( status )){
1187  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1188  ("[AV] AvLoadFileStateFromCache: failed to get instance context.\n") );
1189  return status;
1190  }
1191 
1192  if (! FS_SUPPORTS_FILE_STATE_CACHE( instanceContext->VolumeFSType )) {
1193 
1194  status = STATUS_NOT_FOUND;
1195  goto Cleanup;
1196  }
1197 
1198  RtlCopyMemory( &query.FileId, FileId, sizeof(query.FileId) );
1199 
1200  AvAcquireResourceShared( &instanceContext->Resource );
1201 
1202  entry = RtlLookupElementGenericTable( &instanceContext->FileStateCacheTable,
1203  &query );
1204 
1205  if (entry != NULL) {
1206  *State = entry->InfectedState;
1207  *VolumeRevision = entry->VolumeRevision;
1208  *CacheRevision = entry->CacheRevision;
1209  *FileRevision = entry->FileRevision;
1210  } else {
1211  status = STATUS_NOT_FOUND;
1212  }
1213 
1214  AvReleaseResource( &instanceContext->Resource );
1215 
1216 Cleanup:
1217 
1218  FltReleaseContext( instanceContext );
1219  return status;
1220 }
1221 
1222 NTSTATUS
1224  _In_ PFLT_INSTANCE Instance,
1225  _In_ PAV_STREAM_CONTEXT StreamContext
1226  )
1227 /*++
1228 
1229 Routine Description:
1230 
1231  This routine sync the file state from stream context to volatile cache table.
1232  It is file system transparent.
1233 
1234 Arguments:
1235 
1236  Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL.
1237 
1238  StreamContext - The stream context of the target file.
1239 
1240 Return Value:
1241 
1242  Returns the final status of this operation.
1243 
1244 --*/
1245 {
1246  NTSTATUS status = STATUS_SUCCESS;
1247  BOOLEAN inserted = FALSE;
1248  AV_GENERIC_TABLE_ENTRY entry = {0};
1249  PAV_GENERIC_TABLE_ENTRY pEntry = NULL;
1250  PAV_INSTANCE_CONTEXT instanceContext = NULL;
1251 
1252  PAGED_CODE();
1253 
1254  if ((NULL == Instance) ||
1255  (NULL == StreamContext)) {
1256 
1257  return STATUS_INVALID_PARAMETER;
1258  }
1259 
1260  status = FltGetInstanceContext( Instance, &instanceContext );
1261 
1262  if (!NT_SUCCESS( status )){
1263  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1264  ("[AV] AvSyncCache: failed to get instance context.\n") );
1265  return status;
1266  }
1267 
1268  //
1269  // If the file system is not NTFS, CSVFS or REFS, do nothing
1270  //
1271 
1272  if (!FS_SUPPORTS_FILE_STATE_CACHE( instanceContext->VolumeFSType )) {
1273  goto Cleanup;
1274  }
1275 
1276  //
1277  // If originally, we failed to get the file id,
1278  // then we do not cache it.
1279  //
1280 
1281  if (AV_INVALID_FILE_REFERENCE( StreamContext->FileId )) {
1282  goto Cleanup;
1283  }
1284 
1285  //
1286  // If the file system is NTFS, CSVFS or REFS, overwrite the entry in the
1287  // cache table if exists
1288  //
1289 
1290  RtlCopyMemory( &entry.FileId, &StreamContext->FileId, sizeof(entry.FileId) );
1291 
1292  AvAcquireResourceExclusive( &instanceContext->Resource );
1293 
1294  pEntry = RtlInsertElementGenericTable( &instanceContext->FileStateCacheTable,
1295  (PVOID) &entry,
1297  &inserted);
1298  if (pEntry) {
1299 
1300  //
1301  // Note the cache may become stale as files are modified.
1302  //
1303 
1304  //
1305  // It is possible that after entering the following else-if
1306  // branch, thread A modifies the file, and before thread A
1307  // closes the handle, thread B opens the same file. This
1308  // is fine because in such a case, the streamcontext exists
1309  // AvLoadFileStateFromCache would return the state in stream
1310  // context. Thus, thread B will need to scan the file.
1311  //
1312 
1313  pEntry->InfectedState = StreamContext->State;
1314  pEntry->VolumeRevision = StreamContext->VolumeRevision;
1315  pEntry->CacheRevision = StreamContext->CacheRevision;
1316  pEntry->FileRevision = StreamContext->FileRevision;
1317 
1318  }
1319 
1320  AvReleaseResource( &instanceContext->Resource );
1321 
1322  if (!pEntry) {
1323  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1324  ("[AV] AvSyncCache: RtlInsertElementGenericTable failed.\n") );
1325  }
1326 
1327 Cleanup:
1328 
1329  FltReleaseContext( instanceContext );
1330  return status;
1331 }
1332 
1333 BOOLEAN
1335  _In_ PFLT_FILTER Filter,
1336  _In_ PFLT_CALLBACK_DATA Data
1337  )
1338 /*++
1339 
1340 Routine Description:
1341 
1342  This local function will return if this data stream is alternate or not.
1343  It by default returns FALSE if it fails to retrieve the name information
1344  from the file system.
1345 
1346 Arguments:
1347 
1348  Data - Pointer to the filter callbackData that is passed to us.
1349 
1350 Return Value:
1351 
1352  TRUE - This data stream is alternate.
1353  FALSE - This data stream is NOT alternate.
1354 
1355 --*/
1356 {
1357  NTSTATUS status;
1358  PECP_LIST ecpList;
1359  PVOID ecpContext;
1360 
1361  PAGED_CODE();
1362 
1363  status = FltGetEcpListFromCallbackData( Filter, Data, &ecpList );
1364 
1365  if (NT_SUCCESS(status) && (ecpList != NULL)) {
1366 
1367  status = FltFindExtraCreateParameter( Filter,
1368  ecpList,
1369  &GUID_ECP_PREFETCH_OPEN,
1370  &ecpContext,
1371  NULL );
1372 
1373  if (NT_SUCCESS(status)) {
1374 
1375  if (!FltIsEcpFromUserMode( Filter, ecpContext )) {
1376  return TRUE;
1377  }
1378  }
1379  }
1380 
1381  return FALSE;
1382 }
1383 
1384 BOOLEAN
1386  _Inout_ PFLT_CALLBACK_DATA Data
1387  )
1388 /*++
1389 
1390 Routine Description:
1391 
1392  This local function will return if this data stream is alternate or not.
1393  It by default returns FALSE if it fails to retrieve the name information
1394  from the file system.
1395 
1396 Arguments:
1397 
1398  Data - Pointer to the filter callbackData that is passed to us.
1399 
1400 Return Value:
1401 
1402  TRUE - This data stream is alternate.
1403  FALSE - This data stream is NOT alternate.
1404 
1405 --*/
1406 {
1407  NTSTATUS status;
1408  BOOLEAN alternate = FALSE;
1409  PFLT_FILE_NAME_INFORMATION nameInfo = NULL;
1410 
1411  PAGED_CODE();
1412 
1413  status = FltGetFileNameInformation( Data,
1414  FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP,
1415  &nameInfo );
1416 
1417  if (!NT_SUCCESS(status)) {
1418 
1419  goto Cleanup;
1420  }
1421 
1422  status = FltParseFileNameInformation( nameInfo );
1423 
1424  if (!NT_SUCCESS(status)) {
1425 
1426  goto Cleanup;
1427  }
1428 
1429  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1430  ("[Av]: Dir: %wZ, FinalComponent: %wZ, Stream: %wZ, sLen: %d\n",
1431  nameInfo->ParentDir,
1432  nameInfo->FinalComponent,
1433  nameInfo->Stream,
1434  nameInfo->Stream.Length) );
1435 
1436  alternate = (nameInfo->Stream.Length > 0);
1437 
1438 Cleanup:
1439  if (nameInfo != NULL) {
1440 
1441  FltReleaseFileNameInformation( nameInfo );
1442  nameInfo = NULL;
1443  }
1444  return alternate;
1445 }
1446 
1447 NTSTATUS
1449  _Inout_ PFLT_CALLBACK_DATA Data,
1450  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1451  _In_ AV_SCAN_MODE ScanMode,
1452  _In_ UCHAR IOMajorFunctionAtScan,
1453  _In_ BOOLEAN IsInTxWriter,
1454  _Inout_ PAV_STREAM_CONTEXT StreamContext
1455  )
1456 /*++
1457 
1458 Routine Description:
1459 
1460  This routine kicks of a scan.
1461 
1462 Arguments:
1463 
1464  Data - Pointer to the filter callbackData that is passed to us.
1465 
1466  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1467  opaque handles to this filter, instance, its associated volume and
1468  file object.
1469 
1470  ScanMode - Can either be AvUserMode or AvKernelMode.
1471 
1472  IOMajorFunctionAtScan - Major function of an IRP.
1473 
1474  StreamContext - The stream context of the target file.
1475 
1476 Return Value:
1477 
1478  Returns the final status of this operation.
1479  STATUS_TIMEOUT - if scan in user mode and the thread reference fails,
1480  then it would wait for the scan finish event with a timeout.
1481 
1482 --*/
1483 {
1484  NTSTATUS status = STATUS_SUCCESS;
1485  LONGLONG fileSize;
1486  FLT_VOLUME_PROPERTIES volumeProperties;
1487  ULONG volumePropertiesLength;
1488 
1489  PAGED_CODE();
1490 
1491  //
1492  // Skip the empty file.
1493  //
1494 
1495  status = AvGetFileSize( FltObjects->Instance,
1496  FltObjects->FileObject,
1497  &fileSize );
1498 
1499  if (NT_SUCCESS( status ) &&
1500  (0 == fileSize)) {
1501 
1502  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1503  ("[Av]: AvScan: Skip the EMPTY file.\n") );
1504 
1505  // As if we have 'scanned' this empty file.
1506  SET_FILE_NOT_INFECTED( StreamContext );
1507  return STATUS_SUCCESS;
1508  }
1509 
1510  //
1511  // We could cause deadlocks if the thread were suspended once
1512  // we have started scanning so enter a critical region.
1513  //
1514 
1515  FsRtlEnterFileSystem();
1516 
1517  //
1518  // Wait here for an existing scan on the stream to complete.
1519  // We wait indefinitely since scans themselves will timeout.
1520  //
1521 
1522  status = FltCancellableWaitForSingleObject( StreamContext->ScanSynchronizationEvent,
1523  NULL,
1524  Data );
1525 
1526  if (NT_SUCCESS(status)) {
1527 
1528  //
1529  // Check again in case the file was scanned during the wait
1530  // and is already known to be clean
1531  //
1532 
1533  if (IS_FILE_NEED_SCAN( StreamContext )){
1534 
1535  if (ScanMode == AvUserMode) {
1536 
1537  status = FltGetVolumeProperties( FltObjects->Volume,
1538  &volumeProperties,
1539  sizeof(volumeProperties),
1540  &volumePropertiesLength );
1541  if (!NT_SUCCESS(status)) {
1542  volumeProperties.DeviceType = FILE_DEVICE_NETWORK;
1543  }
1544 
1545  //
1546  // If the scan mode is user mode, the section context will
1547  // be created as needed (at MessageNotification callback).
1548  //
1549  // Setting the file state will be done at
1550  // MessageNotification callback as well.
1551  //
1552 
1553  status = AvScanInUser( Data,
1554  FltObjects,
1555  IOMajorFunctionAtScan,
1556  IsInTxWriter,
1557  volumeProperties.DeviceType );
1558 
1559  if (!NT_SUCCESS( status ) || status == STATUS_TIMEOUT) {
1560 
1561  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1562  ("[AV] AvScan: failed to scan the file.\n") );
1563  }
1564 
1565  } else {
1566 
1567  status = AvScanInKernel( FltObjects,
1568  IOMajorFunctionAtScan,
1569  IsInTxWriter,
1570  StreamContext );
1571 
1572  if (!NT_SUCCESS( status )) {
1573 
1574  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1575  ("[AV] AvScan: failed to scan the file.\n") );
1576  }
1577 
1578  }
1579 
1580  }
1581 
1582  //
1583  // Signal ScanSynchronizationEvent to release any con-current scan of the stream,
1584  //
1585  KeSetEvent( StreamContext->ScanSynchronizationEvent, 0, FALSE );
1586 
1587  } else if (IOMajorFunctionAtScan == IRP_MJ_CREATE) {
1588 
1589  //
1590  // I/O requesting thread if waiting on synchronization event is cancelled,
1591  // we need to clean up the file object too.
1592  //
1593  AvCancelFileOpen(Data, FltObjects, status);
1594  }
1595 
1596  FsRtlExitFileSystem();
1597 
1598  return status;
1599 }
1600 
1601 VOID
1603  _In_ PAV_SCAN_CONTEXT ScanContext,
1604  _In_ PAV_SECTION_CONTEXT SectionContext
1605  )
1606 /*++
1607 
1608 Routine Description:
1609 
1610  This routine closes the section object, and released all waiting threads.
1611 
1612 Arguments:
1613 
1614  ScanContext - The scan context.
1615 
1616  SectionContext - The section context associated with the scan context.
1617 
1618 Return Value:
1619 
1620  None.
1621 
1622 --*/
1623 {
1624  NTSTATUS status;
1625  PAV_STREAM_CONTEXT streamContext = NULL;
1626 
1627  PAGED_CODE();
1628 
1629  AvFinalizeSectionContext( SectionContext );
1630 
1631  status = FltGetStreamContext( ScanContext->FilterInstance,
1632  ScanContext->FileObject,
1633  &streamContext );
1634 
1635  if (NT_SUCCESS( status )) {
1636 
1637  KeSetEvent( streamContext->ScanSynchronizationEvent, 0, FALSE );
1638  FltReleaseContext( streamContext );
1639  }
1640 
1641  //
1642  // Release I/O request thread.
1643  //
1644 
1645  KeSetEvent( &ScanContext->ScanCompleteNotification, 0, FALSE );
1646  return;
1647 }
1648 
1649 NTSTATUS
1651  _In_ ULONG ScanThreadId,
1652  _In_ LONGLONG ScanId
1653  )
1654 /*++
1655 
1656 Routine Description:
1657 
1658  This routine sends an abortion message to the user scan thread.
1659  The cancel callback is asynchronous and thus we send which
1660  scan id to abort; otherwise the worker thread in the user
1661  may abort the 'next' scan task.
1662 
1663 Arguments:
1664 
1665  ScanThreadId - The thread identifier of whom to be aborted.
1666 
1667  ScanId - Which scan task to be aborted.
1668 
1669 Return Value:
1670 
1671  The return value is the status of the operation.
1672 
1673 --*/
1674 {
1675  NTSTATUS status = STATUS_SUCCESS;
1676  ULONG replyLength = 0;
1677  LARGE_INTEGER timeout = {0};
1678  AV_SCANNER_NOTIFICATION notification = {0};
1679 
1680  PAGED_CODE();
1681 
1682  notification.Message = AvMsgAbortScanning;
1683  notification.ScanThreadId = ScanThreadId;
1684  notification.ScanId = ScanId;
1685 
1686  timeout.QuadPart = -((LONGLONG)10) * (LONGLONG)1000 * (LONGLONG)1000; // 1s
1687 
1688  //
1689  // Tell the user-scanner to abort the scan.
1690  //
1691 
1692  status = FltSendMessage( Globals.Filter,
1694  &notification,
1695  sizeof(AV_SCANNER_NOTIFICATION),
1696  NULL,
1697  &replyLength,
1698  &timeout );
1699 
1700 
1701  if (!NT_SUCCESS( status ) ||
1702  (status == STATUS_TIMEOUT)) {
1703 
1704  if ((status != STATUS_PORT_DISCONNECTED) &&
1705  (status != STATUS_TIMEOUT)) {
1706 
1707  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1708  ("[Av]: AvSendAbortToUser: Failed to FltSendMessage.\n, 0x%08x\n",
1709  status) );
1710  }
1711  return status;
1712  }
1713  return status;
1714 }
1715 
1716 NTSTATUS
1718  VOID
1719  )
1720 /*++
1721 
1722 Routine Description:
1723 
1724  This routine sends unloading message to the user program.
1725 
1726 Arguments:
1727 
1728  None.
1729 
1730 Return Value:
1731 
1732  The return value is the status of the operation.
1733 
1734 --*/
1735 {
1736  ULONG abortThreadId;
1737  NTSTATUS status = STATUS_SUCCESS;
1738  ULONG replyLength = sizeof(ULONG);
1739  AV_SCANNER_NOTIFICATION notification = {0};
1740 
1741  PAGED_CODE();
1742 
1743  notification.Message = AvMsgFilterUnloading;
1744 
1745  //
1746  // Tell the user-scanner that we are unloading the filter.
1747  // and waits for its reply.
1748  //
1749 
1750  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
1751  ("[Av]: AvSendUnloadingToUser: BEFORE...\n") );
1752 
1753  status = FltSendMessage( Globals.Filter,
1755  &notification,
1756  sizeof(AV_SCANNER_NOTIFICATION),
1757  &abortThreadId,
1758  &replyLength,
1759  NULL );
1760 
1761  if (!NT_SUCCESS( status )) {
1762 
1763  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1764  ("[Av]: AvSendUnloadingToUser: Failed to FltSendMessage.\n, 0x%08x\n",
1765  status) );
1766  }
1767 
1768  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
1769  ("[Av]: AvSendUnloadingToUser: After...\n") );
1770 
1771  return status;
1772 }
1773 
1774 /*************************************************************************
1775  MiniFilter callback routines.
1776 *************************************************************************/
1777 
1778 FLT_PREOP_CALLBACK_STATUS
1780  _Inout_ PFLT_CALLBACK_DATA Data,
1781  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1782  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1783  )
1784 /*++
1785 
1786 Routine Description:
1787 
1788  This routine is the registered callback routine for filtering
1789  the "write" operation, i.e. the operations that have potentials
1790  to modify the file.
1791 
1792  This is non-pageable because it could be called on the paging path
1793 
1794 Arguments:
1795 
1796  Data - Pointer to the filter callbackData that is passed to us.
1797 
1798  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1799  opaque handles to this filter, instance, its associated volume and
1800  file object.
1801 
1802  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1803  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1804  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1805 
1806 Return Value:
1807 
1808  The return value is the status of the operation.
1809 
1810 --*/
1811 {
1812  NTSTATUS status;
1813  PAV_STREAM_CONTEXT streamContext = NULL;
1814  PAV_STREAMHANDLE_CONTEXT streamHandleContext = NULL;
1815  ULONG flags;
1816 
1817  UNREFERENCED_PARAMETER( CompletionContext );
1818 
1819  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1820  ("[AV] AvPreOperationCallback: Entered\n") );
1821 
1822  if (!AvOperationsModifyingFile(Data)) {
1823 
1824  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1825  }
1826 
1827  //
1828  // Skip prefetcher handles to avoid deadlocks
1829  //
1830 
1831  status = FltGetStreamHandleContext( FltObjects->Instance,
1832  FltObjects->FileObject,
1833  &streamHandleContext );
1834  if (NT_SUCCESS(status)) {
1835 
1836  flags = streamHandleContext->Flags;
1837 
1838  FltReleaseContext( streamHandleContext );
1839 
1840  if (FlagOn( flags, AV_FLAG_PREFETCH )) {
1841  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1842  }
1843  }
1844 
1845  status = FltGetStreamContext( FltObjects->Instance,
1846  FltObjects->FileObject,
1847  &streamContext );
1848 
1849  if (!NT_SUCCESS( status )) {
1850 
1851  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1852  ("[AV] AvPreOperationCallback: get stream context failed. rq: %d\n",
1853  Data->Iopb->MajorFunction) );
1854 
1855  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1856  }
1857 
1858  //
1859  // If this operation is performed in a transacted writer view.
1860  //
1861 
1862  if ((streamContext->TxContext != NULL) &&
1863  (FltObjects->Transaction != NULL)) {
1864 
1865 #if DBG
1866  PAV_TRANSACTION_CONTEXT transactionContext = NULL;
1867 
1868  NTSTATUS statusTx = FltGetTransactionContext( FltObjects->Instance,
1869  FltObjects->Transaction,
1870  &transactionContext );
1871 
1872  FLT_ASSERTMSG( "Transaction context should not fail, because it is supposed to be created at post create.\n", NT_SUCCESS( statusTx ));
1873  FLT_ASSERTMSG( "The file's TxCtx should be identical with the target TxCtx.\n",
1874  streamContext->TxContext == transactionContext);
1875 
1876  if (NT_SUCCESS( statusTx )) {
1877  FltReleaseContext( transactionContext );
1878  }
1879 
1880 #endif // DBG
1881 
1882  //
1883  // Instead of updating State, we update TxState here,
1884  // because the file is part of a transaction writer
1885  //
1886 
1887  SET_FILE_TX_MODIFIED( streamContext );
1888 
1889  } else {
1890 
1891  //
1892  // Consider an optimization for the case where another thread
1893  // is already scanning the file as it is being modified here.
1894  //
1895 
1896  SET_FILE_MODIFIED( streamContext );
1897  }
1898 
1899  FltReleaseContext( streamContext );
1900 
1901  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1902 }
1903 
1904 FLT_PREOP_CALLBACK_STATUS
1906  _Inout_ PFLT_CALLBACK_DATA Data,
1907  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1908  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1909  )
1910 /*++
1911 
1912 Routine Description:
1913 
1914  Pre-file system control callback. This filter example does not support save point feature.
1915  So, we explicitly fail the request here.
1916 
1917 Arguments:
1918 
1919  Data - Pointer to the filter callbackData that is passed to us.
1920 
1921  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1922  opaque handles to this filter, instance, its associated volume and
1923  file object.
1924 
1925  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1926  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1927  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1928 
1929 Return Value:
1930 
1931  The return value is the status of the operation.
1932 
1933 --*/
1934 {
1935 
1936  PAGED_CODE();
1937 
1938  if (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_TXFS_SAVEPOINT_INFORMATION ) {
1939 
1940  //
1941  // We explicitly fail the request of save point here since we
1942  // are deprecating savepoint support for the OS version targeted
1943  // for this filter.
1944  //
1945 
1946  Data->IoStatus.Status = STATUS_NOT_SUPPORTED;
1947  return FLT_PREOP_COMPLETE;
1948  }
1949  return AvPreOperationCallback(Data, FltObjects, CompletionContext);
1950 }
1951 
1952 FLT_PREOP_CALLBACK_STATUS
1954  _Inout_ PFLT_CALLBACK_DATA Data,
1955  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1956  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1957  )
1958 /*++
1959 
1960 Routine Description:
1961 
1962  This routine is the pre-create completion routine.
1963 
1964 
1965 Arguments:
1966 
1967  Data - Pointer to the filter callbackData that is passed to us.
1968 
1969  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1970  opaque handles to this filter, instance, its associated volume and
1971  file object.
1972 
1973  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1974  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1975  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1976 
1977 Return Value:
1978 
1979  FLT_PREOP_SYNCHRONIZE - PostCreate needs to be called back synchronizedly.
1980  FLT_PREOP_SUCCESS_NO_CALLBACK - PostCreate does not need to be called.
1981 
1982 --*/
1983 {
1984  ULONG_PTR stackLow;
1985  ULONG_PTR stackHigh;
1986  PFILE_OBJECT FileObject = Data->Iopb->TargetFileObject;
1987  AV_STREAMHANDLE_CONTEXT streamHandleContext;
1988 
1989 
1990  PAGED_CODE();
1991 
1992  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1993  ("[AV] AvPreCreate: Entered\n") );
1994 
1995  streamHandleContext.Flags = 0;
1996 
1997  //
1998  // Stack file objects are never scanned.
1999  //
2000 
2001  IoGetStackLimits( &stackLow, &stackHigh );
2002 
2003  if (((ULONG_PTR)FileObject > stackLow) &&
2004  ((ULONG_PTR)FileObject < stackHigh)) {
2005 
2006  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2007  }
2008 
2009  //
2010  // Directory opens don't need to be scanned.
2011  //
2012 
2013  if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
2014 
2015  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2016  }
2017 
2018  //
2019  // Skip pre-rename operations which always open a directory.
2020  //
2021 
2022  if ( FlagOn( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY )) {
2023 
2024  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2025  }
2026 
2027  //
2028  // Skip paging files.
2029  //
2030 
2031  if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_PAGING_FILE )) {
2032 
2033  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2034  }
2035 
2036  //
2037  // Skip scanning DASD opens
2038  //
2039 
2040  if (FlagOn( FltObjects->FileObject->Flags, FO_VOLUME_OPEN )) {
2041 
2042  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2043  }
2044 
2045  //
2046  // Skip scanning any files being opened by CSVFS for its downlevel
2047  // processing. This includes filters on the hidden NTFS stack and
2048  // for filters attached to MUP
2049  //
2050  if (AvIsCsvDlEcpPresent( FltObjects->Filter, Data ) ) {
2051 
2052  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2053  }
2054 
2055 
2056  //
2057  // Flag prefetch handles so they can be skipped. Performing IO
2058  // using a prefetch fileobject could lead to a deadlock.
2059  //
2060 
2061  if (AvIsPrefetchEcpPresent( FltObjects->Filter, Data )) {
2062 
2063  SetFlag( streamHandleContext.Flags, AV_FLAG_PREFETCH );
2064  }
2065 
2066  *CompletionContext = (PVOID)streamHandleContext.Flags;
2067 
2068  //
2069  // Perform any CSVFS pre create processing
2070  //
2071  AvPreCreateCsvfs( Data, FltObjects );
2072 
2073  //
2074  // return status can be safely ignored
2075  //
2076 
2077  //
2078  // Return FLT_PREOP_SYNCHRONIZE at PreCreate to ensure PostCreate
2079  // is in the same thread at passive level.
2080  // EResource can't be acquired at DPC.
2081  //
2082 
2083  return FLT_PREOP_SYNCHRONIZE;
2084 
2085 }
2086 
2087 NTSTATUS
2089  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2090  _Inout_ PAV_STREAM_CONTEXT StreamContext
2091  )
2092 /*++
2093 
2094 Routine Description:
2095 
2096  This routine is transaction related implementation, and is expected to be
2097  invoked at post-create. Note that this function will enlist the newly
2098  allocated transaction context via FltEnlistInTransaction if it needs to.
2099 
2100 Arguments:
2101 
2102  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2103  opaque handles to this filter, instance, its associated volume and
2104  file object.
2105 
2106  StreamContext - The stream context.
2107 
2108 Return Value:
2109 
2110  The return value is the status of the operation.
2111 
2112 --*/
2113 {
2114  NTSTATUS status = STATUS_SUCCESS;
2115  PAV_TRANSACTION_CONTEXT oldTxCtx = NULL;
2116  PAV_TRANSACTION_CONTEXT transactionContext = NULL;
2117 
2118  PAGED_CODE();
2119 
2120  if (FltObjects->Transaction != NULL ) {
2121 
2122  //
2123  // Get transaction context
2124  //
2125 
2126  status = AvFindOrCreateTransactionContext( FltObjects,
2127  &transactionContext );
2128 
2129  if (!NT_SUCCESS( status )) {
2130 
2131  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2132  ("[AV] AvProcessPreviousTransaction: AvFindOrCreateTransactionContext FAILED\n") );
2133  transactionContext = NULL;
2134  goto Cleanup;
2135  }
2136 
2137  //
2138  // Enlist it if haven't.
2139  //
2140 
2141  if (! FlagOn(transactionContext->Flags, AV_TXCTX_ENLISTED) ) {
2142 
2143  //
2144  // You can also consider to register TRANSACTION_NOTIFY_PREPARE,
2145  // and scan the file at TRANSACTION_NOTIFY_PREPARE callback if it was modified.
2146  //
2147 
2148  status = FltEnlistInTransaction( FltObjects->Instance,
2149  FltObjects->Transaction,
2150  transactionContext,
2151  TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK );
2152 
2153  if (!NT_SUCCESS( status ) &&
2154  (status != STATUS_FLT_ALREADY_ENLISTED)) {
2155 
2156  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2157  ("[AV] AvProcessPreviousTransaction: FltEnlistInTransaction FAILED!!!!\n") );
2158  goto Cleanup;
2159  }
2160  status = STATUS_SUCCESS;
2161  SetFlag( transactionContext->Flags, AV_TXCTX_ENLISTED );
2162  }
2163  }
2164 
2165  //
2166  // Here we have five cases:
2167  //
2168  // 1)
2169  // oldTxCtx : NULL
2170  // transCtx : B
2171  // 2)
2172  // oldTxCtx : A
2173  // transCtx : NULL
2174  // 3)
2175  // oldTxCtx : A
2176  // transCtx : B
2177  // 4)
2178  // oldTxCtx : A
2179  // transCtx : A
2180  // 5)
2181  // oldTxCtx : NULL
2182  // transCtx : NULL
2183  //
2184 
2185  //
2186  // Synchronize the replacement of StreamContext->TxContext with KTM callback.
2187  //
2188 
2189  oldTxCtx = InterlockedExchangePointer( &StreamContext->TxContext, transactionContext );
2190 
2191  if (oldTxCtx != transactionContext) { // case 1,2,3
2192 
2193  //
2194  // txOutcome is by default set as committed because we are conservative about
2195  // propagating the file state if AvQueryTransactionOutcome failed, it may cause
2196  // redundant scan but will not overlook infected file anyway.
2197  //
2198 
2199  ULONG txOutcome = TransactionOutcomeCommitted;
2200 
2201  if ( oldTxCtx == NULL ) { // case 1
2202 
2203  // This file was not linked in a transaction context yet, and is about to.
2204  //
2205  // Increment TxContext's reference count because stream context has a reference to it.
2206  //
2207 
2208  FltReferenceContext ( transactionContext );
2209 
2210  //
2211  // Before insertion into the FcList in transaction context, we increment stream context's ref count
2212  //
2213 
2214  AvAcquireResourceExclusive( transactionContext->Resource );
2215 
2216  if (!FlagOn(transactionContext->Flags, AV_TXCTX_LISTDRAINED)) {
2217 
2218  FltReferenceContext ( StreamContext ); // Q
2219  InsertTailList( &transactionContext->ScListHead,
2220  &StreamContext->ListInTransaction );
2221  }
2222 
2223  AvReleaseResource( transactionContext->Resource );
2224 
2225  goto Cleanup;
2226  }
2227 
2228  // case 2,3
2229 
2230  //
2231  // We have to query transaction outcome in order to know how we
2232  // can process the previously outstanding transaction context.
2233  //
2234 
2235  status = AvQueryTransactionOutcome( oldTxCtx->Transaction, &txOutcome );
2236 
2237  if (!NT_SUCCESS( status )) {
2238 
2239  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2240  ("[AV] AvProcessPreviousTransaction: AvQueryTransactionOutcome FAILED!!!!\n") );
2241 
2242  //
2243  // We have exchanged the pointer anyway, if we cannot query its outcome,
2244  // we have to go through.
2245  //
2246  }
2247 
2248  AvAcquireResourceExclusive( oldTxCtx->Resource );
2249  RemoveEntryList ( &StreamContext->ListInTransaction );
2250  AvReleaseResource( oldTxCtx->Resource );
2251 
2252  AvPropagateFileState ( StreamContext, txOutcome );
2253 
2254  if ( transactionContext ) { // case 3
2255 
2256  FltReferenceContext( transactionContext );
2257 
2258  AvAcquireResourceExclusive( transactionContext->Resource );
2259 
2260  if (!FlagOn(transactionContext->Flags, AV_TXCTX_LISTDRAINED)) {
2261 
2262  InsertTailList( &transactionContext->ScListHead,
2263  &StreamContext->ListInTransaction );
2264 
2265  } else {
2266 
2267  FltReleaseContext( StreamContext );
2268  }
2269 
2270  AvReleaseResource( transactionContext->Resource );
2271 
2272  } else { // case 2
2273 
2274  FltReleaseContext ( StreamContext ); // Release reference count at Q
2275  }
2276 
2277  // case 2,3
2278 
2279  FltReleaseContext( oldTxCtx ); // Release reference count in stream context originally.
2280 
2281  }
2282 
2283  //
2284  // We don't care about case 4, 5.
2285  //
2286 
2287 Cleanup:
2288 
2289  if (transactionContext) {
2290 
2291  FltReleaseContext( transactionContext ); // Release the ref count grabbed at AvFindOrCreateTransactionContext(...)
2292  }
2293 
2294  return status;
2295 }
2296 
2297 FLT_POSTOP_CALLBACK_STATUS
2298 AvPostCreate (_Inout_ PFLT_CALLBACK_DATA Data,
2299  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2300  _In_opt_ PVOID CompletionContext,
2301  _In_ FLT_POST_OPERATION_FLAGS Flags
2302  )
2303 /*++
2304 
2305 Routine Description:
2306 
2307  This routine is the post-create completion routine.
2308  In this routine, stream context and/or transaction context shall be
2309  created if not exits.
2310 
2311  Note that we only allocate and set the stream context to filter manager
2312  at post create.
2313 
2314 Arguments:
2315 
2316  Data - Pointer to the filter callbackData that is passed to us.
2317 
2318  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2319  opaque handles to this filter, instance, its associated volume and
2320  file object.
2321 
2322  CompletionContext - The completion context set in the pre-create routine.
2323 
2324  Flags - Denotes whether the completion is successful or is being drained.
2325 
2326 Return Value:
2327 
2328  The return value is the status of the operation.
2329 
2330 --*/
2331 {
2332  NTSTATUS status = Data->IoStatus.Status;
2333  BOOLEAN isDir = FALSE;
2334  BOOLEAN isTxWriter = FALSE;
2335 
2336  PAV_STREAM_CONTEXT streamContext = NULL;
2337  PAV_STREAM_CONTEXT oldStreamContext = NULL;
2338  PAV_STREAMHANDLE_CONTEXT streamHandleContext = NULL;
2339  ACCESS_MASK desiredAccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess;
2340 
2341  BOOLEAN updateRevisionNumbers;
2342  LONGLONG VolumeRevision, CacheRevision, FileRevision;
2343 
2344  UNREFERENCED_PARAMETER( CompletionContext );
2345  UNREFERENCED_PARAMETER( Flags );
2346 
2347  PAGED_CODE();
2348 
2349  if (!NT_SUCCESS( status ) ||
2350  (status == STATUS_REPARSE)) {
2351 
2352  //
2353  // File Creation may fail.
2354  //
2355 
2356  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2357  ("[AV] AvPostCreate: file creation failed\n") );
2358 
2359  return FLT_POSTOP_FINISHED_PROCESSING;
2360  }
2361 
2362  //
2363  // After creation, skip it if it is directory.
2364  //
2365 
2366  status = FltIsDirectory( FltObjects->FileObject,
2367  FltObjects->Instance,
2368  &isDir );
2369 
2370  //
2371  // If FltIsDirectory failed, we do not know if it is a directoy,
2372  // we let it go through because if it is a directory, it will fail
2373  // at section creation anyway.
2374  //
2375 
2376  if ( NT_SUCCESS( status ) && isDir ) {
2377 
2378  return FLT_POSTOP_FINISHED_PROCESSING;
2379  }
2380 
2381  //
2382  // We skip the encrypted file open without FILE_WRITE_DATA and FILE_READ_DATA
2383  // This is because if application calls OpenEncryptedFileRaw(...) for backup,
2384  // it won't have to decrypt the file. In such case, if we scan it, we will hit
2385  // an assertion error in NTFS because it does not have the encryption context.
2386  // Thus, we have to skip the encrypted file not open for read/write.
2387  //
2388 
2389  if (!(FlagOn(desiredAccess, FILE_WRITE_DATA)) &&
2390  !(FlagOn(desiredAccess, FILE_READ_DATA)) ) {
2391 
2392  BOOLEAN encrypted = FALSE;
2393  status = AvGetFileEncrypted( FltObjects->Instance,
2394  FltObjects->FileObject,
2395  &encrypted );
2396  if (!NT_SUCCESS( status )) {
2397 
2398  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2399  ("[AV] AvPostCreate: AvGetFileEncrypted FAILED!! \n0x%x\n", status) );
2400  }
2401  if (encrypted) {
2402 
2403  return FLT_POSTOP_FINISHED_PROCESSING;
2404  }
2405  }
2406 
2407  //
2408  // In this sample, we skip the alternate data stream. However, you may decide
2409  // to scan it and modify accordingly.
2410  //
2411 
2412  if (AvIsStreamAlternate( Data )) {
2413 
2414  return FLT_POSTOP_FINISHED_PROCESSING;
2415  }
2416 
2417  //
2418  // Skip a prefetch open and flag it so we skip subsequent
2419  // IO operations on the handle.
2420  //
2421 
2422  if (FlagOn((ULONG_PTR)CompletionContext, AV_FLAG_PREFETCH)) {
2423 
2424  if (!FltSupportsStreamHandleContexts( FltObjects->FileObject )) {
2425 
2426  return FLT_POSTOP_FINISHED_PROCESSING;
2427  }
2428 
2429  status = AvCreateStreamHandleContext( FltObjects->Filter,
2430  &streamHandleContext );
2431 
2432  if (!NT_SUCCESS(status)) {
2433 
2434  return FLT_POSTOP_FINISHED_PROCESSING;
2435  }
2436 
2437  SetFlag( streamHandleContext->Flags, AV_FLAG_PREFETCH );
2438 
2439  status = FltSetStreamHandleContext( FltObjects->Instance,
2440  FltObjects->FileObject,
2441  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
2442  streamHandleContext,
2443  NULL );
2444 
2445  FltReleaseContext( streamHandleContext );
2446 
2447  if (!NT_SUCCESS(status)) {
2448 
2449  //
2450  // Shouldn't find the handle already set
2451  //
2452 
2453  ASSERT( status != STATUS_FLT_CONTEXT_ALREADY_DEFINED );
2454  }
2455 
2456  return FLT_POSTOP_FINISHED_PROCESSING;
2457  }
2458 
2459  //
2460  // Find or create a stream context
2461  //
2462 
2463  status = FltGetStreamContext( FltObjects->Instance,
2464  FltObjects->FileObject,
2465  &streamContext );
2466 
2467  if (status == STATUS_NOT_FOUND) {
2468 
2469  //
2470  // Create a stream context
2471  //
2472 
2473  status = AvCreateStreamContext( FltObjects->Filter, &streamContext );
2474 
2475  if (!NT_SUCCESS( status )) {
2476 
2477  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2478  ("[Av]: Failed to create stream context with status 0x%x. (FileObject = %p, Instance = %p)\n",
2479  status,
2480  FltObjects->FileObject,
2481  FltObjects->Instance) );
2482 
2483  return FLT_POSTOP_FINISHED_PROCESSING;
2484  }
2485 
2486  //
2487  // Attempt to get the stream infected state from our cache
2488  //
2489 
2490  status = AvGetFileId( FltObjects->Instance, FltObjects->FileObject, &streamContext->FileId );
2491 
2492  if (!NT_SUCCESS( status )) {
2493 
2494  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2495  ("[Av]: Failed to get file id with status 0x%x. (FileObject = %p, Instance = %p)\n",
2496  status,
2497  FltObjects->FileObject,
2498  FltObjects->Instance) );
2499 
2500  //
2501  // File id is optional and therefore should not affect the scan logic.
2502  //
2503 
2504  AV_SET_INVALID_FILE_REFERENCE( streamContext->FileId )
2505 
2506  } else {
2507 
2508  //
2509  // This function will load the file infected state from the
2510  // cache if the fileID is valid. Even if this function fails,
2511  // we still have to move on because the cache is optional.
2512  //
2513 
2514  AvLoadFileStateFromCache( FltObjects->Instance,
2515  &streamContext->FileId,
2516  &streamContext->State,
2517  &streamContext->VolumeRevision,
2518  &streamContext->CacheRevision,
2519  &streamContext->FileRevision );
2520  }
2521 
2522  //
2523  // Set the new context we just allocated on the file object
2524  //
2525 
2526  status = FltSetStreamContext( FltObjects->Instance,
2527  FltObjects->FileObject,
2528  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
2529  streamContext,
2530  &oldStreamContext );
2531 
2532  if (!NT_SUCCESS(status)) {
2533 
2534  if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
2535 
2536  //
2537  // Race condition. Someone has set a context after we queried it.
2538  // Use the already set context instead
2539  //
2540 
2541  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2542  ("[Av]: Race: Stream context already defined. Retaining old stream context %p (FileObject = %p, Instance = %p)\n",
2543  oldStreamContext,
2544  FltObjects->FileObject,
2545  FltObjects->Instance) );
2546 
2547  FltReleaseContext( streamContext );
2548 
2549  streamContext = oldStreamContext;
2550 
2551  } else {
2552 
2553  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2554  ("[Av]: Failed to set stream context with status 0x%x. (FileObject = %p, Instance = %p)\n",
2555  status,
2556  FltObjects->FileObject,
2557  FltObjects->Instance) );
2558  goto Cleanup;
2559  }
2560  }
2561 
2562  } else if (!NT_SUCCESS(status)) {
2563 
2564  //
2565  // We will get here if stream contexts are not supported
2566  //
2567 
2568  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2569  ("[Av]: Failed to get stream context with status 0x%x. (FileObject = %p, Instance = %p)\n",
2570  status,
2571  FltObjects->FileObject,
2572  FltObjects->Instance) );
2573 
2574  return FLT_POSTOP_FINISHED_PROCESSING;
2575  }
2576 
2577  //
2578  // If successfully opened a file with the desired access matching
2579  // the "exclusive write" from a TxF point of view, we can guarantee that
2580  // if previous transaction context exists, it must have been comitted
2581  // or rollbacked.
2582  //
2583 
2584  if (FlagOn( Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess,
2585  FILE_WRITE_DATA | FILE_APPEND_DATA |
2586  DELETE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
2587  WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY ) ) {
2588 
2589  //
2590  // Either this file is opened in a transaction context or not,
2591  // we need to process the previous transaction if it exists.
2592  // AvProcessPreviousTransaction(...) handles these cases.
2593  //
2594 
2595  status = AvProcessPreviousTransaction ( FltObjects,
2596  streamContext );
2597  if (!NT_SUCCESS( status )) {
2598 
2599  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2600  ("[AV] AvPostCreate: AvProcessTransaction FAILED!! \n") );
2601 
2602  goto Cleanup;
2603  }
2604 
2605  isTxWriter = (FltObjects->Transaction != NULL);
2606  }
2607 
2608  //
2609  // Perform any CSVFS specific processing
2610  //
2611  AvPostCreateCsvfs( Data,
2612  FltObjects,
2613  streamContext,
2614  &updateRevisionNumbers,
2615  &VolumeRevision,
2616  &CacheRevision,
2617  &FileRevision );
2618  //
2619  // Ignore return status
2620  //
2621 
2622 
2623 
2624  if (IS_FILE_NEED_SCAN( streamContext )) {
2625 
2626  status = AvScan( Data,
2627  FltObjects,
2628  AvUserMode,
2629  Data->Iopb->MajorFunction,
2630  isTxWriter,
2631  streamContext );
2632  if (!NT_SUCCESS( status ) ||
2633  (STATUS_TIMEOUT == status)) {
2634 
2635  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2636  ("[AV] AvPostCreate: AvScan FAILED!! \n") );
2637 
2638  goto Cleanup;
2639  }
2640  }
2641 
2642 
2643  //
2644  // If needed, update the stream context with the latest revision
2645  // numbers that correspond to the verion just scanned
2646  //
2647  if (updateRevisionNumbers) {
2648  streamContext->VolumeRevision = VolumeRevision;
2649  streamContext->CacheRevision = CacheRevision;
2650  streamContext->FileRevision = FileRevision;
2651 
2652  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
2653  ("[Av]: AvPostCreate: RevisionNumbers updated to %I64x:%I64x:%I64x\n",
2654  VolumeRevision,
2655  CacheRevision,
2656  FileRevision)
2657  );
2658  }
2659 
2660  if (IS_FILE_INFECTED( streamContext )) {
2661 
2662  //
2663  // If the file is infected, deny the access.
2664  //
2665  AvCancelFileOpen(Data, FltObjects, STATUS_VIRUS_INFECTED);
2666 
2667  //
2668  // If the scan timed-out or scan was failed, we let the create succeed,
2669  // and it may cause security hole;
2670  //
2671  // Alternatively, you can add a state called AvFileScanFailure or equivalent,
2672  // add a condition here and fail the create. This option will have better
2673  // protection from viruses, but the apps will see the failures due to a
2674  // lengthy scan or scan failure. It's a trade-off.
2675  //
2676  goto Cleanup;
2677  }
2678 
2679 Cleanup:
2680 
2681  FltReleaseContext( streamContext );
2682 
2683  return FLT_POSTOP_FINISHED_PROCESSING;
2684 }
2685 
2686 FLT_PREOP_CALLBACK_STATUS
2688  _Inout_ PFLT_CALLBACK_DATA Data,
2689  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2690  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
2691  )
2692 /*++
2693 
2694 Routine Description:
2695 
2696  Pre-cleanup callback. Make the stream context persistent in the volatile cache.
2697  If the file is transacted, it will be synced at KTM notification callback
2698  if committed.
2699 
2700 Arguments:
2701 
2702  Data - Pointer to the filter callbackData that is passed to us.
2703 
2704  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2705  opaque handles to this filter, instance, its associated volume and
2706  file object.
2707 
2708  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
2709  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
2710  the corresponding post-operation callback routine. Otherwise, it must be NULL.
2711 
2712 Return Value:
2713 
2714  The return value is the status of the operation.
2715 
2716 --*/
2717 {
2718  NTSTATUS status;
2719  BOOLEAN encrypted = FALSE;
2720  PAV_STREAM_CONTEXT streamContext = NULL;
2721  PAV_STREAMHANDLE_CONTEXT streamHandleContext = NULL;
2722  ULONG_PTR stackLow;
2723  ULONG_PTR stackHigh;
2724 
2725  BOOLEAN updateRevisionNumbers;
2726  LONGLONG VolumeRevision, CacheRevision, FileRevision;
2727 
2728  UNREFERENCED_PARAMETER( CompletionContext );
2729 
2730  PAGED_CODE();
2731 
2732  //
2733  // Skip scan on prefetcher handles to avoid deadlocks
2734  //
2735 
2736  status = FltGetStreamHandleContext( FltObjects->Instance,
2737  FltObjects->FileObject,
2738  &streamHandleContext );
2739  if (NT_SUCCESS(status)) {
2740 
2741  if (FlagOn( streamHandleContext->Flags, AV_FLAG_PREFETCH )) {
2742 
2743  //
2744  // Because the Memory Manager can cache the file object
2745  // and use it for other applications performing mapped I/O,
2746  // whenever a Cleanup operation is seen on a prefetcher
2747  // file object, that file object should no longer be
2748  // considered prefetcher-opened.
2749  //
2750 
2751  RtlInterlockedClearBits( &streamHandleContext->Flags,
2752  AV_FLAG_PREFETCH );
2753 
2754  FltDeleteStreamHandleContext( FltObjects->Instance,
2755  FltObjects->FileObject,
2756  NULL );
2757 
2758  FltReleaseContext( streamHandleContext );
2759 
2760  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2761  }
2762 
2763  FltReleaseContext( streamHandleContext );
2764  }
2765 
2766  //
2767  // Stack file objects are never scanned.
2768  //
2769 
2770  IoGetStackLimits( &stackLow, &stackHigh );
2771 
2772  if (((ULONG_PTR)FltObjects->FileObject > stackLow) &&
2773  ((ULONG_PTR)FltObjects->FileObject < stackHigh)) {
2774 
2775  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2776  }
2777 
2778  status = FltGetStreamContext( FltObjects->Instance,
2779  FltObjects->FileObject,
2780  &streamContext );
2781 
2782  if (!NT_SUCCESS( status )) {
2783 
2784  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2785  ("[AV] AvPreCleanup: find stream context failed.\n") );
2786 
2787  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2788  }
2789 
2790  //
2791  // We skip encrypted files at cleanup time because we cannot be
2792  // sure if the file is open raw for backup. It will get scanned
2793  // on the next open anyway.
2794  //
2795 
2796  status = AvGetFileEncrypted( FltObjects->Instance,
2797  FltObjects->FileObject,
2798  &encrypted );
2799  if (!NT_SUCCESS( status )) {
2800 
2801  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2802  ("[AV] AvPreCleanup: AvGetFileEncrypted FAILED!! \n") );
2803 
2804  goto Cleanup;
2805  }
2806 
2807  if (encrypted) {
2808 
2809  goto Cleanup;
2810  }
2811 
2812  AvPreCleanupCsvfs( Data,
2813  FltObjects,
2814  streamContext,
2815  &updateRevisionNumbers,
2816  &VolumeRevision,
2817  &CacheRevision,
2818  &FileRevision );
2819 
2820  //
2821  // For applications, the typical calling sequence is, close the file handle
2822  // and commit/rollback the changes. We skip the scan here for
2823  // transacted writer because we do not know if the change will be
2824  // rollbacked or not. If it eventually commits, it will be scanned
2825  // at next create anyway. However, if it rollbacks, the scan here will
2826  // be redundant.
2827  //
2828 
2829  if ((streamContext->TxContext == NULL) &&
2830  IS_FILE_MODIFIED( streamContext )) {
2831 
2832  status = AvScan( Data,
2833  FltObjects,
2834  AvUserMode,
2835  Data->Iopb->MajorFunction,
2836  FALSE,
2837  streamContext );
2838 
2839  if (!NT_SUCCESS( status ) || STATUS_TIMEOUT == status) {
2840 
2841  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2842  ("[AV] AvPreCleanup: AvScan FAILED!! \n") );
2843 
2844  goto Cleanup;
2845  }
2846 
2847 
2848  //
2849  // If needed, update the stream context with the latest revision
2850  // numbers that correspond to the verion just scanned
2851  //
2852  if (updateRevisionNumbers) {
2853  streamContext->VolumeRevision = VolumeRevision;
2854  streamContext->CacheRevision = CacheRevision;
2855  streamContext->FileRevision = FileRevision;
2856 
2857  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
2858  ("[Av]: AvPreCleanup: RevisionNumbers updated to %I64x:%I64x:%I64x\n",
2859  VolumeRevision,
2860  CacheRevision,
2861  FileRevision)
2862  );
2863  }
2864 
2865  }
2866 
2867 Cleanup:
2868 
2869  //
2870  // We only insert the entry when the file is clean or infected.
2871  //
2872 
2873  if (!IS_FILE_MODIFIED( streamContext ) ||
2874  IS_FILE_INFECTED( streamContext )) {
2875 
2876  if (!NT_SUCCESS ( AvSyncCache( FltObjects->Instance, streamContext ))) {
2877 
2878  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2879  ("[AV] AvPreCleanup: AvSyncCache FAILED!! \n") );
2880  }
2881  }
2882 
2883  FltReleaseContext( streamContext );
2884 
2885  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2886 }
2887 
2888 NTSTATUS
2890  _Unreferenced_parameter_ PCFLT_RELATED_OBJECTS FltObjects,
2891  _In_ PFLT_CONTEXT TransactionContext,
2892  _In_ ULONG TransactionNotification
2893  )
2894 /*++
2895 
2896 Routine Description:
2897 
2898  The registered routine of type PFLT_TRANSACTION_NOTIFICATION_CALLBACK
2899  in FLT_REGISTRATION structure.
2900 
2901 Arguments:
2902 
2903  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2904  opaque handles to this filter, instance, its associated volume and
2905  file object.
2906 
2907  TransactionContext - Pointer to the minifilter driver's transaction context
2908  set at PostCreate.
2909 
2910  TransactionNotification - Specifies the type of notifications that the
2911  filter manager is sending to the minifilter driver.
2912 
2913 Return Value:
2914 
2915  STATUS_SUCCESS - Returning this status value indicates that the minifilter
2916  driver is finished with the transaction. This is a success code.
2917 
2918  STATUS_PENDING - Returning this status value indicates that the minifilter
2919  driver is not yet finished with the transaction. This is a success code.
2920 
2921 --*/
2922 {
2923  PAV_TRANSACTION_CONTEXT transactionContext = (PAV_TRANSACTION_CONTEXT) TransactionContext;
2924 
2925  PAGED_CODE();
2926 
2927  UNREFERENCED_PARAMETER( FltObjects );
2928 
2929  FLT_ASSERTMSG("[AV] AvKtmNotificationCallback: The expected type of notifications registered at FltEnlistInTransaction(...).\n",
2930  FlagOn( TransactionNotification,
2931  (TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK) ) );
2932 
2933  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
2934  ("[AV] AvKtmNotificationCallback: Entered\n") );
2935 
2936  if (NULL != transactionContext) {
2937 
2938  if ( FlagOn( TransactionNotification, TRANSACTION_NOTIFY_COMMIT_FINALIZE ) ) {
2939 
2940  return AvProcessTransactionOutcome( TransactionContext, TransactionOutcomeCommitted );
2941 
2942  } else {
2943 
2944  return AvProcessTransactionOutcome( TransactionContext, TransactionOutcomeAborted );
2945  }
2946  }
2947 
2948  return STATUS_SUCCESS;
2949 }
2950 
2951 NTSTATUS
2953  _Unreferenced_parameter_ PFLT_INSTANCE Instance,
2954  _In_ PFLT_CONTEXT Context,
2955  _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data
2956  )
2957 /*++
2958 
2959 Routine Description:
2960 
2961  This routine is the registered cancel callback function in FLT_REGISTRATION.
2962  It would be invoked by the file system if it decides to abort the scan.
2963  As its name suggests, this function is asynchrounous, so the caller is not
2964  blocked.
2965 
2966  Note: This routine may be called before FltCreateSectionForDataScan returns.
2967  This means the SectionHandle and SectionObject may not yet be set in the
2968  SectionContext. We can't take a dependency on these being set before needing
2969  to abort the scan.
2970 
2971 Arguments:
2972 
2973  Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL.
2974 
2975  Context - The section context.
2976 
2977  Data - Pointer to the filter callbackData that is passed to us.
2978 
2979 Return Value:
2980 
2981  Returns the final status of this operation.
2982 
2983 --*/
2984 {
2985  PAV_SECTION_CONTEXT sectionCtx = (PAV_SECTION_CONTEXT) Context;
2986  PAV_SCAN_CONTEXT scanCtx = NULL;
2987 
2988  PAGED_CODE();
2989 
2990  UNREFERENCED_PARAMETER( Instance );
2991  UNREFERENCED_PARAMETER( Data );
2992 
2993  if (NULL == sectionCtx) {
2994  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
2995  ("[AV] AvScanAbortCallbackAsync: INVALID ARGUMENT.\n") );
2996  return STATUS_INVALID_PARAMETER_2;
2997  }
2998 
2999  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
3000  ("[AV] AvScanAbortCallbackAsync: closesection handle=%p, object=%p, cancelable=%d\n",
3001  sectionCtx->SectionHandle,
3002  sectionCtx->SectionObject,
3003  sectionCtx->CancelableOnConflictingIo) );
3004 
3005  //
3006  // Send abort signal only when the scanning
3007  // happens in cancelable context (such as pre-cleanup).
3008  //
3009 
3010  if (sectionCtx->CancelableOnConflictingIo) {
3011 
3012  //
3013  // The only reason of scan context being NULL is that
3014  // the section context is about to close anyway.
3015  // Please see AvCloseSectionForDataScan(...)
3016  //
3017  scanCtx = InterlockedExchangePointer( &sectionCtx->ScanContext, NULL );
3018 
3019  if (scanCtx == NULL) {
3020 
3021  return STATUS_SUCCESS;
3022  }
3023 
3024  sectionCtx->Aborted = TRUE;
3025  AvSendAbortToUser( scanCtx->ScanThreadId, scanCtx->ScanId );
3026 
3027  }
3028 
3029  return STATUS_SUCCESS;
3030 }
3031 
3032 NTSTATUS
3034  _In_ PUNICODE_STRING RegistryPath
3035  )
3036 /*++
3037 
3038 Routine Descrition:
3039 
3040  This routine sets the filter configuration based on registry values.
3041 
3042 Arguments:
3043 
3044  RegistryPath - The path key passed to the driver during DriverEntry.
3045 
3046 Return Value:
3047 
3048  Returns the status of this operation.
3049 
3050 
3051 --*/
3052 {
3053  NTSTATUS status;
3054  OBJECT_ATTRIBUTES attributes;
3055  HANDLE driverRegKey = NULL;
3056  UNICODE_STRING valueName;
3057  UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
3058  PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
3059  ULONG valueLength = sizeof(buffer);
3060  ULONG resultLength;
3061 
3062  //
3063  // Open the SimRep registry key.
3064  //
3065 
3066  InitializeObjectAttributes( &attributes,
3067  RegistryPath,
3068  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3069  NULL,
3070  NULL );
3071 
3072  status = ZwOpenKey( &driverRegKey,
3073  KEY_READ,
3074  &attributes );
3075 
3076  if (!NT_SUCCESS( status )) {
3077 
3078  goto Cleanup;
3079  }
3080 
3081 
3082 #if DBG
3083 
3084  //
3085  // Query the debug level
3086  //
3087 
3088  RtlInitUnicodeString( &valueName, L"DebugLevel" );
3089 
3090  status = ZwQueryValueKey( driverRegKey,
3091  &valueName,
3093  value,
3094  valueLength,
3095  &resultLength );
3096 
3097  if (NT_SUCCESS( status )) {
3098 
3099  Globals.DebugLevel = *(PULONG)value->Data;
3100  }
3101 
3102 #endif
3103 
3104  //
3105  // Query the local scan timeout
3106  //
3107 
3108  RtlInitUnicodeString( &valueName, L"LocalScanTimeout" );
3109 
3110  status = ZwQueryValueKey( driverRegKey,
3111  &valueName,
3113  value,
3114  valueLength,
3115  &resultLength );
3116 
3117  if (NT_SUCCESS( status )) {
3118 
3119  Globals.LocalScanTimeout = (LONGLONG)(*(PULONG)value->Data);
3120  }
3121 
3122  //
3123  // Query the network scan timeout
3124  //
3125 
3126  RtlInitUnicodeString( &valueName, L"NetworkScanTimeout" );
3127 
3128  status = ZwQueryValueKey( driverRegKey,
3129  &valueName,
3131  value,
3132  valueLength,
3133  &resultLength );
3134 
3135  if (NT_SUCCESS( status )) {
3136 
3137  Globals.NetworkScanTimeout = (LONGLONG)(*(PULONG)value->Data);
3138  }
3139 
3140  status = STATUS_SUCCESS;
3141 
3142 Cleanup:
3143 
3144  if (driverRegKey != NULL) {
3145 
3146  ZwClose( driverRegKey );
3147  }
3148 
3149  return status;
3150 }
3151 
3152 
FLT_PREOP_CALLBACK_STATUS AvPreFsControl(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
#define SET_FILE_TX_MODIFIED(_sCtx)
FLT_PREOP_CALLBACK_STATUS AvPreOperationCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
NTSTATUS AvScan(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ AV_SCAN_MODE ScanMode, _In_ UCHAR IOMajorFunctionAtScan, _In_ BOOLEAN IsInTxWriter, _Inout_ PAV_STREAM_CONTEXT StreamContext)
#define IRP_MJ_WRITE
Definition: mspyLog.h:288
LONGLONG NetworkScanTimeout
Definition: avscan.h:133
#define AV_INSTANCE_CONTEXT_SIZE
NTSTATUS AvPrepareServerPort(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ AVSCAN_CONNECTION_TYPE ConnectionType)
#define FS_SUPPORTS_FILE_STATE_CACHE(VolumeFilesystemType)
NTSTATUS AvLoadFileStateFromCache(_In_ PFLT_INSTANCE Instance, _In_ PAV_FILE_REFERENCE FileId, _Out_ LONG volatile *State, _Out_ PLONGLONG VolumeRevision, _Out_ PLONGLONG CacheRevision, _Out_ PLONGLONG FileRevision)
#define IS_FILE_MODIFIED(_sCtx)
_In_ PCWSTR valueName
Definition: ncinit.c:8
#define IRP_MJ_CLEANUP
Definition: mspyLog.h:302
RTL_GENERIC_COMPARE_ROUTINE AvCompareEntry
LONGLONG ScanId
Definition: avscan.h:60
VOID AvDoCancelScanAndRelease(_In_ PAV_SCAN_CONTEXT ScanContext, _In_ PAV_SECTION_CONTEXT SectionContext)
PAV_TRANSACTION_CONTEXT TxContext
FLT_FILESYSTEM_TYPE VolumeFSType
PFLT_INSTANCE FilterInstance
Definition: avscan.h:55
NTSTATUS AvProcessPreviousTransaction(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PAV_STREAM_CONTEXT StreamContext)
struct _AV_SECTION_CONTEXT * PAV_SECTION_CONTEXT
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
BOOLEAN AvIsPrefetchEcpPresent(_In_ PFLT_FILTER Filter, _In_ PFLT_CALLBACK_DATA Data)
NTSTATUS AvUnload(_Unreferenced_parameter_ FLT_FILTER_UNLOAD_FLAGS Flags)
enum _AV_FILE_INFECTED_STATE AV_FILE_INFECTED_STATE
NTSTATUS AvQueryTransactionOutcome(_In_ PKTRANSACTION Transaction, _Out_ PULONG TxOutcome)
CONST FLT_REGISTRATION FilterRegistration
BOOLEAN AvOperationsModifyingFile(_In_ PFLT_CALLBACK_DATA Data)
NTSTATUS AvSyncCache(_In_ PFLT_INSTANCE Instance, _In_ PAV_STREAM_CONTEXT StreamContext)
NTSTATUS AvScanAbortCallbackAsync(_Unreferenced_parameter_ PFLT_INSTANCE Instance, _In_ PFLT_CONTEXT Context, _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data)
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE Instance
Definition: nc.h:493
#define SET_FILE_NOT_INFECTED(_sCtx)
LONGLONG LocalScanTimeout
Definition: avscan.h:127
PFLT_PORT QueryServerPort
Definition: avscan.h:94
LIST_ENTRY ScanCtxListHead
Definition: avscan.h:115
NTSTATUS AvFinalizeScanAndSection(_Inout_ PAV_SCAN_CONTEXT ScanContext)
FORCEINLINE VOID AvPropagateFileState(_Inout_ PAV_STREAM_CONTEXT StreamContext, _In_ ULONG TransactionOutcome)
return TRUE
AV_SCANNER_GLOBAL_DATA Globals
Definition: avscan.h:152
RTL_GENERIC_ALLOCATE_ROUTINE AvAllocateGenericTableEntry
CONST FLT_OPERATION_REGISTRATION Callbacks[]
NTSTATUS AvFindOrCreateTransactionContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Outptr_ PAV_TRANSACTION_CONTEXT *TransactionContext)
#define AV_TXCTX_ENLISTED
NTSTATUS AvPostCreateCsvfs(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PAV_STREAM_CONTEXT StreamContext, _Out_ BOOLEAN *UpdateRevisionNumbers, _Out_ LONGLONG *VolumeRevisionPtr, _Out_ LONGLONG *CacheRevisionPtr, _Out_ LONGLONG *FileRevisionPtr)
Definition: csvfs.c:693
NTSTATUS AvFinalizeSectionContext(_Inout_ PAV_SECTION_CONTEXT SectionContext)
#define AV_TXCTX_LISTDRAINED
NTSTATUS AvGetFileSize(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Out_ PLONGLONG Size)
NcLoadRegistryStringRetry KeyValuePartialInformation
Definition: ncinit.c:53
NTSTATUS AvGetFileId(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Out_ PAV_FILE_REFERENCE FileId)
PFLT_FILTER Filter
Definition: avscan.h:86
NTSTATUS AvSetConfiguration(_In_ PUNICODE_STRING RegistryPath)
RTL_GENERIC_FREE_ROUTINE AvFreeGenericTableEntry
NTSTATUS AvScanInKernel(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ UCHAR IOMajorFunctionAtScan, _In_ BOOLEAN IsInTxWriter, _In_ PAV_STREAM_CONTEXT StreamContext)
Definition: scan.c:220
RTL_GENERIC_TABLE FileStateCacheTable
struct _AV_FILE_REFERENCE::@0 FileId64
NTSTATUS AvSendAbortToUser(_In_ ULONG ScanThreadId, _In_ LONGLONG ScanId)
#define SET_FILE_MODIFIED(_sCtx)
PFLT_PORT ScanServerPort
Definition: avscan.h:92
NTSTATUS AvSendUnloadingToUser(VOID)
VOID AvInstanceTeardownComplete(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
enum _AV_SCAN_MODE AV_SCAN_MODE
const FLT_CONTEXT_REGISTRATION ContextRegistration[]
#define IRP_MJ_SET_INFORMATION
Definition: mspyLog.h:290
#define FlagOn(_F, _SF)
Definition: minispy.h:247
#define IS_FILE_INFECTED(_sCtx)
#define LIST_FOR_EACH_SAFE(curr, n, head)
#define AV_FLAG_PREFETCH
NTSTATUS AvProcessTransactionOutcome(_Inout_ PAV_TRANSACTION_CONTEXT TransactionContext, _In_ ULONG TransactionOutcome)
UNREFERENCED_PARAMETER(FileObject)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NTSTATUS AvCreateStreamContext(_In_ PFLT_FILTER Filter, _Outptr_ PAV_STREAM_CONTEXT *StreamContext)
LONGLONG ScanIdCounter
Definition: avscan.h:79
NTSTATUS AvGetFileEncrypted(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Out_ PBOOLEAN Encrypted)
BOOLEAN AvIsCsvDlEcpPresent(_In_ PFLT_FILTER Filter, _In_ PFLT_CALLBACK_DATA Data)
Definition: csvfs.c:578
NTSTATUS AvCreateStreamHandleContext(_In_ PFLT_FILTER Filter, _Outptr_ PAV_STREAMHANDLE_CONTEXT *StreamHandleContext)
struct _AV_TRANSACTION_CONTEXT * PAV_TRANSACTION_CONTEXT
FLT_POSTOP_CALLBACK_STATUS AvPostCreate(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
BOOLEAN AvIsVolumeOnCsvDisk(_In_ PFLT_VOLUME Volume)
Definition: csvfs.c:162
PAGED_CODE()
#define IRP_MJ_FILE_SYSTEM_CONTROL
Definition: mspyLog.h:297
AV_FILE_REFERENCE FileId
#define AV_GENERIC_TABLE_ENTRY_SIZE
ULONG ScanThreadId
Definition: avscan.h:61
NTSTATUS AvPreCreateCsvfs(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects)
Definition: csvfs.c:628
DRIVER_INITIALIZE DriverEntry
Definition: filter/avscan.c:30
ERESOURCE ScanCtxListLock
Definition: avscan.h:121
FLT_PREOP_CALLBACK_STATUS AvPreCleanup(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
AVSCAN_MESSAGE Message
Definition: avlib.h:140
VOID AvInstanceTeardownStart(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Unreferenced_parameter_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
NTSTATUS AvPreCleanupCsvfs(_Unreferenced_parameter_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PAV_STREAM_CONTEXT StreamContext, _Out_ BOOLEAN *UpdateRevisionNumbers, _Out_ LONGLONG *VolumeRevisionPtr, _Out_ LONGLONG *CacheRevisionPtr, _Out_ LONGLONG *FileRevisionPtr)
Definition: csvfs.c:864
#define IS_FILE_NEED_SCAN(_sCtx)
BOOLEAN AvIsStreamAlternate(_Inout_ PFLT_CALLBACK_DATA Data)
NTSTATUS AvKtmNotificationCallback(_Unreferenced_parameter_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PFLT_CONTEXT TransactionContext, _In_ ULONG TransactionNotification)
NTSTATUS AvInstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
PFLT_PORT AbortClientPort
Definition: avscan.h:106
NTSTATUS AvInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
FORCEINLINE VOID AvCancelFileOpen(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ NTSTATUS Status)
Definition: avscan.h:178
FLT_PREOP_CALLBACK_STATUS AvPreCreate(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
PFLT_PORT AbortServerPort
Definition: avscan.h:93
#define AV_INVALID_FILE_REFERENCE(_fileid_)
NTSTATUS AvScanInUser(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ UCHAR IOMajorFunctionAtScan, _In_ BOOLEAN IsInTxWriter, _In_ DEVICE_TYPE DeviceType)
Definition: scan.c:337
#define AV_SET_INVALID_FILE_REFERENCE(_fileid_)
_In_opt_ PFILE_OBJECT FileObject
Definition: nc.h:493
#define AV_DBG_PRINT(_dbgLevel, _string)
Definition: avscan.h:172
#define IRP_MJ_CREATE
Definition: mspyLog.h:284
LONGLONG ScanId
Definition: avlib.h:153

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com