microsoft / Windows-driver-samples

This repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.
Microsoft Public License
6.75k stars 4.89k forks source link

[network/trans/WFPSampler] Memory leak #1191

Open cooma05 opened 1 week ago

cooma05 commented 1 week ago

When running in proxy mode a pending context block with a 'Fecf' pool tag is leaked each time a connection is proxied. I traced this to 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 using the following rule:

WFPSampler.Exe -s PROXY -l FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 -aaid C:\tools\ncat\nc2.exe -pra 127.0.0.1 -prp 1234 prs -v

This rule proxies all traffic for nc2.exe to port 1234. Thus if we run a listener script on port 1234 nc -l 127.0.0.1 -p 1234

Each time we send using echo 'hello world' | nc2 127.0.0.1 4444 (where 4444 is an arbitrary port) the connection will be proxied to 1234 and we should see hello world printed in the listen window

And each time we run the send command we leak one of the Fecf blocks

d> !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 95 13680 0 0 WFP filter engine callout context , Binary: netio.sys

TOTAL 95 13680 0 0

Each block is 0x90 bytes long. The reference count for the embedded WFPObject is at offset 4 and this is set to 1 because it was incremented by FwpsAcquireWritableLayerDataPointer0

kd> !pool ffffba8c63c6af70 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 ffffba8c63c6af74 01

With special pool enabled we can see the allocation stack

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 000000000