Tcpreplay 4.6.1 is a security and hardening release. Its centerpiece is a new continuous fuzzing pipeline — three libFuzzer targets covering the pcap parser, the fragroute rules engine, and the tcpprep --services parser, submitted to OSS-Fuzz — which found and fixed nine defects in its first days running, on top of three new GHSA security advisories reported directly and a round of UBSan/ASan hardening across the packet parsers.
Highlights
- Continuous fuzzing via OSS-Fuzz — three new libFuzzer targets (
fuzz_pcap,fuzz_fragroute,fuzz_services) run continuously against every commit; this release fixes all nine issues they found in their first run, from a heap-buffer-overflow write to a resource-exhaustion hang - 3 new security advisories fixed, two of them CVSS 7.0+ (High)
- UBSan now runs alongside ASan in CI, catching a class of misaligned-access bugs that ASan alone doesn't — the fix also made wire-format header structs
packed, removing systemic misaligned access across the packet parsers --xdp-batch-sizeremoved — measurement on 100GigE found no benefit from raising it above the default of 1, now that AF_XDP sends pipeline across the whole umem (from 4.6.0)
Security
Three new advisories, all reported by tao pan (@pant0m):
| Advisory | CVSS | Severity | Component |
|---|---|---|---|
| GHSA-4hqm-8v2c-9pwj | 7.1 | High | Three heap out-of-bounds reads in tcpliveplay's pcap parsing — one can leak adjacent heap memory onto the live network
|
| GHSA-pmmx-m8p5-969j | 7.0 | High | Inverted bounds check in the dlt_radiotap plugin — an 8-year-old >=/<= typo that made an oversized memcpy() run exactly when it was guaranteed to overflow. Not reachable through the bundled CLIs, which clamp caplen; only third-party code linking libtcpedit directly on unclamped input is affected
|
| GHSA-p3f2-88rg-9mch | 6.1 | Medium | Heap out-of-bounds read in tcpprep cache-file parsing — the file's packets_per_byte field was never cross-checked against the hardcoded indexing stride every reader actually uses
|
Continuous fuzzing: nine issues found and fixed
This cycle added test/fuzz/ — three libFuzzer targets built against ASan/UBSan and submitted to OSS-Fuzz (#1092, #1101, #1103). Every issue below was found by that pipeline before it ever reached a user, and none had a public GitHub issue filed for it (#1118) — they're listed here for the first time now that fixes are shipped.
| Finding | Crash type | Fix |
|---|---|---|
ip_chaff_apply() heap-buffer-overflow write
| 2-byte OOB write | A buffer-capacity calculation assumed the IP header started 2 bytes earlier than it actually does (missing a PKT_BUF_ALIGN offset), overstating room by exactly 2 bytes — libdnet wrote an inserted IP option 2 bytes past the heap allocation
|
ip_chaff_apply() pointer corruption → OOB read
| Out-of-bounds read | The option-insert path used libdnet's return value unconditionally, including on failure, silently shifting a packet pointer out of bounds on every failed call; a rules file stacking several ip_chaff opt directives could walk it far enough to underflow a length calculation downstream
|
mod_apply() exponential packet growth
| Timeout (>60s) | Duplicating rules (ip_chaff, tcp_chaff) double the packet queue on every application; stacking ~30 of them in a rules file turns one packet into gigabytes of output. Now bounded at a hard packet-count cap between rule applications
|
mod_close() never called
| Direct memory leak | A fully-implemented cleanup function that freed the whole parsed rule chain was never wired up — leaked on every fragroute_close() call, not just in fuzzing
|
rand_t leak in ip_frag/tcp_seg
| Direct memory leak | Both modules store their RNG handle in a file-scope static rather than per-rule heap state; a repeated directive overwrote the handle without closing the previous one |
pktq_shuffle() on an empty queue
| Unexpected exit | An empty-queue edge case was misdiagnosed as an allocation failure and called exit()
|
get_l2len_protocol() on an unsupported DLT
| Unexpected exit | The one error path in the function that called exit() instead of returning an error code, like every other branch
|
raw_ip_opt_parse() too-few-tokens
| Null dereference | A tcp_opt raw rule with one fewer token than ip_opt raw needs slipped past a caller-side length check and read past the token array
|
delay_apply() on an empty queue
| Null dereference | Same empty-queue class as pktq_shuffle() above, in a different module
|
Other fixes
- UBSan hardening: fixed misaligned MPLS label parsing and a negative left shift in fragroute's
ip_ttl; wire-format header structs are nowpacked, fixing systemic misaligned access flagged once UBSan ran in CI (#1100, #1104) - fragroute: fixed a use-after-free in
pkt_close()on repeated context setup (#1102) - txring: fixed
TX_RINGfailing outright on interfaces with an MTU of ~1365 or less, e.g. 1280, the IPv6 minimum (#1090) - common: fixed an out-of-bounds write from an undersized
struct bpf_programstub onHAVE_LIBBPFbuilds, hit bytcpprep/tcpbridge's-foption (#1121) - fragroute: fixed an uninitialized-stack read in
mod_open()'s debug logging — an intermittent crash under--dbug(#1124) - tcpedit: fixed 17
-Waddress-of-packed-memberwarnings left by the packed-struct fix above (#1122) - test: added a dependency-free unit test suite under
test/unit, run bymake checkandctest(#1079) - build: minor compilation fixes and warning cleanups found while building with meson
warning_level=3(#1116, contributed by @GabrielGanne)
Credits
Thanks to tao pan (@pant0m) for the three security reports behind this release, and to @GabrielGanne for compilation cleanups. The remaining nine fixes came from the new OSS-Fuzz pipeline this release also introduces.
What's Changed
- xdp: remove
--xdp-batch-size— measurement on 100GigE found no benefit from raising it above the default of 1 (#1128) - tcpedit: fix 17
-Waddress-of-packed-memberwarnings left by the packed-struct fix (#1122, #1127) - common: fix out-of-bounds write from an undersized
struct bpf_programstub onHAVE_LIBBPFbuilds (#1121, #1125) - fragroute: fix uninitialized-stack read in
mod_open()'s debug logging under--dbug(#1124) - fix:
flow_decode()over-required bytes for a minimal ICMP/ICMPv6 header (#1119, #1120) - fix(fuzz): don't auto-file public GitHub issues from OSS-Fuzz findings (#1092, #1118)
- fix(fuzz): build a minimal libpcap for OSS-Fuzz targets instead of linking the system one (#1092, #1117)
- ci: run UBSan alongside ASan; mark wire-format header structs packed (#1101, #1104, #1105, #1112)
- test: add libFuzzer targets for the pcap, fragroute rules, and tcpprep
--servicesparsers; submit to OSS-Fuzz (#1092, #1103, #1113, #1114, #1115) - txring: fix TX_RING failing outright on interfaces with an MTU of ~1365 or less (#1090, #1107, #1109, #1111)
- test: add a dependency-free unit test suite under
test/unit, run bymake check/ctest(#1079, #1091, #1099, #1106) - fragroute: fix a use-after-free in
pkt_close()on repeated context setup (#1102) - build: minor compilation fixes and warning cleanups found building with meson
warning_level=3(#1116) - Security: fix inverted bounds check in
dlt_radiotap_get_80211()— GHSA-pmmx-m8p5-969j (#1141) - Security: fix three heap OOB reads in
tcpliveplay's pcap parsing — GHSA-4hqm-8v2c-9pwj (#1140) - Security: reject cache files whose
packets_per_bytedoesn't match the hardcoded indexing stride — GHSA-p3f2-88rg-9mch (#1139) - fragroute: bound
mod_apply()against exponential packet-count growth (OSS-Fuzz 546146015, #1138) - fragroute: fix a
rand_tleak inip_frag_open()/tcp_seg_open()on a repeated directive (OSS-Fuzz 545925322, #1137) - fragroute: wire up
mod_close(), implemented but never called (OSS-Fuzz 545818605, #1136) - fragroute: fix a null-deref in
delay_apply()on an empty packet queue (OSS-Fuzz 545965632, #1135) - fragroute: fix a null-deref in
raw_ip_opt_parse()on atcp_opt rawrule with too few tokens (OSS-Fuzz 545904184, #1134) - fragroute: fix pointer corruption in
ip_chaff_apply()on a failed option insert (OSS-Fuzz 545925319, #1133) - fragroute: fix a heap-buffer-overflow in
ip_chaff_apply()'s option insertion (OSS-Fuzz 545965630, #1132) - common: fix an Unexpected-exit in
get_l2len_protocol()on an unsupported DLT type (OSS-Fuzz 545718476, #1131) - fragroute: fix an Unexpected-exit in
pktq_shuffle()on an empty packet queue (OSS-Fuzz 545904182, #1130)
Verifying the download
The .tar.gz/.tar.xz tarballs are accompanied by detached PGP signatures (.asc), signed with the tcpreplay release key (tcpreplay@appneta.com, fingerprint 84E4FA215C934A7D97DC76D5E9E2149793BDE17E):
gpg --verify tcpreplay-4.6.1.tar.xz.asc tcpreplay-4.6.1.tar.xz
Full Changelog: v4.6.0...v4.6.1