Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

Windows WFP Driver: Getting BSOD when processing packets in ClassifyFn callback

ViottoViotto Member Posts: 1

Hi,

I am trying to code a simple firewall application which can allow or block network connection attempts made from userlevel processes.
To do so, following the WFPStarterKit tutorial, I created a WFP Driver which is set to intercept data at FWPM_LAYER_OUTBOUND_TRANSPORT_V4 layer.
The ClassifyFn callback function is responsible for intercepting the connection attempt, and either allow or deny it.
Once the ClassifyFn callback gets hit, the ProcessID of the packet is sent, along with a few other info, to a userlevel process through the FltSendMessage function.
The userlevel process receives the message, checks the ProcessID, and replies a boolean allow/deny command to the driver.

While this approach works when blocking a first packet,
in some cases (expecially when allowing multiple packets) the code generates a BSOD with the INVALID_PROCESS_ATTACH_ATTEMPT error code.
The error is triggered at the call to FltSendMessage.

While I am still unable to pinpoint the exact problem, it seems that making the callout thread wait (through FltSendMessage) for a reply from userlevel can generate this BSOD error on some conditions.

I would be very grateful if you can point me to the right direction.

Here is the function where I register the callout:

NTSTATUS register_example_callout(DEVICE_OBJECT * wdm_device)
{
    NTSTATUS status = STATUS_SUCCESS;
    FWPS_CALLOUT s_callout = { 0 };
    FWPM_CALLOUT m_callout = { 0 };
    FWPM_DISPLAY_DATA display_data = { 0 };

    if (filter_engine_handle == NULL)
        return STATUS_INVALID_HANDLE;

    display_data.name = EXAMPLE_CALLOUT_NAME;
    display_data.description = EXAMPLE_CALLOUT_DESCRIPTION;

    // Register a new Callout with the Filter Engine using the provided callout functions
    s_callout.calloutKey = EXAMPLE_CALLOUT_GUID;
    s_callout.classifyFn = example_classify;
    s_callout.notifyFn = example_notify;
    s_callout.flowDeleteFn = example_flow_delete;
    status = FwpsCalloutRegister((void *)wdm_device, &s_callout, &example_callout_id);
    if (!NT_SUCCESS(status)) {
        DbgPrint("Failed to register callout functions for example callout, status 0x%08x", status);
        goto Exit;
    }

    // Setup a FWPM_CALLOUT structure to store/track the state associated with the FWPS_CALLOUT
    m_callout.calloutKey = EXAMPLE_CALLOUT_GUID;
    m_callout.displayData = display_data;
    m_callout.applicableLayer = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
    m_callout.flags = 0;
    status = FwpmCalloutAdd(filter_engine_handle, &m_callout, NULL, NULL);
    if (!NT_SUCCESS(status)) {
        DbgPrint("Failed to register example callout, status 0x%08x", status);
    }
    else {
        DbgPrint("Example Callout Registered");
    }

Exit:
    return status;
}

Here is the callout function:

 /*************************
ClassifyFn Function
**************************/
void example_classify(
    const FWPS_INCOMING_VALUES * inFixedValues,
    const FWPS_INCOMING_METADATA_VALUES * inMetaValues,
    void * layerData,
    const void * classifyContext,
    const FWPS_FILTER * filter,
    UINT64 flowContext,
    FWPS_CLASSIFY_OUT * classifyOut)
{
    UNREFERENCED_PARAMETER(layerData);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(inMetaValues);

    NETWORK_ACCESS_QUERY AccessQuery;
    BOOLEAN SafeToOpen = TRUE;
    classifyOut->actionType = FWP_ACTION_PERMIT;

    AccessQuery.remote_address = inFixedValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS].value.uint32;
    AccessQuery.remote_port = inFixedValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_PORT].value.uint16;

    // Get Process ID
    AccessQuery.ProcessId = (UINT64)PsGetCurrentProcessId();

    if (!AccessQuery.ProcessId) 
    {
        return;
    }

    // Here we connect to our userlevel application using FltSendMessage.
    // Some checks are done and the SafeToOpen variable is populated with a BOOLEAN which indicates if to allow or block the packet.
    // However, sometimes, a BSOD is generated with an INVALID_PROCESS_ATTACH_ATTEMPT error on the FltSendMessage call
    QueryUserLevel(QUERY_NETWORK, &AccessQuery, sizeof(NETWORK_ACCESS_QUERY), &SafeToOpen, NULL, 0);

    if (!SafeToOpen) {
        classifyOut->actionType = FWP_ACTION_BLOCK;
    }

    return;
}

Comments

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
Writing WDF Drivers 21 Oct 2019 OSR Seminar Space & ONLINE
Internals & Software Drivers 18 Nov 2019 Dulles, VA
Kernel Debugging 30 Mar 2020 OSR Seminar Space
Developing Minifilters 27 Apr 2020 OSR Seminar Space & ONLINE