This update contains only security fixes and their test coverage.
All of these bugs are present in 4.5.4 and earlier. The get_layer4_v6 over-read is reached by reading an untrusted pcap with any of the tools. The remainder are reached through tcprewrite --fragroute=<rules-file> and require only an attacker-influenced fragroute rules file — no crafted packet content. Builds without libdnet (fragroute support disabled) are unaffected.
What's Changed
- SECURITY: fix heap buffer over-read in get_layer4_v6() (GHSA-jj65-mrgg-f5fx, CWE-125). get_ipv6_next() (src/common/get.c) validates the header it is given, but the pointer it returns is only checked with "ptr > end_ptr" — so it may be exactly end_ptr, or leave fewer bytes than a tcpr_ipv6_ext_hdr_base needs. get_layer4_v6() then read ip_nh straight off that pointer, one byte past the packet buffer, for a crafted IPv6 packet whose extension header chain runs to the end of the captured data. Reachable from tcpprep, tcprewrite and tcpreplay when reading an untrusted pcap. A bounds check is now applied at the three sites that dereference such a pointer. This was reported in 2024 against 4.4.4 and marked patched, but the reporter's proof-of-concept still reproduced on 4.5.4. Reported by msxfXF.
- SECURITY: fix stack buffer overflow in the fragroute rules-file parser (GHSA-777w-9599-w8g4, CWE-787). On a successful parse, mod_open() (src/fragroute/mod.c) accumulated a " -> -> ..." diagnostic of every parsed rule into a BUFSIZ (8192) local, then copied it into the caller's errbuf with an unbounded sprintf(); callers size errbuf at FRAGROUTE_ERRBUF_LEN (1024), so a rules file with a few hundred valid one-word directives overflowed a stack buffer in an ancestor frame (tcprewrite's main()) by several kilobytes, before any packet was processed. The message was written only on the success path, where errbuf is never read, so the whole diagnostic has been removed; the remaining errbuf writes in mod_open() are now bounded with snprintf(). Reported by tinyb0y.
- SECURITY: fix out-of-bounds write on an empty fragroute rules file (GHSA-p7xp-4gj2-x56c, CWE-787, CWE-191). The same removed diagnostic trimmed its trailing " -> " with buf[strlen(buf) - 4]. A rules file that parsed cleanly but produced no rules (empty, or only comments and blank lines) left buf empty, so the index underflowed size_t and wrote before the start of the buffer. Found while reviewing GHSA-777w-9599-w8g4; fixed by the same removal.
- SECURITY: fix off-by-one heap buffer overflow in the fragroute ip_chaff module (GHSA-m655-53p4-6qm8, CWE-193, CWE-787). ip_chaff_apply() (src/fragroute/mod_ip_chaff.c) called rand_strset() with (pkt_end - pkt_ip_data + 1), writing one byte past the end of the allocation pkt_dup() had just made; the call precedes the subtype switch, so it ran for every ip_chaff invocation (dup, opt, or a numeric TTL) on any ordinary IP packet. Also fixed in the same path: pkt_dup() (src/fragroute/pkt.c) never initialized the duplicate's pkt_buf_size, which ip_chaff's opt subtype then passed to ip_add_option() as a capacity bound, and its out-of-memory path freed the source packet — still linked in the caller's pktq — with free() rather than releasing the half-built duplicate with the matching brel(). Reported by tinyb0y.
- SECURITY: fix off-by-one heap buffer overflow in the fragroute tcp_chaff module (GHSA-v8c4-9w98-9v6v, CWE-193, CWE-787). tcp_chaff_apply() (src/fragroute/mod_tcp_chaff.c) had the identical defect in the sibling module that GHSA-m655-53p4-6qm8 covers, calling rand_strset() with (pkt_end - pkt_tcp_data + 1). Triggered by any tcp_chaff directive against an ordinary TCP packet. Found while auditing the ip_chaff fix.
- SECURITY: fix heap buffer overflow via negative fragment/segment size in the fragroute ip_frag and tcp_seg modules (GHSA-27v4-xhfx-g2rx, CWE-787, CWE-190). Both modules parsed their size argument with strtol() and rejected only zero; ip_frag's "must be a multiple of 8" check also passed negative multiples (-8 % 8 == 0 in C). A negative size then defeated the "does this fragment fit" guard (a signed comparison against a positive ptrdiff_t) and reached memcpy() as a huge implicitly-converted size_t, in ip_frag_apply_ipv4(), ip_frag_apply_ipv6() and tcp_seg_apply(). Both modules now require 1..IP_LEN_MAX at rules-file parse time, which also rejects strtol() overflow truncating to a negative int. Reported by tinyb0y.
- fragroute: check pkt_new()/pkt_dup() for failure in the ip_frag, tcp_seg and tcp_chaff modules. Six call sites dereferenced the returned packet immediately, so an allocation failure crashed on a NULL pointer instead of aborting the rule.
- fragroute: don't free a rule that is still linked into the rule list. mod_open()'s cleanup freed its last-allocated rule unconditionally; this was harmless only because the removed success-path diagnostic left the variable NULL, and would otherwise have left a dangling entry for mod_apply() to walk on every packet.
- test: add fragroute test cases (fragroute_valid, fragroute_negsize, fragroute_badrules) covering the modules above; previously the fragroute tree had no test coverage at all.
Full Changelog: v4.5.4...v4.5.5
Download the release by clicking the tcpreplay* assets below ...