locked
Triple fault on FwpsPendOperation0/FwpsCompleteOperation0 RRS feed

  • Question

  • Hi, I have the following code in my classify callout:

        PendedOp *pendedOp = ExAllocatePoolWithTag(NonPagedPool, sizeof(PendedOp),
                                                   PENDED_OP_POOL_TAG);
        if (pendedOp != NULL) {
          status = FwpsPendOperation0(inMetaValues->completionHandle,
                                      &pendedOp->completionContext);
          if (NT_SUCCESS(status)) {
            DbgPrint("  operation pended\n");
            FwpsCompleteOperation0(pendedOp->completionContext, NULL);
            DbgPrint("  operation completed\n");
          }
          if (!NT_SUCCESS(status) && pendedOp->completionContext != NULL) {
            DbgPrint("  operation pend failed\n");
          }
          ExFreePoolWithTag(pendedOp, PENDED_OP_POOL_TAG);
        }
    The plan is to do asynchronous processing on the request, then later mark the packet as complete. However, running even just the above code results in a triple fault that immediately resets my Virtual PC. This goes away as soon as I comment out the lines that do the Pend and Complete. I'm filtering at the ALE RESOURCE_ASSIGNMENT layer (I plan to move to the ALE CONNECT and RECV_ACCEPT layers later).

    I know this is possible since the "inspect" network sample in the WDK does something similar, but at the CONNECT and RECV_ACCEPT layers. Yet what I'm doing should be simpler since there are no packets involved and thus I don't need to block and reinject packets. I can't spot the difference between the logic of these two drivers in terms of how they use Pend and Complete.

    Any hints would be tremendously appreciated.

    Here's the complete code listing for this driver.

    #include <ntddk.h>
    
    #pragma warning(push)
    #pragma warning(disable:4201)       // unnamed struct/union
    #include <fwpsk.h>
    #pragma warning(pop)
    
    #include <fwpmk.h>
    #include <ws2ipdef.h>
    #include <in6addr.h>
    #include <ip2string.h>
    #include <string.h>
    
    #define INITGUID
    #include <guiddef.h>
    
    //
    // GUIDs
    //
    
    // 76b743d4-1249-4614-a632-6f9c4d08d25a
    DEFINE_GUID(DEMO_CALLOUT_V4,
                0x76b743d4,
                0x1249,
                0x4614,
                0xa6, 0x32, 0x6f, 0x9c, 0x4d, 0x08, 0xd2, 0x5a);
    
    // 2e207682-d95f-4525-b966-969f26587f03
    DEFINE_GUID(DEMO_SUBLAYER,
                0x2e207682,
                0xd95f,
                0x4525,
                0xb9, 0x66, 0x96, 0x9f, 0x26, 0x58, 0x7f, 0x03);
    
    // bb6e405b-19f4-4ff3-b501-1a3dc01aae01
    DEFINE_GUID(DEMO_FILTER,
                0xbb6e405b,
                0x19f4,
                0x4ff3,
                0xb5, 0x01, 0x1a, 0x3d, 0xc0, 0x1a, 0xae, 0x01);
    
    //
    // Constants
    //
    
    enum { PENDED_OP_POOL_TAG = 'kppD' };
    
    //
    // Globals
    //
    
    PDEVICE_OBJECT gDeviceObject = NULL;
    HANDLE gEngineHandle = NULL;
    UINT32 gCalloutIdV4 = 0;
    
    //
    // Structs
    //
    
    typedef struct PendedOp_ {
      HANDLE completionContext;
    } PendedOp;
    
    //
    // Callouts
    //
    
    NTSTATUS
    DemoNotify(
      IN FWPS_CALLOUT_NOTIFY_TYPE notifyType,
      IN const GUID* filterKey,
      IN const FWPS_FILTER0* filter
      )
    {
      UNREFERENCED_PARAMETER(notifyType);
      UNREFERENCED_PARAMETER(filterKey);
      UNREFERENCED_PARAMETER(filter);
    
      return STATUS_SUCCESS;
    }
    
    void
    DemoClassify(
      IN const FWPS_INCOMING_VALUES0* inFixedValues,
      IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
      IN OUT void* layerData,
      IN const FWPS_FILTER0* filter,
      IN UINT64 flowContext,
      OUT FWPS_CLASSIFY_OUT0* classifyOut
      )
    {
      NTSTATUS status = STATUS_SUCCESS;
    
      UNREFERENCED_PARAMETER(inFixedValues);
      UNREFERENCED_PARAMETER(inMetaValues);
      UNREFERENCED_PARAMETER(layerData);
      UNREFERENCED_PARAMETER(filter);
      UNREFERENCED_PARAMETER(flowContext);
      UNREFERENCED_PARAMETER(classifyOut);
    
      // do we have the right to alter the classify? see
      // <http://msdn.microsoft.com/en-us/library/aa364008.aspx>
      if (classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) {
        PendedOp *pendedOp = ExAllocatePoolWithTag(NonPagedPool, sizeof(PendedOp),
                                                   PENDED_OP_POOL_TAG);
        if (pendedOp != NULL) {
          status = FwpsPendOperation0(inMetaValues->completionHandle,
                                      &pendedOp->completionContext);
          if (NT_SUCCESS(status)) {
            DbgPrint("  operation pended\n");
            FwpsCompleteOperation0(pendedOp->completionContext, NULL);
            DbgPrint("  operation completed\n");
          }
          if (!NT_SUCCESS(status) && pendedOp->completionContext != NULL) {
            DbgPrint("  operation pend failed\n");
          }
          ExFreePoolWithTag(pendedOp, PENDED_OP_POOL_TAG);
        }
      }
    }
    
    //
    // Driver routines
    //
    
    VOID
    DriverUnload(
      IN  PDRIVER_OBJECT driverObject
      )
    {
      DbgPrint("unloading driver\n");
    
      if (gEngineHandle != NULL) {
        FwpmFilterDeleteByKey0(gEngineHandle, &DEMO_FILTER);
    
        if (gCalloutIdV4 != 0) {
          DbgPrint("unregistering callout\n");
          FwpsCalloutUnregisterById0(gCalloutIdV4);
          gCalloutIdV4 = 0;
        }
    
        FwpmSubLayerDeleteByKey0(gEngineHandle, &DEMO_SUBLAYER);
    
        DbgPrint("closing engine\n");
        FwpmEngineClose0(gEngineHandle);
        gEngineHandle = NULL;
      }
    
      if (gDeviceObject != NULL) {
        DbgPrint("deleting device\n");
        IoDeleteDevice(gDeviceObject);
        gDeviceObject = NULL;
      }
    
      DbgPrint("driver unloaded\n");
    }
    
    NTSTATUS
    DriverEntry(
      IN  PDRIVER_OBJECT  driverObject,
      IN  PUNICODE_STRING registryPath
      )
    {
      NTSTATUS status = STATUS_SUCCESS;
    
      UNICODE_STRING deviceName;
      DbgPrint("creating driver\n");
      RtlInitUnicodeString(&deviceName, L"\\Device\\DemoDriver");
      gDeviceObject = NULL;
      status = IoCreateDevice(driverObject,
                              0, // extension size
                              &deviceName,
                              FILE_DEVICE_NETWORK, // device type
                              0, // flags
                              FALSE, // exclusive access?
                              &gDeviceObject); // output
    
      if (NT_SUCCESS(status)) {
        FWPM_SESSION0 session = {0};
        DbgPrint("opening engine\n");
        session.flags = FWPM_SESSION_FLAG_DYNAMIC;
        status = FwpmEngineOpen0(NULL, // must be null
                                 RPC_C_AUTHN_WINNT, // authentication service
                                 NULL, // authentication id
                                 &session, // optional session params
                                 &gEngineHandle); // engine output
    
        if (NT_SUCCESS(status)) {
          BOOLEAN inTransaction = FALSE;
          DbgPrint("starting txn\n");
          status = FwpmTransactionBegin0(gEngineHandle, 0 /* flags */);
    
          if (NT_SUCCESS(status)) {
            FWPM_SUBLAYER0 demoSublayer;
            BOOLEAN addedSublayer = FALSE;
            inTransaction = TRUE;
            DbgPrint("adding sublayer\n");
            RtlZeroMemory(&demoSublayer, sizeof demoSublayer);
            demoSublayer.subLayerKey = DEMO_SUBLAYER;
            demoSublayer.displayData.name = L"Demo Sub-Layer";
            demoSublayer.displayData.description =
              L"Sub-Layer for use by Demo callouts";
            demoSublayer.flags = 0;
            // must be less than the weight of FWPM_SUBLAYER_UNIVERSAL to be
            // compatible with Vista's IpSec implementation.
            demoSublayer.weight = 0;
            status = FwpmSubLayerAdd0(gEngineHandle, &demoSublayer, NULL);
    
            if (NT_SUCCESS(status)) {
              FWPS_CALLOUT0 sCallout = {0};
              BOOLEAN calloutRegistered = FALSE;
              UINT32 *calloutId = &gCalloutIdV4;
              const GUID *calloutKey = &DEMO_CALLOUT_V4;
              addedSublayer = TRUE;
              DbgPrint("registering callout\n");
              sCallout.calloutKey = *calloutKey;
              sCallout.classifyFn = DemoClassify;
              sCallout.notifyFn = DemoNotify;
              status = FwpsCalloutRegister0(gDeviceObject, &sCallout, calloutId);
    
              if (NT_SUCCESS(status)) {
                const GUID *layerKey = &FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4;
                FWPM_CALLOUT0 mCallout = {0};
                calloutRegistered = TRUE;
                DbgPrint("adding callout\n");
                mCallout.calloutKey = *calloutKey;
                mCallout.displayData.name = L"Demo Callout";
                mCallout.displayData.description =
                  L"Intercepts inbound or outbound connect attempts";
                mCallout.applicableLayer = *layerKey;
                status = FwpmCalloutAdd0(gEngineHandle,
                                         &mCallout,
                                         NULL, // security descriptor
                                         NULL); // output id
    
                if (NT_SUCCESS(status)) {
                  FWPM_FILTER0 filter = {0};
                  FWPM_FILTER_CONDITION0 filterConditions[3] = {0};
                  UINT conditionIndex = 0;
    
                  DbgPrint("adding filter\n");
                  filter.layerKey = *layerKey;
                  filter.displayData.name = L"Demo Filter";
                  filter.displayData.description =
                    L"Intercepts inbound or outbound connect attempts";
                  filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
                  filter.action.calloutKey = *calloutKey;
                  filter.filterCondition = filterConditions;
                  filter.subLayerKey = DEMO_SUBLAYER;
                  filter.weight.type = FWP_EMPTY; // auto-weight.
                  filter.rawContext = 0;
    
                  filter.numFilterConditions = conditionIndex;
                  status = FwpmFilterAdd0(gEngineHandle,
                                          &filter,
                                          NULL, // security descriptor
                                          NULL); // output id
    
                  if (NT_SUCCESS(status)) {
                    DbgPrint("committing txn\n");
                    status = FwpmTransactionCommit0(gEngineHandle);
    
                    if (NT_SUCCESS(status)) {
                      inTransaction = FALSE;
    
                      DbgPrint("DriverEntry succeeded\n");
                    }
    
                    if (!NT_SUCCESS(status)) {
                      // nothing to rollback
                    }
                  }
    
                  if (!NT_SUCCESS(status)) {
                    DbgPrint("deleting filter due to error\n");
                    FwpmFilterDeleteByKey0(gEngineHandle, &DEMO_FILTER);
                  }
                }
              }
    
              if (!NT_SUCCESS(status) && calloutRegistered) {
                DbgPrint("unregistering callout due to error\n");
                FwpsCalloutUnregisterById0(*calloutId);
                *calloutId = 0;
              }
            }
    
            if (!NT_SUCCESS(status) && addedSublayer) {
              DbgPrint("removing sublayer due to error\n");
              FwpmSubLayerDeleteByKey0(gEngineHandle, &DEMO_SUBLAYER);
            }
          }
    
          if (!NT_SUCCESS(status) && inTransaction) {
            DbgPrint("aborting txn due to error\n");
            FwpmTransactionAbort0(gEngineHandle);
          }
        }
    
        if (!NT_SUCCESS(status) && gEngineHandle != NULL) {
          DbgPrint("closing engine due to error\n");
          FwpmEngineClose0(gEngineHandle);
          gEngineHandle = NULL;
        }
      }
    
      if (!NT_SUCCESS(status) && gDeviceObject != NULL) {
        DbgPrint("deleting device due to error\n");
        IoDeleteDevice(gDeviceObject);
        gDeviceObject = NULL;
      }
    
      driverObject->DriverUnload = DriverUnload;
    
      return status;
    }
    
    Thursday, October 1, 2009 4:26 PM

All replies

  • You need to hook up a KD to your VM to get some clues about what you're doing wrong.
    Thursday, March 18, 2010 1:35 AM
  • check re-aouthorize in your callout function with :

    inFixedValues->incomingValue[flagsIndex].value.uint32 & FWP_CONDITION_FLAG_IS_REAUTHORIZE

    Saturday, November 14, 2015 6:58 AM