Hello all
I'm trying to resolve a memory leak that occurs when calling FwpsAcquireWritableLayerDataPointer0. Each time we call this function we leak a pending context block which is 0x90 bytes long with a Fecf pool tag and is allocated by FePendClassify. The issue appears to be the reference count on the Fecf block
Good case
FwpsPendClassify0: FePendClassify allocates the leaked block and initializes reference count to 2
FwpsCompleteClassify0: FeCompleteClassify decrements the reference count twice and the block is released.
Bad case
FwpsPendClassify0: FePendClassify allocates the leaked block and initializes reference count to 2
FwpsAcquireWritableLayerDataPointer0: FeAcquireWritableLayerDataPointer increments reference count to 3
FwpsApplyModifiedLayerData0: FeApplyModifiedLayerData increments then decrements reference count so this is still 3
FwpsCompleteClassify0: FeCompleteClassify again decrements the reference count twice but this time the reference count is 1 so the block is leaked.
Neglected to mention that in both cases we call FwpsReleaseClassifyHandle after the call to FwpsCompleteClassify0 but this doesn't do anything to the reference count
ALSO when these are freed, they are freed (ie not stored in a lookaside list)
I just tried removing our product and installing the MS WDK wfpsampler behemoth and I'm seeing the same thing there. If I run the proxy scenario using the command:
kd> !poolused 2 Fecf
Using a machine size of fff8d pages to configure the kd cache
.
Sorting by NonPaged Pool Consumed
NonPaged Paged
Tag Allocs Used Allocs Used
Fecf 425 61200 0 0 WFP filter engine callout context , Binary: netio.sys
TOTAL 425 61200 0 0
kd> !pool ffffba8c`63c6af70 2
Pool page ffffba8c63c6af70 region is Special pool
*ffffba8c63c6a000 size: 90 data: ffffba8c63c6af70 (NonPaged) *Fecf
Pooltag Fecf : WFP filter engine callout context, Binary : netio.sys
// Offset +4 is the reference count for the WFP_OBJECT header
kd> db ffffba8c63c6af70+4 l1
ffffba8c`63c6af74 01
kd> !verifier 80 ffffba8c63c6af70 1
Log of recent kernel pool Allocate and Free operations:
There are up to 0x10000 entries in the log.
Parsing 0x0000000000010000 log entries, searching for address 0xffffba8c63c6af70.
======================================================================
Pool block ffffba8c63c6af70, Size 0000000000000090, Thread ffffba8c64d26080
fffff8034a3f9fe5 nt!VfAllocPoolNotification+0x31
fffff8034a3ee89f nt!VeAllocatePoolWithTagPriority+0x2cf
fffff8034a3ef06c nt!VerifierExAllocatePoolWithTag+0x8c
fffff8034bcb3e61 NETIO!WfpPoolAllocNonPaged+0x21
fffff8034bcff862 NETIO!FeAcquireWritableLayerDataPointer+0x2a2
fffff8034c0978ec fwpkclnt!FwpsAcquireWritableLayerDataPointer0+0x2c
fffff8034c1a1e42 WFPSamplerCalloutDriver!KrnlHlprRedirectDataPopulate+0x292
fffff8034c1a19e8 WFPSamplerCalloutDriver!KrnlHlprRedirectDataCreate+0x178
fffff8034c173f1d WFPSamplerCalloutDriver!ClassifyProxyByALERedirect+0x42d
fffff8034bec04c2 tcpip!AlePostProcessClassify+0x122
fffff8034bcbc83d NETIO!ProcessCallout+0x7dd
fffff8034bcb870b NETIO!KfdClassify+0x8bb
fffff8034bda9cda tcpip!AleInspectConnectRequest+0x592
Parsed entry 00000000000035b5/0000000000010000...
Parsed 00000000000035b5 entries out of 0000000000010000.
.
It definitely feels like this is an issue with FwpsAcquireWritableLayerDataPointer0 incrementing the reference counter which is not subsequently decremented by FeApplyModifiedLayerData or FwpsReleaseClassifyHandle. I have reproduced this on clean installs of both Windows 10 and Windows 11 with only the Microsoft WDK wfpsampler running which is configured as follows:
Listener
This is an instance of netcat listening on port 1234
nc -l 127.0.0.1 -p 1234
Sender
A second instance of netcat which I renamed to nc2.exe. I arbitrarily send this on port 4444 but the proxy rule below proxies all traffic to 1234 so this could be anything
echo 'hello world' | nc2 127.0.0.1 4444
Proxy rule
I use the following rule to proxy all traffic from nc2.exe to port 1243 (add -r to remove)
And as our own driver the failure to free the block is due to the reference count on the context block being set to 1 by FwpsAcquireWritableLayerDataPointer0
Surely others must have seen this before. If anybody is using FwpsAcquireWritableLayerDataPointer, next time they are in the kernel debugger would you mind running the following command:.,
!poolused 2 Fecf
Also is anybody aware of an email alias for the WDK samples or the WFP team at Microsoft that I can raise this with?