WDK Mini Filter Example
minispy.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2002 Microsoft Corporation
4 
5 Module Name:
6 
7  MiniSpy.c
8 
9 Abstract:
10 
11  This is the main module for the MiniSpy mini-filter.
12 
13 Environment:
14 
15  Kernel mode
16 
17 --*/
18 
19 #include "mspyKern.h"
20 #include <stdio.h>
21 
22 //
23 // Global variables
24 //
25 
27 NTSTATUS StatusToBreakOn = 0;
28 
29 //---------------------------------------------------------------------------
30 // Function prototypes
31 //---------------------------------------------------------------------------
32 DRIVER_INITIALIZE DriverEntry;
33 NTSTATUS
35  _In_ PDRIVER_OBJECT DriverObject,
36  _In_ PUNICODE_STRING RegistryPath
37  );
38 
39 
40 NTSTATUS
41 SpyMessage (
42  _In_ PVOID ConnectionCookie,
43  _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer,
44  _In_ ULONG InputBufferSize,
45  _Out_writes_bytes_to_opt_(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
46  _In_ ULONG OutputBufferSize,
47  _Out_ PULONG ReturnOutputBufferLength
48  );
49 
50 NTSTATUS
52  _In_ PFLT_PORT ClientPort,
53  _In_ PVOID ServerPortCookie,
54  _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext,
55  _In_ ULONG SizeOfContext,
56  _Flt_ConnectionCookie_Outptr_ PVOID *ConnectionCookie
57  );
58 
59 VOID
61  _In_opt_ PVOID ConnectionCookie
62  );
63 
64 NTSTATUS
66  _In_ PCFLT_RELATED_OBJECTS FltObjects
67  );
68 
69 //---------------------------------------------------------------------------
70 // Assign text sections for each routine.
71 //---------------------------------------------------------------------------
72 
73 #ifdef ALLOC_PRAGMA
74  #pragma alloc_text(INIT, DriverEntry)
75  #pragma alloc_text(PAGE, SpyFilterUnload)
76  #pragma alloc_text(PAGE, SpyQueryTeardown)
77  #pragma alloc_text(PAGE, SpyConnect)
78  #pragma alloc_text(PAGE, SpyDisconnect)
79  #pragma alloc_text(PAGE, SpyMessage)
80 #endif
81 
82 
83 #define SetFlagInterlocked(_ptrFlags,_flagToSet) \
84  ((VOID)InterlockedOr(((volatile LONG *)(_ptrFlags)),_flagToSet))
85 
86 //---------------------------------------------------------------------------
87 // ROUTINES
88 //---------------------------------------------------------------------------
89 
90 NTSTATUS
92  _In_ PDRIVER_OBJECT DriverObject,
93  _In_ PUNICODE_STRING RegistryPath
94  )
95 /*++
96 
97 Routine Description:
98 
99  This routine is called when a driver first loads. Its purpose is to
100  initialize global state and then register with FltMgr to start filtering.
101 
102 Arguments:
103 
104  DriverObject - Pointer to driver object created by the system to
105  represent this driver.
106  RegistryPath - Unicode string identifying where the parameters for this
107  driver are located in the registry.
108 
109 Return Value:
110 
111  Status of the operation.
112 
113 --*/
114 {
115  PSECURITY_DESCRIPTOR sd;
116  OBJECT_ATTRIBUTES oa;
117  UNICODE_STRING uniString;
118  NTSTATUS status = STATUS_SUCCESS;
119 
120  try {
121 
122  //
123  // Initialize global data structures.
124  //
125 
126  MiniSpyData.LogSequenceNumber = 0;
128  MiniSpyData.RecordsAllocated = 0;
130 
131  MiniSpyData.DriverObject = DriverObject;
132 
133  InitializeListHead( &MiniSpyData.OutputBufferList );
134  KeInitializeSpinLock( &MiniSpyData.OutputBufferLock );
135 
136  ExInitializeNPagedLookasideList( &MiniSpyData.FreeBufferList,
137  NULL,
138  NULL,
139  POOL_NX_ALLOCATION,
140  RECORD_SIZE,
141  SPY_TAG,
142  0 );
143 
144 #if MINISPY_VISTA
145 
146  //
147  // Dynamically import FilterMgr APIs for transaction support
148  //
149 
150 #pragma warning(push)
151 #pragma warning(disable:4055) // type cast from data pointer to function pointer
152  MiniSpyData.PFltSetTransactionContext = (PFLT_SET_TRANSACTION_CONTEXT) FltGetRoutineAddress( "FltSetTransactionContext" );
153  MiniSpyData.PFltGetTransactionContext = (PFLT_GET_TRANSACTION_CONTEXT) FltGetRoutineAddress( "FltGetTransactionContext" );
154  MiniSpyData.PFltEnlistInTransaction = (PFLT_ENLIST_IN_TRANSACTION) FltGetRoutineAddress( "FltEnlistInTransaction" );
155 #pragma warning(pop)
156 
157 #endif
158 
159  //
160  // Read the custom parameters for MiniSpy from the registry
161  //
162 
163  SpyReadDriverParameters(RegistryPath);
164 
165  //
166  // Now that our global configuration is complete, register with FltMgr.
167  //
168 
169  status = FltRegisterFilter( DriverObject,
171  &MiniSpyData.Filter );
172 
173  if (!NT_SUCCESS( status )) {
174 
175  leave;
176  }
177 
178 
179  status = FltBuildDefaultSecurityDescriptor( &sd,
180  FLT_PORT_ALL_ACCESS );
181 
182  if (!NT_SUCCESS( status )) {
183  leave;
184  }
185 
186  RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME );
187 
188  InitializeObjectAttributes( &oa,
189  &uniString,
190  OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
191  NULL,
192  sd );
193 
194  status = FltCreateCommunicationPort( MiniSpyData.Filter,
195  &MiniSpyData.ServerPort,
196  &oa,
197  NULL,
198  SpyConnect,
200  SpyMessage,
201  1 );
202 
203  FltFreeSecurityDescriptor( sd );
204 
205  if (!NT_SUCCESS( status )) {
206  leave;
207  }
208 
209  //
210  // We are now ready to start filtering
211  //
212 
213  status = FltStartFiltering( MiniSpyData.Filter );
214 
215  } finally {
216 
217  if (!NT_SUCCESS( status ) ) {
218 
219  if (NULL != MiniSpyData.ServerPort) {
220  FltCloseCommunicationPort( MiniSpyData.ServerPort );
221  }
222 
223  if (NULL != MiniSpyData.Filter) {
224  FltUnregisterFilter( MiniSpyData.Filter );
225  }
226 
227  ExDeleteNPagedLookasideList( &MiniSpyData.FreeBufferList );
228  }
229  }
230 
231  return status;
232 }
233 
234 NTSTATUS
236  _In_ PFLT_PORT ClientPort,
237  _In_ PVOID ServerPortCookie,
238  _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext,
239  _In_ ULONG SizeOfContext,
240  _Flt_ConnectionCookie_Outptr_ PVOID *ConnectionCookie
241  )
242 /*++
243 
244 Routine Description
245 
246  This is called when user-mode connects to the server
247  port - to establish a connection
248 
249 Arguments
250 
251  ClientPort - This is the pointer to the client port that
252  will be used to send messages from the filter.
253  ServerPortCookie - unused
254  ConnectionContext - unused
255  SizeofContext - unused
256  ConnectionCookie - unused
257 
258 Return Value
259 
260  STATUS_SUCCESS - to accept the connection
261 --*/
262 {
263 
264  PAGED_CODE();
265 
266  UNREFERENCED_PARAMETER( ServerPortCookie );
267  UNREFERENCED_PARAMETER( ConnectionContext );
268  UNREFERENCED_PARAMETER( SizeOfContext);
269  UNREFERENCED_PARAMETER( ConnectionCookie );
270 
271  FLT_ASSERT( MiniSpyData.ClientPort == NULL );
272  MiniSpyData.ClientPort = ClientPort;
273  return STATUS_SUCCESS;
274 }
275 
276 
277 VOID
279  _In_opt_ PVOID ConnectionCookie
280  )
281 /*++
282 
283 Routine Description
284 
285  This is called when the connection is torn-down. We use it to close our handle to the connection
286 
287 Arguments
288 
289  ConnectionCookie - unused
290 
291 Return value
292 
293  None
294 --*/
295 {
296 
297  PAGED_CODE();
298 
299  UNREFERENCED_PARAMETER( ConnectionCookie );
300 
301  //
302  // Close our handle
303  //
304 
305  FltCloseClientPort( MiniSpyData.Filter, &MiniSpyData.ClientPort );
306 }
307 
308 NTSTATUS
310  _In_ FLT_FILTER_UNLOAD_FLAGS Flags
311  )
312 /*++
313 
314 Routine Description:
315 
316  This is called when a request has been made to unload the filter. Unload
317  requests from the Operation System (ex: "sc stop minispy" can not be
318  failed. Other unload requests may be failed.
319 
320  You can disallow OS unload request by setting the
321  FLTREGFL_DO_NOT_SUPPORT_SERVICE_STOP flag in the FLT_REGISTARTION
322  structure.
323 
324 Arguments:
325 
326  Flags - Flags pertinent to this operation
327 
328 Return Value:
329 
330  Always success
331 
332 --*/
333 {
334  UNREFERENCED_PARAMETER( Flags );
335 
336  PAGED_CODE();
337 
338  //
339  // Close the server port. This will stop new connections.
340  //
341 
342  FltCloseCommunicationPort( MiniSpyData.ServerPort );
343 
344  FltUnregisterFilter( MiniSpyData.Filter );
345 
347  ExDeleteNPagedLookasideList( &MiniSpyData.FreeBufferList );
348 
349  return STATUS_SUCCESS;
350 }
351 
352 
353 NTSTATUS
355  _In_ PCFLT_RELATED_OBJECTS FltObjects,
356  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
357  )
358 /*++
359 
360 Routine Description:
361 
362  This allows our filter to be manually detached from a volume.
363 
364 Arguments:
365 
366  FltObjects - Contains pointer to relevant objects for this operation.
367  Note that the FileObject field will always be NULL.
368 
369  Flags - Flags pertinent to this operation
370 
371 Return Value:
372 
373 --*/
374 {
375  UNREFERENCED_PARAMETER( FltObjects );
376  UNREFERENCED_PARAMETER( Flags );
377  PAGED_CODE();
378  return STATUS_SUCCESS;
379 }
380 
381 
382 NTSTATUS
384  _In_ PVOID ConnectionCookie,
385  _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer,
386  _In_ ULONG InputBufferSize,
387  _Out_writes_bytes_to_opt_(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
388  _In_ ULONG OutputBufferSize,
389  _Out_ PULONG ReturnOutputBufferLength
390  )
391 /*++
392 
393 Routine Description:
394 
395  This is called whenever a user mode application wishes to communicate
396  with this minifilter.
397 
398 Arguments:
399 
400  ConnectionCookie - unused
401 
402  OperationCode - An identifier describing what type of message this
403  is. These codes are defined by the MiniFilter.
404  InputBuffer - A buffer containing input data, can be NULL if there
405  is no input data.
406  InputBufferSize - The size in bytes of the InputBuffer.
407  OutputBuffer - A buffer provided by the application that originated
408  the communication in which to store data to be returned to this
409  application.
410  OutputBufferSize - The size in bytes of the OutputBuffer.
411  ReturnOutputBufferSize - The size in bytes of meaningful data
412  returned in the OutputBuffer.
413 
414 Return Value:
415 
416  Returns the status of processing the message.
417 
418 --*/
419 {
420  MINISPY_COMMAND command;
421  NTSTATUS status;
422 
423  PAGED_CODE();
424 
425  UNREFERENCED_PARAMETER( ConnectionCookie );
426 
427  //
428  // **** PLEASE READ ****
429  //
430  // The INPUT and OUTPUT buffers are raw user mode addresses. The filter
431  // manager has already done a ProbedForRead (on InputBuffer) and
432  // ProbedForWrite (on OutputBuffer) which guarentees they are valid
433  // addresses based on the access (user mode vs. kernel mode). The
434  // minifilter does not need to do their own probe.
435  //
436  // The filter manager is NOT doing any alignment checking on the pointers.
437  // The minifilter must do this themselves if they care (see below).
438  //
439  // The minifilter MUST continue to use a try/except around any access to
440  // these buffers.
441  //
442 
443  if ((InputBuffer != NULL) &&
444  (InputBufferSize >= (FIELD_OFFSET(COMMAND_MESSAGE,Command) +
445  sizeof(MINISPY_COMMAND)))) {
446 
447  try {
448 
449  //
450  // Probe and capture input message: the message is raw user mode
451  // buffer, so need to protect with exception handler
452  //
453 
454  command = ((PCOMMAND_MESSAGE) InputBuffer)->Command;
455 
456  } except (SpyExceptionFilter( GetExceptionInformation(), TRUE )) {
457 
458  return GetExceptionCode();
459  }
460 
461  switch (command) {
462 
463  case GetMiniSpyLog:
464 
465  //
466  // Return as many log records as can fit into the OutputBuffer
467  //
468 
469  if ((OutputBuffer == NULL) || (OutputBufferSize == 0)) {
470 
471  status = STATUS_INVALID_PARAMETER;
472  break;
473  }
474 
475  //
476  // We want to validate that the given buffer is POINTER
477  // aligned. But if this is a 64bit system and we want to
478  // support 32bit applications we need to be careful with how
479  // we do the check. Note that the way SpyGetLog is written
480  // it actually does not care about alignment but we are
481  // demonstrating how to do this type of check.
482  //
483 
484 #if defined(_WIN64)
485 
486  if (IoIs32bitProcess( NULL )) {
487 
488  //
489  // Validate alignment for the 32bit process on a 64bit
490  // system
491  //
492 
493  if (!IS_ALIGNED(OutputBuffer,sizeof(ULONG))) {
494 
495  status = STATUS_DATATYPE_MISALIGNMENT;
496  break;
497  }
498 
499  } else {
500 
501 #endif
502 
503  if (!IS_ALIGNED(OutputBuffer,sizeof(PVOID))) {
504 
505  status = STATUS_DATATYPE_MISALIGNMENT;
506  break;
507  }
508 
509 #if defined(_WIN64)
510 
511  }
512 
513 #endif
514 
515  //
516  // Get the log record.
517  //
518 
519  status = SpyGetLog( OutputBuffer,
520  OutputBufferSize,
521  ReturnOutputBufferLength );
522  break;
523 
524 
525  case GetMiniSpyVersion:
526 
527  //
528  // Return version of the MiniSpy filter driver. Verify
529  // we have a valid user buffer including valid
530  // alignment
531  //
532 
533  if ((OutputBufferSize < sizeof( MINISPYVER )) ||
534  (OutputBuffer == NULL)) {
535 
536  status = STATUS_INVALID_PARAMETER;
537  break;
538  }
539 
540  //
541  // Validate Buffer alignment. If a minifilter cares about
542  // the alignment value of the buffer pointer they must do
543  // this check themselves. Note that a try/except will not
544  // capture alignment faults.
545  //
546 
547  if (!IS_ALIGNED(OutputBuffer,sizeof(ULONG))) {
548 
549  status = STATUS_DATATYPE_MISALIGNMENT;
550  break;
551  }
552 
553  //
554  // Protect access to raw user-mode output buffer with an
555  // exception handler
556  //
557 
558  try {
559 
560  ((PMINISPYVER)OutputBuffer)->Major = MINISPY_MAJ_VERSION;
561  ((PMINISPYVER)OutputBuffer)->Minor = MINISPY_MIN_VERSION;
562 
563  } except (SpyExceptionFilter( GetExceptionInformation(), TRUE )) {
564 
565  return GetExceptionCode();
566  }
567 
568  *ReturnOutputBufferLength = sizeof( MINISPYVER );
569  status = STATUS_SUCCESS;
570  break;
571 
572  default:
573  status = STATUS_INVALID_PARAMETER;
574  break;
575  }
576 
577  } else {
578 
579  status = STATUS_INVALID_PARAMETER;
580  }
581 
582  return status;
583 }
584 
585 
586 //---------------------------------------------------------------------------
587 // Operation filtering routines
588 //---------------------------------------------------------------------------
589 
590 
591 FLT_PREOP_CALLBACK_STATUS
592 #pragma warning(suppress: 6262) // higher than usual stack usage is considered safe in this case
594  _Inout_ PFLT_CALLBACK_DATA Data,
595  _In_ PCFLT_RELATED_OBJECTS FltObjects,
596  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
597  )
598 /*++
599 
600 Routine Description:
601 
602  This routine receives ALL pre-operation callbacks for this filter. It then
603  tries to log information about the given operation. If we are able
604  to log information then we will call our post-operation callback routine.
605 
606  NOTE: This routine must be NON-PAGED because it can be called on the
607  paging path.
608 
609 Arguments:
610 
611  Data - Contains information about the given operation.
612 
613  FltObjects - Contains pointers to the various objects that are pertinent
614  to this operation.
615 
616  CompletionContext - This receives the address of our log buffer for this
617  operation. Our completion routine then receives this buffer address.
618 
619 Return Value:
620 
621  Identifies how processing should continue for this operation
622 
623 --*/
624 {
625  FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; //assume we are NOT going to call our completion routine
626  PRECORD_LIST recordList;
627  PFLT_FILE_NAME_INFORMATION nameInfo = NULL;
628  UNICODE_STRING defaultName;
629  PUNICODE_STRING nameToUse;
630  NTSTATUS status;
631 
632 #if MINISPY_VISTA
633 
634  PUNICODE_STRING ecpDataToUse = NULL;
635  UNICODE_STRING ecpData;
636  WCHAR ecpDataBuffer[MAX_NAME_SPACE/sizeof(WCHAR)];
637 
638 #endif
639 
640 #if MINISPY_NOT_W2K
641 
642  WCHAR name[MAX_NAME_SPACE/sizeof(WCHAR)];
643 
644 #endif
645 
646  //
647  // Try and get a log record
648  //
649 
650  recordList = SpyNewRecord();
651 
652  if (recordList) {
653 
654  //
655  // We got a log record, if there is a file object, get its name.
656  //
657  // NOTE: By default, we use the query method
658  // FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP
659  // because MiniSpy would like to get the name as much as possible, but
660  // can cope if we can't retrieve a name. For a debugging type filter,
661  // like Minispy, this is reasonable, but for most production filters
662  // who need names reliably, they should query the name at times when it
663  // is known to be safe and use the query method
664  // FLT_FILE_NAME_QUERY_DEFAULT.
665  //
666 
667  if (FltObjects->FileObject != NULL) {
668 
669  status = FltGetFileNameInformation( Data,
670  FLT_FILE_NAME_NORMALIZED |
671  MiniSpyData.NameQueryMethod,
672  &nameInfo );
673 
674  } else {
675 
676  //
677  // Can't get a name when there's no file object
678  //
679 
680  status = STATUS_UNSUCCESSFUL;
681  }
682 
683  //
684  // Use the name if we got it else use a default name
685  //
686 
687  if (NT_SUCCESS( status )) {
688 
689  nameToUse = &nameInfo->Name;
690 
691  //
692  // Parse the name if requested
693  //
694 
695  if (FlagOn( MiniSpyData.DebugFlags, SPY_DEBUG_PARSE_NAMES )) {
696 
697 #ifdef DBG
698 
699  FLT_ASSERT( NT_SUCCESS( FltParseFileNameInformation( nameInfo ) ) );
700 
701 #else
702 
703  FltParseFileNameInformation( nameInfo );
704 
705 #endif
706 
707  }
708 
709  } else {
710 
711 #if MINISPY_NOT_W2K
712 
713  NTSTATUS lstatus;
714  PFLT_FILE_NAME_INFORMATION lnameInfo;
715 
716  //
717  // If we couldn't get the "normalized" name try and get the
718  // "opened" name
719  //
720 
721  if (FltObjects->FileObject != NULL) {
722 
723  //
724  // Get the opened name
725  //
726 
727  lstatus = FltGetFileNameInformation( Data,
728  FLT_FILE_NAME_OPENED |
729  FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP,
730  &lnameInfo );
731 
732 
733  if (NT_SUCCESS(lstatus)) {
734 
735 #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
736  (VOID)_snwprintf( name,
737  sizeof(name)/sizeof(WCHAR),
738  L"<%08x> %wZ",
739  status,
740  &lnameInfo->Name );
741 
742  FltReleaseFileNameInformation( lnameInfo );
743 
744  } else {
745 
746  //
747  // If that failed report both NORMALIZED status and
748  // OPENED status
749  //
750 
751 #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
752  (VOID)_snwprintf( name,
753  sizeof(name)/sizeof(WCHAR),
754  L"<NO NAME: NormalizeStatus=%08x OpenedStatus=%08x>",
755  status,
756  lstatus );
757  }
758 
759  } else {
760 
761 #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
762  (VOID)_snwprintf( name,
763  sizeof(name)/sizeof(WCHAR),
764  L"<NO NAME>" );
765 
766  }
767 
768  //
769  // Name was initialized by _snwprintf() so it may not be null terminated
770  // if the buffer is insufficient. We will ignore this error and truncate
771  // the file name.
772  //
773 
774  name[(sizeof(name)/sizeof(WCHAR))-1] = L'\0';
775 
776  RtlInitUnicodeString( &defaultName, name );
777  nameToUse = &defaultName;
778 
779 #else
780 
781  //
782  // We were unable to get the String safe routine to work on W2K
783  // Do it the old safe way
784  //
785 
786  RtlInitUnicodeString( &defaultName, L"<NO NAME>" );
787  nameToUse = &defaultName;
788 
789 #endif //MINISPY_NOT_W2K
790 
791 #if DBG
792 
793  //
794  // Debug support to break on certain errors.
795  //
796 
797  if (FltObjects->FileObject != NULL) {
798  NTSTATUS retryStatus;
799 
800  if ((StatusToBreakOn != 0) && (status == StatusToBreakOn)) {
801 
802  DbgBreakPoint();
803  }
804 
805  retryStatus = FltGetFileNameInformation( Data,
806  FLT_FILE_NAME_NORMALIZED |
807  MiniSpyData.NameQueryMethod,
808  &nameInfo );
809 
810  if (!NT_SUCCESS( retryStatus )) {
811 
812  //
813  // We always release nameInfo, so ignore return value.
814  //
815 
816  NOTHING;
817  }
818  }
819 
820 #endif
821 
822  }
823 
824 #if MINISPY_VISTA
825 
826  //
827  // Look for ECPs, but only if it's a create operation
828  //
829 
830  if (Data->Iopb->MajorFunction == IRP_MJ_CREATE) {
831 
832  //
833  // Initialize an empty string to receive an ECP data dump
834  //
835 
836  RtlInitEmptyUnicodeString( &ecpData,
837  ecpDataBuffer,
838  MAX_NAME_SPACE/sizeof(WCHAR) );
839 
840  //
841  // Parse any extra create parameters
842  //
843 
844  SpyParseEcps( Data, recordList, &ecpData );
845 
846  ecpDataToUse = &ecpData;
847  }
848 
849  //
850  // Store the name and ECP data (if any)
851  //
852 
853  SpySetRecordNameAndEcpData( &(recordList->LogRecord), nameToUse, ecpDataToUse );
854 
855 #else
856 
857  //
858  // Store the name
859  //
860 
861  SpySetRecordName( &(recordList->LogRecord), nameToUse );
862 
863 #endif
864 
865  //
866  // Release the name information structure (if defined)
867  //
868 
869  if (NULL != nameInfo) {
870 
871  FltReleaseFileNameInformation( nameInfo );
872  }
873 
874  //
875  // Set all of the operation information into the record
876  //
877 
878  SpyLogPreOperationData( Data, FltObjects, recordList );
879 
880  //
881  // Pass the record to our completions routine and return that
882  // we want our completion routine called.
883  //
884 
885  if (Data->Iopb->MajorFunction == IRP_MJ_SHUTDOWN) {
886 
887  //
888  // Since completion callbacks are not supported for
889  // this operation, do the completion processing now
890  //
891 
893  FltObjects,
894  recordList,
895  0 );
896 
897  returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
898 
899  } else {
900 
901  *CompletionContext = recordList;
902  returnStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
903  }
904  }
905 
906  return returnStatus;
907 }
908 
909 
910 FLT_POSTOP_CALLBACK_STATUS
912  _Inout_ PFLT_CALLBACK_DATA Data,
913  _In_ PCFLT_RELATED_OBJECTS FltObjects,
914  _In_ PVOID CompletionContext,
915  _In_ FLT_POST_OPERATION_FLAGS Flags
916  )
917 /*++
918 
919 Routine Description:
920 
921  This routine receives ALL post-operation callbacks. This will take
922  the log record passed in the context parameter and update it with
923  the completion information. It will then insert it on a list to be
924  sent to the usermode component.
925 
926  NOTE: This routine must be NON-PAGED because it can be called at DPC level
927 
928 Arguments:
929 
930  Data - Contains information about the given operation.
931 
932  FltObjects - Contains pointers to the various objects that are pertinent
933  to this operation.
934 
935  CompletionContext - Pointer to the RECORD_LIST structure in which we
936  store the information we are logging. This was passed from the
937  pre-operation callback
938 
939  Flags - Contains information as to why this routine was called.
940 
941 Return Value:
942 
943  Identifies how processing should continue for this operation
944 
945 --*/
946 {
947  PRECORD_LIST recordList;
948  PRECORD_LIST reparseRecordList = NULL;
949  PLOG_RECORD reparseLogRecord;
950  PFLT_TAG_DATA_BUFFER tagData;
951  ULONG copyLength;
952 
953  UNREFERENCED_PARAMETER( FltObjects );
954 
955  recordList = (PRECORD_LIST)CompletionContext;
956 
957  //
958  // If our instance is in the process of being torn down don't bother to
959  // log this record, free it now.
960  //
961 
962  if (FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING)) {
963 
964  SpyFreeRecord( recordList );
965  return FLT_POSTOP_FINISHED_PROCESSING;
966  }
967 
968  //
969  // Set completion information into the record
970  //
971 
972  SpyLogPostOperationData( Data, recordList );
973 
974  //
975  // Log reparse tag information if specified.
976  //
977 
978  tagData = Data->TagData;
979  if (tagData) {
980 
981  reparseRecordList = SpyNewRecord();
982 
983  if (reparseRecordList) {
984 
985  //
986  // only copy the DATA portion of the information
987  //
988 
989  RtlCopyMemory( &reparseRecordList->LogRecord.Data,
990  &recordList->LogRecord.Data,
991  sizeof(RECORD_DATA) );
992 
993  reparseLogRecord = &reparseRecordList->LogRecord;
994 
995  copyLength = FLT_TAG_DATA_BUFFER_HEADER_SIZE + tagData->TagDataLength;
996 
997  if(copyLength > MAX_NAME_SPACE) {
998 
999  copyLength = MAX_NAME_SPACE;
1000  }
1001 
1002  //
1003  // Copy reparse data
1004  //
1005 
1006  RtlCopyMemory(
1007  &reparseRecordList->LogRecord.Name[0],
1008  tagData,
1009  copyLength
1010  );
1011 
1012  reparseLogRecord->RecordType |= RECORD_TYPE_FILETAG;
1013  reparseLogRecord->Length += (ULONG) ROUND_TO_SIZE( copyLength, sizeof( PVOID ) );
1014  }
1015  }
1016 
1017  //
1018  // Send the logged information to the user service.
1019  //
1020 
1021  SpyLog( recordList );
1022 
1023  if (reparseRecordList) {
1024 
1025  SpyLog( reparseRecordList );
1026  }
1027 
1028  //
1029  // For creates within a transaction enlist in the transaction
1030  // if we haven't already done.
1031  //
1032 
1033  if ((FltObjects->Transaction != NULL) &&
1034  (Data->Iopb->MajorFunction == IRP_MJ_CREATE) &&
1035  (Data->IoStatus.Status == STATUS_SUCCESS)) {
1036 
1037  //
1038  // Enlist in the transaction.
1039  //
1040 
1041  SpyEnlistInTransaction( FltObjects );
1042  }
1043 
1044  return FLT_POSTOP_FINISHED_PROCESSING;
1045 }
1046 
1047 
1048 NTSTATUS
1050  _In_ PCFLT_RELATED_OBJECTS FltObjects
1051  )
1052 /*++
1053 
1054 Routine Description
1055 
1056  Minispy calls this function to enlist in a transaction of interest.
1057 
1058 Arguments
1059 
1060  FltObjects - Contains parameters required to enlist in a transaction.
1061 
1062 Return value
1063 
1064  Returns STATUS_SUCCESS if we were able to successfully enlist in a new transcation or if we
1065  were already enlisted in the transaction. Returns an appropriate error code on a failure.
1066 
1067 --*/
1068 {
1069 
1070 #if MINISPY_VISTA
1071 
1072  PMINISPY_TRANSACTION_CONTEXT transactionContext = NULL;
1073  PMINISPY_TRANSACTION_CONTEXT oldTransactionContext = NULL;
1074  PRECORD_LIST recordList;
1075  NTSTATUS status;
1076  static ULONG Sequence=1;
1077 
1078  //
1079  // This code is only built in the Vista environment, but
1080  // we need to ensure this binary still runs down-level. Return
1081  // at this point if the transaction dynamic imports were not found.
1082  //
1083  // If we find FltGetTransactionContext, we assume the other
1084  // transaction APIs are also present.
1085  //
1086 
1087  if (NULL == MiniSpyData.PFltGetTransactionContext) {
1088 
1089  return STATUS_SUCCESS;
1090  }
1091 
1092  //
1093  // Try to get our context for this transaction. If we get
1094  // one we have already enlisted in this transaction.
1095  //
1096 
1097  status = (*MiniSpyData.PFltGetTransactionContext)( FltObjects->Instance,
1098  FltObjects->Transaction,
1099  &transactionContext );
1100 
1101  if (NT_SUCCESS( status )) {
1102 
1103  //
1104  // Check if we have already enlisted in the transaction.
1105  //
1106 
1107  if (FlagOn(transactionContext->Flags, MINISPY_ENLISTED_IN_TRANSACTION)) {
1108 
1109  //
1110  // FltGetTransactionContext puts a reference on the context. Release
1111  // that now and return success.
1112  //
1113 
1114  FltReleaseContext( transactionContext );
1115  return STATUS_SUCCESS;
1116  }
1117 
1118  //
1119  // If we have not enlisted then we need to try and enlist in the transaction.
1120  //
1121 
1122  goto ENLIST_IN_TRANSACTION;
1123  }
1124 
1125  //
1126  // If the context does not exist create a new one, else return the error
1127  // status to the caller.
1128  //
1129 
1130  if (status != STATUS_NOT_FOUND) {
1131 
1132  return status;
1133  }
1134 
1135  //
1136  // Allocate a transaction context.
1137  //
1138 
1139  status = FltAllocateContext( FltObjects->Filter,
1140  FLT_TRANSACTION_CONTEXT,
1142  PagedPool,
1143  &transactionContext );
1144 
1145  if (!NT_SUCCESS( status )) {
1146 
1147  return status;
1148  }
1149 
1150  //
1151  // Set the context into the transaction
1152  //
1153 
1154  RtlZeroMemory(transactionContext, sizeof(MINISPY_TRANSACTION_CONTEXT));
1155  transactionContext->Count = Sequence++;
1156 
1157  FLT_ASSERT( MiniSpyData.PFltSetTransactionContext );
1158 
1159  status = (*MiniSpyData.PFltSetTransactionContext)( FltObjects->Instance,
1160  FltObjects->Transaction,
1161  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
1162  transactionContext,
1163  &oldTransactionContext );
1164 
1165  if (!NT_SUCCESS( status )) {
1166 
1167  FltReleaseContext( transactionContext ); //this will free the context
1168 
1169  if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
1170 
1171  return status;
1172  }
1173 
1174  FLT_ASSERT(oldTransactionContext != NULL);
1175 
1176  if (FlagOn(oldTransactionContext->Flags, MINISPY_ENLISTED_IN_TRANSACTION)) {
1177 
1178  //
1179  // If this context is already enlisted then release the reference
1180  // which FltSetTransactionContext put on it and return success.
1181  //
1182 
1183  FltReleaseContext( oldTransactionContext );
1184  return STATUS_SUCCESS;
1185  }
1186 
1187  //
1188  // If we found an existing transaction then we should try and
1189  // enlist in it. There is a race here in which the thread
1190  // which actually set the transaction context may fail to
1191  // enlist in the transaction and delete it later. It might so
1192  // happen that we picked up a reference to that context here
1193  // and successfully enlisted in that transaction. For now
1194  // we have chosen to ignore this scenario.
1195  //
1196 
1197  //
1198  // If we are not enlisted then assign the right transactionContext
1199  // and attempt enlistment.
1200  //
1201 
1202  transactionContext = oldTransactionContext;
1203  }
1204 
1205 ENLIST_IN_TRANSACTION:
1206 
1207  //
1208  // Enlist on this transaction for notifications.
1209  //
1210 
1211  FLT_ASSERT( MiniSpyData.PFltEnlistInTransaction );
1212 
1213  status = (*MiniSpyData.PFltEnlistInTransaction)( FltObjects->Instance,
1214  FltObjects->Transaction,
1215  transactionContext,
1216  FLT_MAX_TRANSACTION_NOTIFICATIONS );
1217 
1218  //
1219  // If the enlistment failed we might have to delete the context and remove
1220  // our count.
1221  //
1222 
1223  if (!NT_SUCCESS( status )) {
1224 
1225  //
1226  // If the error is that we are already enlisted then we do not need
1227  // to delete the context. Otherwise we have to delete the context
1228  // before releasing our reference.
1229  //
1230 
1231  if (status == STATUS_FLT_ALREADY_ENLISTED) {
1232 
1233  status = STATUS_SUCCESS;
1234 
1235  } else {
1236 
1237  //
1238  // It is worth noting that only the first caller of
1239  // FltDeleteContext will remove the reference added by
1240  // filter manager when the context was set.
1241  //
1242 
1243  FltDeleteContext( transactionContext );
1244  }
1245 
1246  FltReleaseContext( transactionContext );
1247  return status;
1248  }
1249 
1250  //
1251  // Set the flag so that future enlistment efforts know that we
1252  // successfully enlisted in the transaction.
1253  //
1254 
1255  SetFlagInterlocked( &transactionContext->Flags, MINISPY_ENLISTED_IN_TRANSACTION );
1256 
1257  //
1258  // The operation succeeded, remove our count
1259  //
1260 
1261  FltReleaseContext( transactionContext );
1262 
1263  //
1264  // Log a record that a new transaction has started.
1265  //
1266 
1267  recordList = SpyNewRecord();
1268 
1269  if (recordList) {
1270 
1271  SpyLogTransactionNotify( FltObjects, recordList, 0 );
1272 
1273  //
1274  // Send the logged information to the user service.
1275  //
1276 
1277  SpyLog( recordList );
1278  }
1279 
1280 #endif // MINISPY_VISTA
1281 
1282  return STATUS_SUCCESS;
1283 }
1284 
1285 
1286 #if MINISPY_VISTA
1287 
1288 NTSTATUS
1290  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1291  _In_ PFLT_CONTEXT TransactionContext,
1292  _In_ ULONG TransactionNotification
1293  )
1294 {
1295  PRECORD_LIST recordList;
1296 
1297  UNREFERENCED_PARAMETER( TransactionContext );
1298 
1299  //
1300  // Try and get a log record
1301  //
1302 
1303  recordList = SpyNewRecord();
1304 
1305  if (recordList) {
1306 
1307  SpyLogTransactionNotify( FltObjects, recordList, TransactionNotification );
1308 
1309  //
1310  // Send the logged information to the user service.
1311  //
1312 
1313  SpyLog( recordList );
1314  }
1315 
1316  return STATUS_SUCCESS;
1317 }
1318 
1319 #endif // MINISPY_VISTA
1320 
1321 VOID
1323  _Inout_ PMINISPY_TRANSACTION_CONTEXT Context,
1324  _In_ FLT_CONTEXT_TYPE ContextType
1325  )
1326 {
1327  UNREFERENCED_PARAMETER( Context );
1328  UNREFERENCED_PARAMETER( ContextType );
1329 
1330  FLT_ASSERT(FLT_TRANSACTION_CONTEXT == ContextType);
1331  FLT_ASSERT(Context->Count != 0);
1332 }
1333 
1334 
1335 LONG
1337  _In_ PEXCEPTION_POINTERS ExceptionPointer,
1338  _In_ BOOLEAN AccessingUserBuffer
1339  )
1340 /*++
1341 
1342 Routine Description:
1343 
1344  Exception filter to catch errors touching user buffers.
1345 
1346 Arguments:
1347 
1348  ExceptionPointer - The exception record.
1349 
1350  AccessingUserBuffer - If TRUE, overrides FsRtlIsNtStatusExpected to allow
1351  the caller to munge the error to a desired status.
1352 
1353 Return Value:
1354 
1355  EXCEPTION_EXECUTE_HANDLER - If the exception handler should be run.
1356 
1357  EXCEPTION_CONTINUE_SEARCH - If a higher exception handler should take care of
1358  this exception.
1359 
1360 --*/
1361 {
1362  NTSTATUS Status;
1363 
1364  Status = ExceptionPointer->ExceptionRecord->ExceptionCode;
1365 
1366  //
1367  // Certain exceptions shouldn't be dismissed within the namechanger filter
1368  // unless we're touching user memory.
1369  //
1370 
1371  if (!FsRtlIsNtstatusExpected( Status ) &&
1372  !AccessingUserBuffer) {
1373 
1374  return EXCEPTION_CONTINUE_SEARCH;
1375  }
1376 
1377  return EXCEPTION_EXECUTE_HANDLER;
1378 }
1379 
1380 
struct _COMMAND_MESSAGE * PCOMMAND_MESSAGE
NTSTATUS SpyQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
Definition: minispy.c:354
PFLT_ENLIST_IN_TRANSACTION PFltEnlistInTransaction
Definition: mspyKern.h:211
VOID SpyParseEcps(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PRECORD_LIST RecordList, _Inout_ PUNICODE_STRING EcpData)
Definition: mspyLib.c:707
NTSTATUS SpyFilterUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
Definition: minispy.c:309
ULONG Length
Definition: minispy.h:146
LOG_RECORD LogRecord
Definition: minispy.h:175
NTSTATUS(* PFLT_GET_TRANSACTION_CONTEXT)(_In_ PFLT_INSTANCE Instance, _In_ PKTRANSACTION Transaction, _Outptr_ PFLT_CONTEXT *Context)
Definition: mspyKern.h:67
PDRIVER_OBJECT DriverObject
Definition: mspyKern.h:124
LIST_ENTRY OutputBufferList
Definition: mspyKern.h:150
PFLT_PORT ClientPort
Definition: mspyKern.h:143
NTSTATUS SpyKtmNotificationCallback(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PFLT_CONTEXT TransactionContext, _In_ ULONG TransactionNotification)
Definition: minispy.c:1289
PFLT_GET_TRANSACTION_CONTEXT PFltGetTransactionContext
Definition: mspyKern.h:209
VOID SpyLogPreOperationData(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1047
USHORT TagDataLength
Definition: mspyLog.h:395
VOID SpyLog(_In_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1206
WCHAR Name[]
Definition: minispy.h:153
struct _MINISPYVER * PMINISPYVER
#define DEFAULT_MAX_RECORDS_TO_ALLOCATE
Definition: mspyKern.h:242
#define MINISPY_ENLISTED_IN_TRANSACTION
Definition: mspyKern.h:234
ULONG NameQueryMethod
Definition: mspyKern.h:193
DRIVER_INITIALIZE DriverEntry
Definition: minispy.c:32
__volatile LONG LogSequenceNumber
Definition: mspyKern.h:185
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
#define SPY_TAG
Definition: mspyKern.h:33
#define MINISPY_MAJ_VERSION
Definition: minispy.h:56
VOID SpyDisconnect(_In_opt_ PVOID ConnectionCookie)
Definition: minispy.c:278
struct _RECORD_LIST * PRECORD_LIST
VOID SpyLogPostOperationData(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1117
CONST FLT_REGISTRATION FilterRegistration
#define SetFlagInterlocked(_ptrFlags, _flagToSet)
Definition: minispy.c:83
#define RECORD_TYPE_FILETAG
Definition: minispy.h:90
LONG SpyExceptionFilter(_In_ PEXCEPTION_POINTERS ExceptionPointer, _In_ BOOLEAN AccessingUserBuffer)
Definition: minispy.c:1336
VOID SpyReadDriverParameters(_In_ PUNICODE_STRING RegistryPath)
Definition: mspyLib.c:1445
NTSTATUS(* PFLT_SET_TRANSACTION_CONTEXT)(_In_ PFLT_INSTANCE Instance, _In_ PKTRANSACTION Transaction, _In_ FLT_SET_CONTEXT_OPERATION Operation, _In_ PFLT_CONTEXT NewContext, _Outptr_opt_ PFLT_CONTEXT *OldContext)
Definition: mspyKern.h:58
PFLT_PORT ServerPort
Definition: mspyKern.h:137
FLT_ASSERT(IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))
return TRUE
PFLT_SET_TRANSACTION_CONTEXT PFltSetTransactionContext
Definition: mspyKern.h:207
FLT_POSTOP_CALLBACK_STATUS SpyPostOperationCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
Definition: minispy.c:911
NTSTATUS SpyEnlistInTransaction(_In_ PCFLT_RELATED_OBJECTS FltObjects)
Definition: minispy.c:1049
PFLT_FILTER Filter
Definition: mspyKern.h:131
#define SPY_DEBUG_PARSE_NAMES
Definition: mspyKern.h:252
#define MINISPY_PORT_NAME
Definition: minispy.h:70
enum _MINISPY_COMMAND MINISPY_COMMAND
#define FlagOn(_F, _SF)
Definition: minispy.h:247
#define ROUND_TO_SIZE(_length, _alignment)
Definition: minispy.h:242
VOID SpyLogTransactionNotify(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PRECORD_LIST RecordList, _In_ ULONG TransactionNotification)
Definition: mspyLib.c:1152
_In_ PLARGE_INTEGER _In_ ULONG _In_ ULONG _In_reads_bytes_(Length)
VOID SpyEmptyOutputBufferList(VOID)
Definition: mspyLib.c:1396
VOID SpySetRecordNameAndEcpData(_Inout_ PLOG_RECORD LogRecord, _In_ PUNICODE_STRING Name, _In_opt_ PUNICODE_STRING EcpData)
Definition: mspyLib.c:885
#define MAX_NAME_SPACE
Definition: minispy.h:210
NTSTATUS(* PFLT_ENLIST_IN_TRANSACTION)(_In_ PFLT_INSTANCE Instance, _In_ PKTRANSACTION Transaction, _In_ PFLT_CONTEXT TransactionContext, _In_ NOTIFICATION_MASK NotificationMask)
Definition: mspyKern.h:74
NTSTATUS SpyConnect(_In_ PFLT_PORT ClientPort, _In_ PVOID ServerPortCookie, _In_reads_bytes_(SizeOfContext) PVOID ConnectionContext, _In_ ULONG SizeOfContext, _Flt_ConnectionCookie_Outptr_ PVOID *ConnectionCookie)
Definition: minispy.c:235
UNREFERENCED_PARAMETER(FileObject)
#define DEFAULT_NAME_QUERY_METHOD
Definition: mspyKern.h:245
ULONG DebugFlags
Definition: mspyKern.h:199
FLT_PREOP_CALLBACK_STATUS SpyPreOperationCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: minispy.c:593
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NPAGED_LOOKASIDE_LIST FreeBufferList
Definition: mspyKern.h:156
#define RECORD_SIZE
Definition: minispy.h:83
KSPIN_LOCK OutputBufferLock
Definition: mspyKern.h:149
__volatile LONG RecordsAllocated
Definition: mspyKern.h:163
RECORD_DATA Data
Definition: minispy.h:152
NTSTATUS SpyMessage(_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)
Definition: minispy.c:383
struct _MINISPYVER MINISPYVER
PAGED_CODE()
PRECORD_LIST SpyNewRecord(VOID)
Definition: mspyLib.c:218
IoStatus Status
VOID SpyDeleteTxfContext(_Inout_ PMINISPY_TRANSACTION_CONTEXT Context, _In_ FLT_CONTEXT_TYPE ContextType)
Definition: minispy.c:1322
NTSTATUS StatusToBreakOn
Definition: minispy.c:27
#define MINISPY_MIN_VERSION
Definition: minispy.h:57
NTSTATUS SpyGetLog(_Out_writes_bytes_to_(OutputBufferLength, *ReturnOutputBufferLength) PUCHAR OutputBuffer, _In_ ULONG OutputBufferLength, _Out_ PULONG ReturnOutputBufferLength)
Definition: mspyLib.c:1240
LONG MaxRecordsToAllocate
Definition: mspyKern.h:162
VOID SpyFreeRecord(_In_ PRECORD_LIST Record)
Definition: mspyLib.c:285
#define IRP_MJ_SHUTDOWN
Definition: mspyLog.h:300
ULONG RecordType
Definition: minispy.h:149
MINISPY_DATA MiniSpyData
Definition: minispy.c:26
#define IRP_MJ_CREATE
Definition: mspyLog.h:284

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