Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
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; }
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Writing WDF Drivers | 7 Dec 2020 | LIVE ONLINE |
Internals & Software Drivers | 25 Jan 2021 | LIVE ONLINE |
Developing Minifilters | 8 March 2021 | LIVE ONLINE |
Comments
This callback can be called at IRQL DISPATCH_LEVEL, which would make it illegal to use a communication port. Enable Driver Verifier and always post the !analyze -v output if you have a crash.
-scott
OSR
Hello Scott,
thank you for your reply.
Since I cannot use a communication port through FltSendMessage inside this function,
how would you suggest I should communicate with userlevel?
FltSendMessage was the easiest option since it waits for response by the userlevel process.
Here is the !analyze -v log:
INVALID_PROCESS_ATTACH_ATTEMPT (5)
Arguments:
Arg1: ffffa98d439b2080
Arg2: ffffa98d402581c0
Arg3: 0000000000000001
Arg4: 0000000000000001
Debugging Details:
DUMP_CLASS: 1
DUMP_QUALIFIER: 0
BUILD_VERSION_STRING: 15046.0.amd64fre.rs2_release.170224-1700
DUMP_TYPE: 0
BUGCHECK_P1: ffffa98d439b2080
BUGCHECK_P2: ffffa98d402581c0
BUGCHECK_P3: 1
BUGCHECK_P4: 1
CPU_COUNT: 4
CPU_MHZ: fa8
CPU_VENDOR: GenuineIntel
CPU_FAMILY: 6
CPU_MODEL: 5e
CPU_STEPPING: 3
CPU_MICROCODE: 6,5e,3,0 (F,M,S,R) SIG: BA'00000000 (cache) BA'00000000 (init)
DEFAULT_BUCKET_ID: WIN8_DRIVER_FAULT
BUGCHECK_STR: 0x5
PROCESS_NAME: System
CURRENT_IRQL: 2
ANALYSIS_SESSION_HOST: DESKTOP-NQ55126
ANALYSIS_SESSION_TIME: 02-29-2020 17:41:58.0187
ANALYSIS_VERSION: 10.0.16299.15 amd64fre
LAST_CONTROL_TRANSFER: from fffff802489f6812 to fffff80248972cc0
Use the ALE layers for this. https://docs.microsoft.com/en-us/windows/win32/fwp/application-layer-enforcement--ale-
I already switched to FWPM_LAYER_ALE_AUTH_CONNECT_V4 since a while now:
Which is definitely better for my purpose.

Although the issue occurrs more rarely now, sometimes there is still the same BSOD error INVALID_PROCESS_ATTACH_ATTEMPT when calling FltSendMessage.
On StackOverflow I was suggested to use the inverted call model instead of FltSendMessage.
This would require some protocol rewriting, but I can go for it, or do you have any other better approach in mind?
Thank you
> (Quote)
> I already switched to FWPM_LAYER_ALE_AUTH_CONNECT_V4 since a while now:
>
> m_callout.applicableLayer = FWPM_LAYER_ALE_AUTH_CONNECT_V4; //m_callout.applicableLayer = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
>
> Which is definitely better for my purpose.
> Although the issue occurrs more rarely now, sometimes there is still the same BSOD error INVALID_PROCESS_ATTACH_ATTEMPT when calling FltSendMessage. :(
> On StackOverflow I was suggested to use the inverted call model instead of FltSendMessage.
> This would require some protocol rewriting, but I can go for it, or do you have any other better approach in mind? =)
>
> Thank you
You expecting current implementation somehow magically start working ?
If you did read the thread, you would have understood that the implementation usually works, except on some random cases which throw the INVALID_PROCESS_ATTACH_ATTEMPT error.
I opened the thread to get a direction regarding the reason and solution for this error.
Do you have something actually useful to add?
No. Bsod = doesn’t work. You solution doesn’t work. You should understand that you can’t use fltsendmessage at dispatch. This is said in function documentation. You implementation is flawed on conceptual level, it can’t be fixed. You need to change your model.
And remember: work most of the time = doesn’t work
I believe at this point that the best thing to do is remove FltSendMessage and use inverted call model for communication instead.
Each time I get an event in the ClassifyFn callback, I will communicate this to userlevel by completing one of the pending IOCTL...
Unless somebody has got some direction for me, that's the way I'll go