WDK Mini Filter Example
communication.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 2011 Microsoft Corporation
4 
5 Module Name:
6 
7  communication.c
8 
9 Abstract:
10 
11  Communication module implementation.
12  This module contains the routines that involves the communication
13  between kernel mode and user mode.
14 
15 Environment:
16 
17  Kernel mode
18 
19 --*/
20 
21 #include "avscan.h"
22 
23 NTSTATUS
25  _In_ PFLT_PORT ClientPort,
26  _In_ PVOID ServerPortCookie,
27  _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext,
28  _In_ ULONG SizeOfContext,
29  _Outptr_result_maybenull_ PVOID *ConnectionCookie
30  );
31 
32 VOID
34  _In_opt_ PVOID ConnectionCookie
35  );
36 
37 NTSTATUS
39  _In_ PVOID ConnectionCookie,
40  _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer,
41  _In_ ULONG InputBufferSize,
42  _Out_writes_bytes_to_opt_(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
43  _In_ ULONG OutputBufferSize,
44  _Out_ PULONG ReturnOutputBufferLength
45  );
46 
47 //
48 // Local routines
49 //
50 
51 NTSTATUS
53  _In_ LONGLONG ScanId,
54  _Out_ PAV_SCAN_CONTEXT *ScanCtx
55  );
56 
57 NTSTATUS
59  _In_ PFLT_VOLUME volumeObject,
60  _Out_ PAV_INSTANCE_CONTEXT *InstanceContext
61  );
62 
63 NTSTATUS
65  _In_ HANDLE Handle,
66  _Out_ PAV_INSTANCE_CONTEXT *InstanceContext
67  );
68 
69 NTSTATUS
71  _In_ HANDLE Handle,
72  _Out_ PAV_STREAM_CONTEXT *StreamContext
73  );
74 
75 NTSTATUS
77  _Inout_ PAV_STREAM_CONTEXT StreamContext,
78  _In_ PAV_SCAN_CONTEXT ScanContext,
79  _In_ AVSCAN_RESULT ScanResult
80  );
81 
82 NTSTATUS
84  _Inout_ PAV_SCAN_CONTEXT ScanContext,
85  _Out_ PHANDLE SectionHandle
86  );
87 
88 NTSTATUS
90  _Inout_ PAV_SCAN_CONTEXT ScanContext,
91  _In_ AVSCAN_RESULT ScanResult
92  );
93 
94 #ifdef ALLOC_PRAGMA
95  #pragma alloc_text(PAGE, AvMessageNotifyCallback)
96  #pragma alloc_text(PAGE, AvConnectNotifyCallback)
97  #pragma alloc_text(PAGE, AvDisconnectNotifyCallback)
98  #pragma alloc_text(PAGE, AvPrepareServerPort)
99 
100  #pragma alloc_text(PAGE, AvGetInstanceContextByVolume)
101  #pragma alloc_text(PAGE, AvGetInstanceContextByFileHandle)
102  #pragma alloc_text(PAGE, AvGetStreamContextByHandle)
103  #pragma alloc_text(PAGE, AvUpdateStreamContextWithScanResult)
104  #pragma alloc_text(PAGE, AvFinalizeScanAndSection)
105  #pragma alloc_text(PAGE, AvFinalizeScanContext)
106  #pragma alloc_text(PAGE, AvFinalizeSectionContext)
107  #pragma alloc_text(PAGE, AvHandleCmdCreateSectionForDataScan)
108  #pragma alloc_text(PAGE, AvHandleCmdCloseSectionForDataScan)
109 #endif
110 
111 NTSTATUS
113  _In_ PFLT_PORT ClientPort,
114  _In_ PVOID ServerPortCookie,
115  _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext,
116  _In_ ULONG SizeOfContext,
117  _Outptr_result_maybenull_ PVOID *ConnectionCookie
118  )
119 /*++
120 
121 Routine Description
122 
123  Communication connection callback routine.
124  This is called when user-mode connects to the server port.
125 
126 Arguments
127 
128  ClientPort - This is the client connection port that will be used to send messages from the filter
129 
130  ServerPortCookie - Unused
131 
132  ConnectionContext - The connection context passed from the user. This is to recognize which type
133  connection the user is trying to connect.
134 
135  SizeofContext - The size of the connection context.
136 
137  ConnectionCookie - Propagation of the connection context to disconnection callback.
138 
139 Return Value
140 
141  STATUS_SUCCESS - to accept the connection
142  STATUS_INSUFFICIENT_RESOURCES - if memory is not enough
143  STATUS_INVALID_PARAMETER_3 - Connection context is not valid.
144 --*/
145 {
146  PAV_CONNECTION_CONTEXT connectionCtx = (PAV_CONNECTION_CONTEXT) ConnectionContext;
147  PAVSCAN_CONNECTION_TYPE connectionCookie = NULL;
148 
149  PAGED_CODE();
150 
151  UNREFERENCED_PARAMETER( ServerPortCookie );
152  UNREFERENCED_PARAMETER( SizeOfContext );
153 
154  if (NULL == connectionCtx) {
155 
156  return STATUS_INVALID_PARAMETER_3;
157  }
158 
159  //
160  // ConnectionContext passed in may be deleted. We need to make a copy of it.
161  //
162 
163  connectionCookie = ExAllocatePoolWithTag( PagedPool,
164  sizeof(AVSCAN_CONNECTION_TYPE),
166  if (NULL == connectionCookie) {
167 
168  return STATUS_INSUFFICIENT_RESOURCES;
169  }
170 
171  *connectionCookie = connectionCtx->Type;
172  switch (connectionCtx->Type) {
173  case AvConnectForScan:
174  Globals.ScanClientPort = ClientPort;
175  *ConnectionCookie = connectionCookie;
176  break;
177  case AvConnectForAbort:
178  Globals.AbortClientPort = ClientPort;
179  *ConnectionCookie = connectionCookie;
180  break;
181  case AvConnectForQuery:
182  Globals.QueryClientPort = ClientPort;
183  *ConnectionCookie = connectionCookie;
184  break;
185  default:
186  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
187  ("[AV]: AvConnectNotifyCallback: No such connection type. \n") );
188  ExFreePoolWithTag( connectionCookie,
190  *ConnectionCookie = NULL;
191  return STATUS_INVALID_PARAMETER_3;
192  }
193 
194  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
195  ("[AV]: AvConnectNotifyCallback entered. type: %d \n", connectionCtx->Type) );
196 
197  return STATUS_SUCCESS;
198 }
199 
200 VOID
202  _In_opt_ PVOID ConnectionCookie
203  )
204 /*++
205 
206 Routine Description
207 
208  Communication disconnection callback routine.
209  This is called when user-mode disconnects the server port.
210 
211 Arguments
212 
213  ConnectionCookie - The cookie set in AvConnectNotifyCallback(...). It is connection context.
214 
215 Return Value
216 
217  None
218 --*/
219 {
220  PAVSCAN_CONNECTION_TYPE connectionType = (PAVSCAN_CONNECTION_TYPE) ConnectionCookie;
221 
222  PAGED_CODE();
223 
224  if (NULL == connectionType) {
225 
226  return;
227  }
228  //
229  // Close communication handle
230  //
231  switch (*connectionType) {
232  case AvConnectForScan:
233  FltCloseClientPort( Globals.Filter, &Globals.ScanClientPort );
235  break;
236  case AvConnectForAbort:
237  FltCloseClientPort( Globals.Filter, &Globals.AbortClientPort );
239  break;
240  case AvConnectForQuery:
241  FltCloseClientPort( Globals.Filter, &Globals.QueryClientPort );
243  break;
244  default:
245  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
246  ("[AV]: AvDisconnectNotifyCallback: No such connection type. \n") );
247  return;
248  }
249 
250  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
251  ("[AV]: AvDisconnectNotifyCallback entered. type: %d \n", *connectionType) );
252 
253  ExFreePoolWithTag( connectionType,
255 
256 }
257 
258 NTSTATUS
260  _In_ LONGLONG ScanId,
261  _Out_ PAV_SCAN_CONTEXT *ScanCtx
262  )
263 /*++
264 
265 Routine Description
266 
267  A helper function to retrieve the scan context from its scan context id.
268  It is synchronized by a lock.
269 
270 Arguments
271 
272  ScanId - The scan id to be found.
273  ScanCtx - The output scan context. NULL if not found
274 
275 Return Value
276 
277  STATUS_SUCCESS - if found.
278  Otherwise - Error, or if not found.
279 
280 --*/
281 {
282  PLIST_ENTRY link;
283  NTSTATUS status = STATUS_SUCCESS;
284  BOOLEAN found = FALSE;
285  PAV_SCAN_CONTEXT scanCtx = NULL;
286 
287  //
288  // We only 'read' the scan context when we traversing the list
289  //
290 
291  AvAcquireResourceShared( &Globals.ScanCtxListLock );
292 
293  for (link = Globals.ScanCtxListHead.Flink;
294  link != &Globals.ScanCtxListHead;
295  link = link->Flink) {
296 
297  scanCtx = CONTAINING_RECORD( link, AV_SCAN_CONTEXT, List );
298 
299  if (scanCtx->ScanId == ScanId) {
300  found = TRUE;
301  AvReferenceScanContext( scanCtx );
302  break;
303  }
304 
305  }
306 
307  AvReleaseResource( &Globals.ScanCtxListLock );
308 
309  if (found) {
310 
311  *ScanCtx = scanCtx;
312  return STATUS_SUCCESS;
313  }
314 
315  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
316  ("[AV] AvGetScanCtxSynchronized: scan context not found. \n") );
317 
318  *ScanCtx = NULL;
319 
320  if (NT_SUCCESS( status )){
321 
322  status = STATUS_UNSUCCESSFUL;
323  }
324 
325  return status;
326 }
327 
328 NTSTATUS
330  _In_ PFLT_VOLUME VolumeObject,
331  _Out_ PAV_INSTANCE_CONTEXT *InstanceContext
332  )
333 /*++
334 
335 Routine Description
336 
337  A helper function to retrieve the instance context from its volume object.
338 
339  The caller is responsible for dereference InstanceContext via calling
340  FltReleaseContext(...) if success.
341 
342 Arguments
343 
344  VolumeObject - The volume object.
345  InstanceContext - The output instance context. NULL if not found
346 
347 Return Value
348 
349  STATUS_SUCCESS - if found.
350  Otherwise - Error, or not found.
351 --*/
352 {
353  ULONG i;
354  NTSTATUS status = STATUS_SUCCESS;
355  BOOLEAN found = FALSE;
356  PFLT_INSTANCE *instArray = NULL;
357  ULONG instCnt = 0;
358  PAV_INSTANCE_CONTEXT instCtx = NULL;
359 
360  PAGED_CODE();
361 
362  status = AvEnumerateInstances ( &instArray, &instCnt );
363 
364  if ( !NT_SUCCESS(status) ) {
365 
366  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
367  ("[AV] AvGetInstanceContextByVolume: Failed to enumerate instances. \n") );
368  return status;
369  }
370 
371  for (i = 0; i < instCnt; i++) {
372 
373  status = FltGetInstanceContext( instArray[i], &instCtx );
374 
375  if ( !NT_SUCCESS(status) ) {
376 
377  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
378  ("[AV] AvGetInstanceContextByVolume: Failed to get instance context. \n") );
379  break;
380  }
381 
382  if (instCtx->Volume == VolumeObject) {
383 
384  //
385  // When found, we do not release the reference of instance context
386  // because the caller is responsible for releasing it.
387  //
388 
389  found = TRUE;
390  break;
391  }
392 
393  FltReleaseContext( instCtx );
394  }
395 
396  AvFreeInstances( instArray, instCnt );
397  instArray = NULL;
398 
399  if (found) {
400 
401  *InstanceContext = instCtx;
402  return STATUS_SUCCESS;
403  }
404 
405  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
406  ("[AV] AvGetInstanceContextByVolume: instance context not found. \n") );
407 
408  if ( NT_SUCCESS( status ) ){
409 
410  status = STATUS_UNSUCCESSFUL;
411  }
412 
413  instCtx = NULL;
414 
415  return status;
416 }
417 
418 NTSTATUS
420  _In_ HANDLE Handle,
421  _Out_ PAV_INSTANCE_CONTEXT *InstanceContext
422  )
423 /*++
424 
425 Routine Description
426 
427  A helper function to retrieve the instance context from file handle.
428 
429  The caller is responsible for dereference InstanceContext via calling
430  FltReleaseContext(...) if success.
431 
432 Arguments
433 
434  Handle - The file handle of interest.
435  InstanceContext - The output instance context. NULL if not found
436 
437 Return Value
438 
439  STATUS_SUCCESS - if found.
440  Otherwise - if not found; it will report the corresponding status.
441 --*/
442 {
443  NTSTATUS status = STATUS_SUCCESS;
444  PFILE_OBJECT fileObject = NULL;
445  PFLT_VOLUME volumeObject = NULL;
446 
447  PAGED_CODE();
448 
449  //
450  // Get file object by handle
451  //
452 
453  status = ObReferenceObjectByHandle (
454  Handle,
455  0,
456  *IoFileObjectType,
457  KernelMode,
458  (PVOID *)&fileObject,
459  NULL
460  );
461  if (!NT_SUCCESS(status)) {
462 
463  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
464  ("[AV] AvGetInstanceContextByFileHandle: Failed to get file object by handle. \n") );
465  return status;
466  }
467 
468  try {
469 
470  status = FltGetVolumeFromFileObject( Globals.Filter,
471  fileObject,
472  &volumeObject );
473 
474  if (!NT_SUCCESS(status)) {
475  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
476  ("[AV] AvGetInstanceContextByFileHandle: Failed to get volume by file object. \n") );
477  leave;
478  }
479 
480  status = AvGetInstanceContextByVolume(volumeObject, InstanceContext);
481 
482  FltObjectDereference( volumeObject );
483 
484  } finally {
485 
486  ObDereferenceObject( fileObject );
487  }
488 
489  return status;
490 }
491 
492 NTSTATUS
494  _In_ HANDLE Handle,
495  _Out_ PAV_STREAM_CONTEXT *StreamContext
496  )
497 /*++
498 
499 Routine Description
500 
501  A helper function to retrieve the stream context from a file handle at message
502  callback routine. This function will increment the reference count of the
503  output stream context.
504 
505  The caller is responsible for dereference it via calling FltReleaseContext(...)
506  if success.
507 
508 Arguments
509 
510  Handle - The file handle of interest.
511  StreamContext - The output stream context. NULL if not found
512 
513 Return Value
514 
515  STATUS_SUCCESS - if found.
516  Otherwise - if not found; it will report the corresponding status.
517 --*/
518 {
519  NTSTATUS status;
520  PFILE_OBJECT fileObject = NULL;
521  PAV_INSTANCE_CONTEXT instanceContext = NULL;
522 
523  PAGED_CODE();
524 
525  status = AvGetInstanceContextByFileHandle( Handle, &instanceContext);
526 
527  if (!NT_SUCCESS(status)) {
528 
529  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
530  ("[AV]: ***AvGetInstanceContextByFileHandle FAILED. \n") );
531  return status;
532  }
533  try {
534 
535  status = ObReferenceObjectByHandle (
536  Handle,
537  0,
538  *IoFileObjectType,
539  KernelMode,
540  (PVOID *)&fileObject,
541  NULL
542  );
543  if (!NT_SUCCESS(status)) {
544 
545  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
546  ("[AV] AvGetStreamContextByHandle: Failed to get file object by handle. \n") );
547  leave;
548  }
549 
550  status = FltGetStreamContext( instanceContext->Instance,
551  fileObject,
552  StreamContext );
553 
554  ObDereferenceObject( fileObject );
555 
556  } finally {
557 
558  FltReleaseContext( instanceContext );
559  }
560  return status;
561 }
562 
563 NTSTATUS
565  _Inout_ PAV_SCAN_CONTEXT ScanContext,
566  _Out_ PHANDLE SectionHandle
567  )
568 /*++
569 
570 Routine Description:
571 
572  This function handles CmdCreateSectionForDataScan message.
573  This function will create and return the section handle to the caller.
574  If any error occurs, it will trigger events to release the waiting threads.
575 
576  NOTE: this function does not check the buffer size etc.
577  It must be checked before passing into this function.
578 
579 Arguments:
580 
581  ScanContext - The scan context.
582  ScanThreadId - The thread ID of the thread doing the scan
583  SectionHandle - receives the section handle
584 
585 Return Value:
586 
587  Returns the status of processing the message.
588 
589 --*/
590 {
591  NTSTATUS status = STATUS_SUCCESS;
592  PAV_STREAM_CONTEXT streamContext = NULL;
593  PAV_SECTION_CONTEXT sectionContext = NULL;
594  HANDLE sectionHandle = NULL;
595 
596  PAGED_CODE();
597 
598  status = FltGetStreamContext ( ScanContext->FilterInstance,
599  ScanContext->FileObject,
600  &streamContext );
601 
602  if (!NT_SUCCESS( status )) {
603 
604  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
605  ("[AV] AvHandleCmdCreateSectionForDataScan: failed to get stream context.\n") );
606 
607  goto Cleanup;
608  }
609 
610  //
611  // It should be impossible for the stream state to change from
612  // uknown to clean since we kicked off this scan.
613  //
614 
615  ASSERT(IS_FILE_NEED_SCAN( streamContext ));
616 
617  status = AvCreateSectionContext( ScanContext->FilterInstance,
618  ScanContext->FileObject,
619  &sectionContext);
620 
621  if (!NT_SUCCESS( status )) {
622 
623  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
624  ("[AV] AvHandleCmdCreateSectionForDataScan: failed to create section context.\n") );
625 
626  goto Cleanup;
627  }
628 
629  //
630  // Before we are going to create section object, if this flag is set (by the thread that requests for scan),
631  // it means that the thread is trying to cancel this scan, and thus we don't want the scan to proceed anymore.
632  //
633  if (ScanContext->IoWaitOnScanCompleteNotificationAborted) {
634 
635  status = STATUS_CANCELLED;
636  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
637  ("[AV] AvHandleCmdCreateSectionForDataScan: Before FltCreateSectionForDataScan, it found Io is trying to abort the wait.\n") );
638 
639  goto Cleanup;
640  }
641 
642  sectionContext->ScanContext = ScanContext;
643  sectionContext->CancelableOnConflictingIo = (ScanContext->IOMajorFunctionAtScan == IRP_MJ_CLEANUP);
644 
645  //
646  // Note: the section conflict callback could be called before
647  // this routine returns. It is even possible that the context
648  // passed to the callback won't have the SectionHandle and
649  // SectionObject fields set yet.
650  //
651 
652  status = FltCreateSectionForDataScan( ScanContext->FilterInstance,
653  ScanContext->FileObject,
654  sectionContext,
655  SECTION_MAP_READ,
656  NULL,
657  NULL,
658  PAGE_READONLY,
659  SEC_COMMIT,
660  0,
661  &sectionContext->SectionHandle,
662  &sectionContext->SectionObject,
663  NULL );
664 
665  sectionHandle = sectionContext->SectionHandle;
666 
667  if (!NT_SUCCESS( status )) {
668 
669 #if DBG
670  NTSTATUS sta = STATUS_SUCCESS;
671  PFLT_VOLUME volumeObject = NULL;
672  ULONG length = 0;
673  UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES)+256]; //enough space for names
674  PFLT_VOLUME_PROPERTIES property = (PFLT_VOLUME_PROPERTIES)volPropBuffer;
675 
676  sta = FltGetVolumeFromFileObject( Globals.Filter,
677  ScanContext->FileObject,
678  &volumeObject );
679  if (NT_SUCCESS( sta )) {
680  sta = FltGetVolumeProperties( volumeObject,
681  property,
682  sizeof(volPropBuffer),
683  &length );
684  if (NT_SUCCESS( sta )) {
685  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
686  ("[AV] ############## %wZ, %wZ, %wZ\n",
687  property->FileSystemDriverName,
688  property->FileSystemDeviceName,
689  property->RealDeviceName) );
690  }
691  FltObjectDereference( volumeObject );
692  }
693 
694  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
695  ("[AV] AvHandleCmdCreateSectionForDataScan: %I64x,%I64x failed to create section object. 0x%x\n",
696  streamContext->FileId.FileId64.UpperZeroes,
697  streamContext->FileId.FileId64.Value,
698  sta) );
699 #endif // DBG
700 
701  goto Cleanup;
702  }
703 
704  //
705  // Before scanning, we set the file status as scanning.
706  // This is important when another thread is writing to this file while we are scanning
707  // this file.
708  //
709 
710  SET_FILE_SCANNING_EX( ScanContext->IsFileInTxWriter, streamContext );
711 
712  //
713  // Only after the section object is successfully created, we put a section context pointer
714  // into the scan context.
715  //
716 
717  FltReferenceContext( sectionContext );
718  ScanContext->SectionContext = sectionContext;
719 
720  *SectionHandle = sectionHandle;
721 
722 Cleanup:
723 
724  //
725  // The I/O request thread is waiting for this event.
726  // If any error occurs, we have to release the waiting thread.
727  // if status is a success code, the thread will get released when
728  // the user send message to close the section object.
729  //
730 
731  if (!NT_SUCCESS( status )) {
732 
733  KeSetEvent( &ScanContext->ScanCompleteNotification, 0, FALSE );
734  }
735 
736  if (streamContext) {
737 
738  //
739  // On error signal the event to release any threads waiting to
740  // scan the same file. On success it will get released when the
741  // message is sent to close the section object.
742  //
743 
744  if (!NT_SUCCESS( status )) {
745 
746  SET_FILE_MODIFIED_EX( ScanContext->IsFileInTxWriter, streamContext );
747  }
748 
749  FltReleaseContext( streamContext );
750  streamContext = NULL;
751  }
752 
753  if (sectionContext) {
754 
755  FltReleaseContext( sectionContext );
756  sectionContext = NULL;
757  }
758 
759  //
760  // After this routine assigned section context into scan context and created sectionHandle,
761  // we need to check if notification abort flag was set, if it was, we need to fail the section creation
762  // because at this point, the request for scan was abondaned anyway, we 'stop' the scan by
763  // returning STATUS_CANCELLED to the user.
764  //
765  if (NT_SUCCESS( status ) &&
766  ScanContext->IoWaitOnScanCompleteNotificationAborted) {
767 
768  status = STATUS_CANCELLED;
769  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
770  ("[AV] AvHandleCmdCreateSectionForDataScan: After FltCreateSectionForDataScan, it found Io is trying to abort the wait.\n") );
771 
772  //
773  // We explicitly call NtClose() instead of ZwClose() so that PreviousMode() will be User.
774  // This prevents accidental closing of a kernel handle and also will not bugcheck the
775  // system if the handle value is no longer valid
776  //
777  NtClose( sectionHandle );
778 
779  //
780  // This user mode handle is supposed to be closed in the user mode program.
781  // We close in the context of the same process context.
782  //
783  AvFinalizeScanAndSection( ScanContext );
784  }
785 
786  return status;
787 }
788 
789 
790 NTSTATUS
792  _Inout_ PAV_STREAM_CONTEXT StreamContext,
793  _In_ PAV_SCAN_CONTEXT ScanContext,
794  _In_ AVSCAN_RESULT ScanResult
795  )
796 /*++
797 
798 Routine Description:
799 
800  This function updates StreamContex according to ScanResult.
801  e.g. Set the stream as modified, infected, etc.
802 
803 Arguments:
804 
805  StreamContext - The stream context to be updated.
806 
807  ScanContext - The scan context.
808 
809  ScanResult - The scan result. Please see the definition of AVSCAN_RESULT.
810 
811 Return Value:
812 
813  Returns STATUS_SUCCESS.
814 
815 --*/
816 {
817  NTSTATUS status = STATUS_SUCCESS;
818 
819  PAGED_CODE();
820 
821  switch( ScanResult ) {
822 
824  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
825  ("***[AV] AvUpdateScanResult: the caller did not specify the scan result.\n") );
826  //
827  // If for some reason, the scan result returns undetermined, we have to
828  // set the file state back to AvFileModifed.
829  //
830 
831  SET_FILE_MODIFIED_EX( ScanContext->IsFileInTxWriter, StreamContext);
832  break;
834  //
835  // If after the scan and before setting this file as clean, the file gets modified,
836  // then we have to leave it as modified.
837  //
838 
839  if (ScanContext->IsFileInTxWriter) {
840 
841  InterlockedCompareExchange( &StreamContext->TxState, AvFileInfected, AvFileScanning );
842 
843  } else {
844 
845  InterlockedCompareExchange( &StreamContext->State, AvFileInfected, AvFileScanning );
846  }
847  break;
848  case AvScanResultClean:
849 
850  //
851  // If after the scan and before setting this file as clean, the file gets modified,
852  // then we have to leave it as modified.
853  //
854 
855  if (ScanContext->IsFileInTxWriter) {
856 
857  InterlockedCompareExchange( &StreamContext->TxState, AvFileNotInfected, AvFileScanning );
858 
859  } else {
860 
861  InterlockedCompareExchange( &StreamContext->State, AvFileNotInfected, AvFileScanning );
862  }
863 
864  break;
865  default:
866  FLT_ASSERTMSG( "No such scan result.\n", FALSE);
867  break;
868  }
869 
870  return status;
871 }
872 
873 NTSTATUS
875  _Inout_ PAV_SCAN_CONTEXT ScanContext
876  )
877 /*++
878 
879 Routine Description:
880 
881  This function is a wrapper function to finalize scan context and section context.
882  Normally, you should call this function if you don't need to use section context before
883  closing it.
884 
885 Arguments:
886 
887  ScanContext - The scan context.
888 
889 Return Value:
890 
891  Returns the status code from FltCloseSectionForDataScan.
892 
893 --*/
894 {
895  NTSTATUS status = STATUS_SUCCESS;
896  PAV_SECTION_CONTEXT sectionContext = NULL;
897 
898  PAGED_CODE();
899 
900  AvFinalizeScanContext( ScanContext, &sectionContext );
901 
902  //
903  // This thread won the race, and is responsible for finalizing the section context
904  //
905  if (sectionContext != NULL) {
906 
907  status = AvFinalizeSectionContext( sectionContext );
908  }
909  return status;
910 }
911 
912 VOID
914  _Inout_ PAV_SCAN_CONTEXT ScanContext,
915  _Outptr_result_maybenull_ PAV_SECTION_CONTEXT *SectionContext
916  )
917 /*++
918 
919 Routine Description:
920 
921  This function interlocked-exchange the section context inside the scan context and
922  release the waiting I/O request thread.
923 
924  The caller is responsible for releasing the reference count of SectionContext
925  when it successfully exchanges a non-NULL section context.
926 
927 Arguments:
928 
929  ScanContext - The scan context.
930 
931  SectionContext - Receives the sectioncontext address indicating the caller is
932  responsible for tearing down the sectioncontext.
933  Receives NULL if the context is already being torn down by another thread.
934 
935 Return Value:
936 
937  None.
938 
939 --*/
940 {
941  PAV_SECTION_CONTEXT oldSectionCtx = NULL;
942 
943  PAGED_CODE();
944 
945  *SectionContext = NULL;
946 
947  //
948  // Synchronization between AvInstanceTeardownStart(...) or timeout
949  // processing in the IO thread.
950  //
951 
952  oldSectionCtx = InterlockedExchangePointer( &ScanContext->SectionContext, NULL );
953 
954  //
955  // If sectionContext is NULL, it means that another thread has
956  // already begun teardown of the section.
957  //
958 
959  if (oldSectionCtx) {
960 
961  //
962  // The caller is responsible for releasing the reference count when assigned in ScanContext.
963  //
964  *SectionContext = oldSectionCtx;
965  }
966 
967  //
968  // The I/O request thread is waiting for this event.
969  //
970 
971  KeSetEvent( &ScanContext->ScanCompleteNotification, 0, FALSE );
972 }
973 
974 NTSTATUS
976  _Inout_ PAV_SECTION_CONTEXT SectionContext
977  )
978 /*++
979 
980 Routine Description:
981 
982  This function is a wrapper function to finalize section context.
983  It closes the section context/object and release its reference.
984 
985 Arguments:
986 
987  SectionContext - The section context.
988 
989 Return Value:
990 
991  Returns the status code from FltCloseSectionForDataScan.
992 
993 --*/
994 
995 {
996  NTSTATUS status = STATUS_SUCCESS;
997 
998  PAGED_CODE();
999 
1000  status = AvCloseSectionForDataScan( SectionContext );
1001 
1002  if (!NT_SUCCESS(status)) {
1003 
1004  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1005  ("***[AV]: AvFinalizeSectionContext: Close section failed.\n") );
1006  }
1007  FltReleaseContext( SectionContext );
1008  return status;
1009 }
1010 
1011 NTSTATUS
1013  _Inout_ PAV_SCAN_CONTEXT ScanContext,
1014  _In_ AVSCAN_RESULT ScanResult
1015  )
1016 /*++
1017 
1018 Routine Description:
1019 
1020  This function handles AvCmdCloseSectionForDataScan message.
1021  This function will
1022 
1023  1) close the section object
1024  2) Set the file clean or infected.
1025  3) trigger events to release the waiting threads.
1026 
1027 Arguments:
1028 
1029  ScanContext - The scan context.
1030 
1031  ScanResult - The scan result. Please see the definition of AVSCAN_RESULT.
1032 
1033 Return Value:
1034 
1035  Returns the status of processing the message.
1036 
1037 --*/
1038 {
1039  NTSTATUS status = STATUS_SUCCESS;
1040  PAV_STREAM_CONTEXT streamContext = NULL;
1041 
1042  PAGED_CODE();
1043 
1044  status = FltGetStreamContext ( ScanContext->FilterInstance,
1045  ScanContext->FileObject,
1046  &streamContext );
1047 
1048  if (!NT_SUCCESS( status )) {
1049 
1050  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1051  ("***[AV] AvHandleCmdCloseSectionForDataScan: failed to get stream context.\n") );
1052 
1053  goto Cleanup;
1054  }
1055 
1056  //
1057  // Update stream context will succeed.
1058  //
1059  AvUpdateStreamContextWithScanResult(streamContext, ScanContext, ScanResult);
1060 
1061 Cleanup:
1062 
1063  status = AvFinalizeScanAndSection( ScanContext );
1064 
1065  //
1066  // Either the above operations are successful, or any error occur,
1067  // we have to release the stream context.
1068  //
1069 
1070  if ( streamContext ) {
1071 
1072  FltReleaseContext( streamContext );
1073  }
1074 
1075  return status;
1076 
1077 }
1078 
1079 NTSTATUS
1081  _In_ PVOID ConnectionCookie,
1082  _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer,
1083  _In_ ULONG InputBufferSize,
1084  _Out_writes_bytes_to_opt_(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
1085  _In_ ULONG OutputBufferSize,
1086  _Out_ PULONG ReturnOutputBufferLength
1087  )
1088 /*++
1089 
1090 Routine Description:
1091 
1092  This routine is called whenever the user program sends message to
1093  filter via FilterSendMessage(...).
1094 
1095  The user space scanner sends message to
1096 
1097  1) Create the section for data scan
1098  2) Close the section for data scan
1099  3) Set a certain file to be infected
1100  4) Query the file state of a file
1101 
1102 Arguments:
1103 
1104  InputBuffer - A buffer containing input data, can be NULL if there
1105  is no input data.
1106 
1107  InputBufferSize - The size in bytes of the InputBuffer.
1108 
1109  OutputBuffer - A buffer provided by the application that originated
1110  the communication in which to store data to be returned to the
1111  application.
1112 
1113  OutputBufferSize - The size in bytes of the OutputBuffer.
1114 
1115  ReturnOutputBufferSize - The size in bytes of meaningful data
1116  returned in the OutputBuffer.
1117 
1118 Return Value:
1119 
1120  Returns the status of processing the message.
1121 
1122 --*/
1123 {
1124  NTSTATUS status = STATUS_SUCCESS;
1125  AVSCAN_COMMAND command;
1126  HANDLE hFile = NULL;
1127  LONGLONG scanId = 0;
1128  PAV_SCAN_CONTEXT scanContext = NULL;
1130  PAV_STREAM_CONTEXT streamContext;
1131  HANDLE sectionHandle;
1132 
1133  PAGED_CODE();
1134 
1135  UNREFERENCED_PARAMETER( ConnectionCookie );
1136 
1137  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
1138  ("[AV]: AvMessageNotifyCallback entered. \n") );
1139 
1140 
1141  if ((InputBuffer == NULL) ||
1142  (InputBufferSize < (FIELD_OFFSET(COMMAND_MESSAGE, Command) +
1143  sizeof(AVSCAN_COMMAND)))) {
1144 
1145  return STATUS_INVALID_PARAMETER;
1146  }
1147 
1148  try {
1149 
1150  //
1151  // Probe and capture input message: the message is raw user mode
1152  // buffer, so need to protect with exception handler
1153  //
1154 
1155  command = ((PCOMMAND_MESSAGE) InputBuffer)->Command;
1156  scanId = ((PCOMMAND_MESSAGE) InputBuffer)->ScanId;
1157 
1158  } except (AvExceptionFilter( GetExceptionInformation(), TRUE )) {
1159 
1160  return GetExceptionCode();
1161  }
1162 
1163  //
1164  // Only
1165  // AvCmdCreateSectionForDataScan
1166  // AvCmdCloseSectionForDataScan
1167  // require the check of scanCtxId
1168  //
1169  // We also check the output buffer size, and its alignment here.
1170  //
1171 
1172  switch (command) {
1173 
1175 
1176  if ((OutputBufferSize < sizeof (HANDLE)) ||
1177  (OutputBuffer == NULL)) {
1178 
1179  return STATUS_INVALID_PARAMETER;
1180  }
1181 
1182  if (!IS_ALIGNED(OutputBuffer,sizeof(HANDLE))) {
1183 
1184  return STATUS_DATATYPE_MISALIGNMENT;
1185  }
1186 
1187  status = AvGetScanCtxSynchronized( scanId,
1188  &scanContext );
1189 
1190  if (!NT_SUCCESS( status )) {
1191 
1192  return STATUS_NOT_FOUND;
1193  }
1194 
1195  status = AvHandleCmdCreateSectionForDataScan( scanContext,
1196  &sectionHandle );
1197 
1198  if (NT_SUCCESS(status)) {
1199  //
1200  // We succesfully created a section object/handle.
1201  // Try to set the handle in the OutputBuffer
1202  //
1203  try {
1204 
1205  (*(PHANDLE)OutputBuffer) = sectionHandle;
1206  *ReturnOutputBufferLength = sizeof(HANDLE);
1207 
1208  } except (AvExceptionFilter( GetExceptionInformation(), TRUE )) {
1209  //
1210  // We cannot depend on user service program to close this handle for us.
1211  // We explicitly call NtClose() instead of ZwClose() so that PreviousMode() will be User.
1212  // This prevents accidental closing of a kernel handle and also will not bugcheck the
1213  // system if the handle value is no longer valid
1214  //
1215  NtClose( sectionHandle );
1216 
1217  //
1218  // Close section and release the waiting I/O request thread
1219  // We treat invalid user buffer as an exception and remove
1220  // section object inside scan context. You can also design a protocol
1221  // that have user program to re-try for section creation failure.
1222  //
1223  AvFinalizeScanAndSection( scanContext );
1224  status = GetExceptionCode();
1225  }
1226  }
1227 
1228  //
1229  // AvGetScanCtxSynchronized incremented the ref count of scan context
1230  //
1231  AvReleaseScanContext( scanContext );
1232 
1233  break;
1234 
1236 
1237  try {
1238 
1239  scanResult = ((PCOMMAND_MESSAGE) InputBuffer)->ScanResult;
1240 
1241  if (scanResult == AvScanResultInfected) {
1242  AV_DBG_PRINT( AVDBG_TRACE_OPERATION_STATUS,
1243  ("[AV]: *******AvCmdCreateSectionForDataScan FAILED. \n") );
1244  }
1245 
1246  } except (AvExceptionFilter( GetExceptionInformation(), TRUE )) {
1247 
1248  return GetExceptionCode();
1249  }
1250 
1251  status = AvGetScanCtxSynchronized( scanId,
1252  &scanContext );
1253 
1254  if (!NT_SUCCESS( status )) {
1255 
1256  return STATUS_NOT_FOUND;
1257  }
1258 
1259  status = AvHandleCmdCloseSectionForDataScan( scanContext, scanResult );
1260 
1261  if (NT_SUCCESS(status)) {
1262  *ReturnOutputBufferLength = 0;
1263  }
1264 
1265  //
1266  // AvGetScanCtxSynchronized incremented the ref count of scan context
1267  //
1268  AvReleaseScanContext( scanContext );
1269 
1270  break;
1271 
1272  case AvIsFileModified:
1273 
1274  try {
1275 
1276  hFile = ((PCOMMAND_MESSAGE) InputBuffer)->FileHandle;
1277 
1278  } except (AvExceptionFilter( GetExceptionInformation(), TRUE )) {
1279 
1280  return GetExceptionCode();
1281  }
1282 
1283  if ((OutputBufferSize < sizeof (BOOLEAN)) ||
1284  (OutputBuffer == NULL)) {
1285 
1286  return STATUS_INVALID_PARAMETER;
1287  }
1288 
1289  if (!IS_ALIGNED(OutputBuffer,sizeof(BOOLEAN))) {
1290 
1291  return STATUS_DATATYPE_MISALIGNMENT;
1292  }
1293 
1294  //
1295  // Get file object by file handle
1296  // Get PFLT_VOLUME by file object
1297  // Get instance context by PFLT_VOLUME
1298  // Get filter instance in instance context
1299  // Get stream context by file object and instance context
1300  // Return if the file was previously modified
1301  //
1302 
1303  status = AvGetStreamContextByHandle( hFile, &streamContext );
1304 
1305  if (!NT_SUCCESS(status)) {
1306 
1307  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
1308  ("[AV]: **************************AvGetStreamContextByHandle FAILED. \n") );
1309  break;
1310  }
1311 
1312  try {
1313 
1314  (*(PBOOLEAN) OutputBuffer) = (BOOLEAN) IS_FILE_MODIFIED( streamContext );
1315  *ReturnOutputBufferLength = (ULONG) sizeof( BOOLEAN );
1316 
1317  } except (AvExceptionFilter( GetExceptionInformation(), TRUE )) {
1318 
1319  status = GetExceptionCode();
1320  }
1321 
1322  FltReleaseContext( streamContext );
1323 
1324  break;
1325 
1326  default:
1327  return STATUS_INVALID_PARAMETER;
1328  }
1329 
1330  return status;
1331 
1332 }
1333 
1334 NTSTATUS
1336  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1337  _In_ AVSCAN_CONNECTION_TYPE ConnectionType
1338  )
1339 /*++
1340 
1341 Routine Description:
1342 
1343  A wrapper function that prepare the communicate port.
1344 
1345 Arguments:
1346 
1347  SecurityDescriptor - Specifies a security descriptor to InitializeObjectAttributes(...).
1348 
1349  ConnectionType - The type of connection: AvConnectForScan, AvConnectForAbort, AvConnectForQuery
1350 
1351 Return Value:
1352 
1353  Returns the status of the prepartion.
1354 
1355 --*/
1356 {
1357  NTSTATUS status;
1358  OBJECT_ATTRIBUTES oa;
1359  UNICODE_STRING uniString;
1360  LONG maxConnections = 1;
1361  PCWSTR portName = NULL;
1362  PFLT_PORT *pServerPort = NULL;
1363 
1364  PAGED_CODE();
1365 
1366  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
1367  ("[AV]: AvPrepareServerPort entered. \n") );
1368 
1369  switch( ConnectionType ) {
1370  case AvConnectForScan:
1371  portName = AV_SCAN_PORT_NAME;
1372  pServerPort = &Globals.ScanServerPort;
1373  break;
1374  case AvConnectForAbort:
1375  portName = AV_ABORT_PORT_NAME;
1376  pServerPort = &Globals.AbortServerPort;
1377  break;
1378  case AvConnectForQuery:
1379  portName = AV_QUERY_PORT_NAME;
1380  pServerPort = &Globals.QueryServerPort;
1381  break;
1382  default:
1383  FLT_ASSERTMSG( "No such connection type.\n", FALSE);
1384  return STATUS_INVALID_PARAMETER;
1385  }
1386 
1387  RtlInitUnicodeString( &uniString, portName );
1388 
1389  InitializeObjectAttributes( &oa,
1390  &uniString,
1391  OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1392  NULL,
1393  SecurityDescriptor );
1394 
1395  status = FltCreateCommunicationPort( Globals.Filter,
1396  pServerPort, // this is the output to server port.
1397  &oa,
1398  NULL,
1402  maxConnections );
1403 
1404  return status;
1405 }
1406 
1407 
struct _COMMAND_MESSAGE * PCOMMAND_MESSAGE
#define AV_QUERY_PORT_NAME
Definition: avlib.h:36
#define AV_CONNECTION_CTX_TAG
NTSTATUS AvGetInstanceContextByVolume(_In_ PFLT_VOLUME volumeObject, _Out_ PAV_INSTANCE_CONTEXT *InstanceContext)
VOID AvDisconnectNotifyCallback(_In_opt_ PVOID ConnectionCookie)
#define IS_FILE_MODIFIED(_sCtx)
#define IRP_MJ_CLEANUP
Definition: mspyLog.h:302
LONGLONG ScanId
Definition: avscan.h:60
#define AV_ABORT_PORT_NAME
Definition: avlib.h:35
NTSTATUS AvUpdateStreamContextWithScanResult(_Inout_ PAV_STREAM_CONTEXT StreamContext, _In_ PAV_SCAN_CONTEXT ScanContext, _In_ AVSCAN_RESULT ScanResult)
NTSTATUS AvCreateSectionContext(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Outptr_ PAV_SECTION_CONTEXT *SectionContext)
VOID AvFreeInstances(_In_reads_(InstanceCount) PFLT_INSTANCE *InstanceArray, _In_ ULONG InstanceCount)
PFLT_PORT ScanClientPort
Definition: avscan.h:105
NTSTATUS AvHandleCmdCloseSectionForDataScan(_Inout_ PAV_SCAN_CONTEXT ScanContext, _In_ AVSCAN_RESULT ScanResult)
#define AV_SCAN_PORT_NAME
Definition: avlib.h:34
PFLT_PORT QueryServerPort
Definition: avscan.h:94
LIST_ENTRY ScanCtxListHead
Definition: avscan.h:115
PFLT_PORT QueryClientPort
Definition: avscan.h:107
return TRUE
AV_SCANNER_GLOBAL_DATA Globals
Definition: avscan.h:152
NTSTATUS AvGetInstanceContextByFileHandle(_In_ HANDLE Handle, _Out_ PAV_INSTANCE_CONTEXT *InstanceContext)
NTSTATUS AvMessageNotifyCallback(_In_ PVOID ConnectionCookie, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_to_opt_(OutputBufferSize, *ReturnOutputBufferLength) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _Out_ PULONG ReturnOutputBufferLength)
NTSTATUS AvReferenceScanContext(_In_ PAV_SCAN_CONTEXT ScanContext)
NTSTATUS AvConnectNotifyCallback(_In_ PFLT_PORT ClientPort, _In_ PVOID ServerPortCookie, _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext, _In_ ULONG SizeOfContext, _Outptr_result_maybenull_ PVOID *ConnectionCookie)
PFLT_FILTER Filter
Definition: avscan.h:86
struct _AV_FILE_REFERENCE::@0 FileId64
NTSTATUS AvGetScanCtxSynchronized(_In_ LONGLONG ScanId, _Out_ PAV_SCAN_CONTEXT *ScanCtx)
PFLT_PORT ScanServerPort
Definition: avscan.h:92
NTSTATUS AvGetStreamContextByHandle(_In_ HANDLE Handle, _Out_ PAV_STREAM_CONTEXT *StreamContext)
_In_ PLARGE_INTEGER _In_ ULONG _In_ ULONG _In_reads_bytes_(Length)
NTSTATUS AvEnumerateInstances(_Outptr_result_buffer_(*NumberInstances) PFLT_INSTANCE **InstanceArray, _Out_ PULONG NumberInstances)
UNREFERENCED_PARAMETER(FileObject)
enum _AVSCAN_COMMAND AVSCAN_COMMAND
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NTSTATUS AvFinalizeSectionContext(_Inout_ PAV_SECTION_CONTEXT SectionContext)
NTSTATUS AvCloseSectionForDataScan(_Inout_ PAV_SECTION_CONTEXT SectionContext)
Definition: scan.c:542
PAGED_CODE()
AV_FILE_REFERENCE FileId
ERESOURCE ScanCtxListLock
Definition: avscan.h:121
struct _AV_CONNECTION_CONTEXT * PAV_CONNECTION_CONTEXT
#define IS_FILE_NEED_SCAN(_sCtx)
enum _AVSCAN_RESULT AVSCAN_RESULT
NTSTATUS AvReleaseScanContext(_In_ PAV_SCAN_CONTEXT ScanContext)
PFLT_PORT AbortClientPort
Definition: avscan.h:106
NTSTATUS AvHandleCmdCreateSectionForDataScan(_Inout_ PAV_SCAN_CONTEXT ScanContext, _Out_ PHANDLE SectionHandle)
#define SET_FILE_MODIFIED_EX(_flag, _sCtx)
NTSTATUS AvPrepareServerPort(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ AVSCAN_CONNECTION_TYPE ConnectionType)
#define SET_FILE_SCANNING_EX(_flag, _sCtx)
VOID AvFinalizeScanContext(_Inout_ PAV_SCAN_CONTEXT ScanContext, _Outptr_result_maybenull_ PAV_SECTION_CONTEXT *SectionContext)
enum _AVSCAN_CONNECTION_TYPE * PAVSCAN_CONNECTION_TYPE
enum _AVSCAN_CONNECTION_TYPE AVSCAN_CONNECTION_TYPE
PFLT_PORT AbortServerPort
Definition: avscan.h:93
LONG AvExceptionFilter(_In_ PEXCEPTION_POINTERS ExceptionPointer, _In_ BOOLEAN AccessingUserBuffer)
NTSTATUS AvFinalizeScanAndSection(_Inout_ PAV_SCAN_CONTEXT ScanContext)
#define AV_DBG_PRINT(_dbgLevel, _string)
Definition: avscan.h:172
AVSCAN_CONNECTION_TYPE Type
Definition: avlib.h:182

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