basil00 / WinDivert

WinDivert: Windows Packet Divert
https://reqrypt.org/windivert.html
Other
2.45k stars 501 forks source link

application hang when call WinDivertClose #298

Open tanda996 opened 2 years ago

tanda996 commented 2 years ago

askbug this is my app's stack. My app hang when call WinDivertClose: if (m_hSocketMon && m_hSocketMon != INVALID_HANDLE_VALUE) { WinDivertClose(m_hSocketMon); // hang here }

after run above codes, my app still have 3 other handle to close. does Windivert driver call cleanup too soon or somethings?

basil00 commented 2 years ago

It seems related to #294.

Eyeballing the code, it is strange that it hangs on WdfDeleteObject. The read_queue object should be managed by WDF and not the WinDivert driver.

What version of Windows is this? Is there a reliable way to reproduce the problem?

tanda996 commented 2 years ago

Sometime happened on Windows 1703 x86, Windows x64 too but much less. AFAIK windivert_cleanup() will be called only when all windivert's handles reach to 0 reference. But on my machine it's still have 3 other handles (1 handle hanging, maybe?), this strange. More info: My app request stop windivert driver (change to stop_pending status) before call WinDivertClose() to close all handles, does this cause to unknown behavior?

basil00 commented 2 years ago

AFAIK windivert_cleanup() will be called only when all windivert's handles reach to 0 reference. But on my machine it's still have 3 other handles (1 handle hanging, maybe?), this strange.

windivert_cleanup() is called by the WDF framework once the ref count for a given handle drops to zero. I assume the other handles are independent so should not matter, or else if they are duplicates (DuplicateHandle) the ref count should not be zero.

I also checked, and it seems what WinDivert is doing is correct, on paper at least:

_For example, a driver that provides an EvtDeviceFileCreate callback function might create an I/O queue to handle I/O requests that are associated with a particular framework file object. In this case the driver's EvtFileCleanup callback function must call WdfIoQueuePurge to purge the queue and then call WdfObjectDelete to delete it._

Basically, when the program calls WinDivertRecv there may not be any packet to service the request at that time. So WinDivert needs to queue the request (waiting for the next packet), which is why it has the read_queue.

So the current design appears to be sound at least, and the bug probably is something else. But I don't think I can make progress on this unless I can replicate the bug.