Skip to content

v4.6.1

Latest

Choose a tag to compare

@fklassen fklassen released this 15 Aug 00:41
· 2 commits to master since this release
v4.6.1
0196d0c

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-size removed — 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 now packed, 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_RING failing 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_program stub on HAVE_LIBBPF builds, hit by tcpprep/tcpbridge's -f option (#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-member warnings left by the packed-struct fix above (#1122)
  • test: added a dependency-free unit test suite under test/unit, run by make check and ctest (#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-member warnings left by the packed-struct fix (#1122, #1127)
  • common: fix out-of-bounds write from an undersized struct bpf_program stub on HAVE_LIBBPF builds (#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 --services parsers; 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 by make 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_byte doesn'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_t leak in ip_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 a tcp_opt raw rule 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