If you are familiar with Windows Filtering Platform (WFP) , a technology introduced in Windows Vista, chances are good that you already have read about or used FwpsQueryPacketInjectionState0  few times. WDK headers declare FwpsQueryPacketInjectionState0 as below.

FWPS_PACKET_INJECTION_STATE NTAPI
  FwpsQueryPacketInjectionState0(
    IN HANDLE  injectionHandle,
    IN const NET_BUFFER_LIST  *netBufferList,
    OUT OPTIONAL HANDLE  *injectionContext
    );

As you can see, the function takes two input parameters and has one optional output parameter. The first parameter is an injection handle that the callout driver gets when it calls FwpsInjectionHandleCreate0. The second parameter is a NET_BUFFER_LIST pointer which describes packet buffers chained together. NET_BUFFER_LIST is declared like thus -

typedef struct _NET_BUFFER_LIST { 
  NET_BUFFER_LIST_HEADER  NetBufferListHeader; 
  PNET_BUFFER_LIST_CONTEXT  Context; 
  PNET_BUFFER_LIST  ParentNetBufferList; 
  NDIS_HANDLE  NdisPoolHandle; 
  DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)PVOID  NdisReserved[2]; 
  DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)PVOID  ProtocolReserved[4]; 
  DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)PVOID  MiniportReserved[2]; 
  PVOID  Scratch; 
  NDIS_HANDLE  SourceHandle; 
  ULONG  NblFlags; 
  LONG  ChildRefCount; 
  ULONG  Flags; 
  NDIS_STATUS  Status; 
  PVOID  NetBufferListInfo[MaxNetBufferListInfo];
} NET_BUFFER_LIST, *PNET_BUFFER_LIST;

Now  NetBufferListHeader.NetBufferListData.Next points to the next NET_BUFFER_LIST (if any) so NET_BUFFER_LISTs can be chained together. Each NET_BUFFER_LIST can have one or more NET_BUFFERs chained together.

NetBufferListHeader.NetBufferListData.FirstNetBuffer points to the first NET_BUFFER in the NET_BUFFER_LIST. FirstNetBuffer->NetBufferHeader.NetBufferData.Next has the next NET_BUFFER pointer.

Each NET_BUFFER in turn has an MDL chain of packet buffers. WDK has nice macros to hide all the complexities of accessing intended members.

So FwpsQueryPacketInjectionState0 is used to get the injection state (and optionally the injection context) of the NET_BUFFER_LIST given the injectionHandle. FWPS_PACKET_INJECTION_STATE is an enum like below.

typedef enum FWPS_PACKET_INJECTION_STATE_ {
  FWPS_PACKET_NOT_INJECTED,
  FWPS_PACKET_INJECTED_BY_SELF,
  FWPS_PACKET_INJECTED_BY_OTHER,
  FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF,
  FWPS_PACKET_INJECTION_STATE_MAX
} FWPS_PACKET_INJECTION_STATE;

WFP maintains the original injection handle in undocumented structure in NetBufferListInfo[WfpNetBufferListInfo]. By using that information, and comparing the injection handle to the injection handle passed, FwpsQueryPacketInjectionState0 is able to determine, for example, whether this NET_BUFFER_LIST was injected by the calling driver (FWPS_PACKET_INJECTED_BY_SELF) or whether this NET_BUFFER_LIST was injected by another driver (FWPS_PACKET_INJECTED_BY_OTHER). If no injection handle is present in the NET_BUFFER_LIST, FWPS_PACKET_NOT_INJECTED is returned. FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF is returned when the FwpsQueryPacketInjectionState0 determines that the NET_BUFFER_LIST is a clone of another NET_BUFFER_LIST that was injected by the calling driver previously. FwpsQueryPacketInjectionState0 knows that by looking at the NET_BUFFER_LIST.ParentNetBufferList which points to the source of the clone. A NET_BUFFER_LIST can be cloned by using FwpsAllocateCloneNetBufferList0 or NdisAllocateCloneNetBufferList.

There is a bug in Vista handling cloned NET_BUFFER_LISTs however. When you call FwpsQueryPacketInjectionState0 on a cloned NET_BUFFER_LIST, you may crash the system because of a bug during cloning which leaves a cloned NET_BUFFER_LIST with a null ParentNetBufferList and FwpsQueryPacketInjectionState0 dereferences null ParentNetBufferList and chokes. It is not clear whether FwpsQueryPacketInjectionState0 has some leftover flags that suggest that it is a cloned NET_BUFFER_LIST or the absence of null check is just an oversight. I have seen this crash happen when a cloned NET_BUFFER_LIST from a callout was injected, cloned subsequently by tcpip.sys and a second callout decided to call FwpsQueryPacketInjectionState0 on the clone of clone.
 
So if your callout driver all of a sudden starts crashing at fwpkclnt!FwpsQueryPacketInjectionState0+0x46 (and you find another WFP callout driver is cloning on the system) you know you have hit this bug.

Microsoft will fix this issue in Vista SP1.

Tagged with →  
Share →

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Looking for something?

Use the form below to search the site:


Still not finding what you're looking for? Drop us a note so we can take care of it!

Visit our friends!

A few highly recommended friends...

Set your Twitter account name in your settings to use the TwitterBar Section.