sniff: reap the tcpdump prefilter subprocess in offline mode#5046
sniff: reap the tcpdump prefilter subprocess in offline mode#5046eugen-goebel wants to merge 2 commits into
Conversation
sniff(offline=..., filter=...) prefilters packets through a tcpdump subprocess, but the code kept only its stdout pipe and discarded the Popen. The process was never waited on, so it lingered as a zombie and Python emitted "ResourceWarning: subprocess N is still running". Get the process with getproc=True, attach it to the PcapReader, and reap it in close(): the read pipe is closed first, a still-running tcpdump then gets a SIGTERM, and wait() collects it. This also handles early stops (count=, timeout=), where tcpdump has not finished on its own. Fixes secdev#4512 AI-Assisted: yes (Claude Opus 4.8)
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5046 +/- ##
==========================================
+ Coverage 80.13% 80.47% +0.33%
==========================================
Files 388 388
Lines 96467 96657 +190
==========================================
+ Hits 77308 77785 +477
+ Misses 19159 18872 -287
🚀 New features to boost your workflow:
|
|
Looks good to me, but it only covers the filename paths. Would you mind extending the same fix to the others ? One |
… paths The previous commit only covered the offline sources given as filenames. The packet iterable branch (sniff(offline=IP()/UDP(...), filter=...)) and the file descriptor branch still built their PcapReader from a bare getfd=True pipe, so the tcpdump process was left unreaped there. Route both through the existing _offline_pcap_reader helper, generalized to take any source tcpdump() accepts (filename, IterSocket, open file descriptor), so every filtered offline path attaches the process to the reader and reaps it in close(). AI-Assisted: yes (Claude Opus 5)
|
Thanks @guedou, good catch. Extended the same treatment to the remaining two paths: the packet iterable branch (the one your They now share the same Verified on the packet path: before the change one child process is left unreaped after |
Problem
sniff(offline="file.pcap", filter="tcp")prefilters packets through atcpdumpsubprocess. The offline path builtPcapReader(tcpdump(..., getfd=True)), which returns only the stdout pipe, so thePopenobject was discarded and neverwait()ed. The process was left as a zombie, and Python 3 reports:Reproduction on current master:
Fix
As discussed in the issue, the reader now takes the process via
getproc=Trueand owns its lifetime.RawPcapReader.close()closes the read pipe, sends a still-runningtcpdumpaSIGTERM, andwait()s for it, so nothing is left behind. This also covers stopping early (count=,timeout=), wheretcpdumphas not exited on its own.Thanks to @AbhishekPandey1998 for scoping the
getprocapproach in the thread.Test
Added a regression test in
test/regression.utsthat reads a filtered offline capture (a full read and an earlycount=stop) and asserts nosubprocess ... still runningResourceWarningis emitted.Fixes #4512