locked
doing clone-block-reinject takes away FWPS_RIGHT_ACTION_WRITE for some zero-sized buffers RRS feed

  • Question

  • I have a WFP driver that does stream filtering in userspace using the clone-block-reinject method. I've observed that under specific circumstances the FWPS_CLASSIFY_OUT0::rights parameter to stream classify callout has FWPS_RIGHT_ACTION_WRITE cleared and actionType set to FWP_ACTION_BLOCK when it is being called with the zero-sized buffer signalling the end of connection. This is on a system with no other third-party WFP drivers. The driver behaves correctly in that it doesn't clone-block-reinject this particular buffer, but the result is that the receiving application never receives the end of connection. This has been observed on Windows 7 SP1 32 and 64 bit.

    I've also noticed some suspicious behavior: If I modify the driver to not do classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE (for the previous calls), the FIN call arrives with rights intact (but action is still set to block). Also if the driver ignores rights and reinjects the FIN, the application sees it (although such implementation would be incompatible with other WFP filters).

    There are some patterns I was able to identify. This happens only if the last ethernet frame contains the last piece of application data along with ACK, PSH and FIN flags. The occurence of this problem is quite low, I would estimate it to 1%. When it happens, layerData->streamData->flags misses FWPS_STREAM_FLAG_RECEIVE_PUSH. Also the call stack is always such that my driver is trying to reinject some previous piece of data, but before the call returns, its classify function is called (this call stack is with a slightly simplified driver with no user-space in the loop that has the same problem):

    WfpReinject!StreamClassify
    NETIO!StreamInvokeCalloutAndNormalizeAction
    NETIO!StreamCalloutProcessDisconnect
    NETIO!StreamCalloutProcessingLoop
    NETIO!StreamProcessCallout
    NETIO!ProcessCallout
    NETIO!ArbitrateAndEnforce
    NETIO!KfdClassify
    NETIO!StreamInternalClassify
    NETIO!StreamInject
    NETIO!FwppStreamInject
    fwpkclnt!FwpsStreamInjectAsync0
    WfpReinject!ReinjectThreadProc
    nt!PspSystemThreadStartup
    nt!KiThreadStartup

    This leads me to hypothesize that the classifyOut structure for the last-data call is somehow shared with the classifyOut structure for the FIN call. Perhaps because they arrived in a single ethernet frame, because they share the call stack, or both.

    This problem is easy to replicate when browsing the web interface of certain ASUS routers, e.g. RT-AC66U. I've also written a linux application that uses raw sockets (windows' implementation of raw sockets is unfortunately not useful for this purpose). It tries to emulate the server's behavior, but the chance of this problem occuring with this application are somewhat small. Also if you're interested I can provide you with the source code for WfpReinject which is basically a minimal implementation of clone-block-reinject.

    To me this looks like a problem with the WFP framework itself, so I would like to ask to you to investigate. If there is any more information that would be useful, I'd be happy to provide that.

    Thanks in advance,
    Marek 'MMx' Ludha

    Friday, February 14, 2014 2:06 PM