Skip to content

4.5.5 - #1067

Merged
fklassen merged 3 commits into
masterfrom
4.5.5
Jul 23, 2026
Merged

4.5.5#1067
fklassen merged 3 commits into
masterfrom
4.5.5

Conversation

@fklassen

Copy link
Copy Markdown
Member

Release 4.5.5 — security fixes for the fragroute rules-file parser and modules.

Every one of these bugs is present in the released 4.5.4. Until now the fixes existed only on the unreleased 4.6.0-beta2 branch, so the advisories had no shippable remedy for the 4.5.x line that distributions package.

Security fixes

advisory defect
GHSA-777w-9599-w8g4 mod_open() built a rule-list diagnostic in a BUFSIZ (8192) local and sprintf()'d it into the caller's 1024-byte errbuf, smashing an ancestor stack frame
GHSA-p7xp-4gj2-x56c the same code trimmed a trailing " -> " with buf[strlen(buf) - 4], underflowing size_t on a rules file that parsed cleanly but yielded no rules
GHSA-m655-53p4-6qm8 ip_chaff_apply() passed (pkt_end - pkt_ip_data + 1) to rand_strset(), writing one byte past the duplicate's allocation
GHSA-v8c4-9w98-9v6v tcp_chaff_apply() had the identical off-by-one
GHSA-27v4-xhfx-g2rx ip_frag/tcp_seg rejected only a zero size; ip_frag's "multiple of 8" test admits negatives (-8 % 8 == 0), reaching memcpy() as a huge size_t

Also fixed: pkt_dup() left the duplicate's pkt_buf_size uninitialized and its OOM path freed the source packet with free() instead of releasing the duplicate with brel(); six pkt_new()/pkt_dup() call sites dereferenced the result without a NULL check; mod_open() freed a rule still linked into the rule list.

The 4.5.4 tcp_opt/ip6_opt/ip_opt fixes are untouched — this is strictly additive.

Tests

Adds fragroute_valid, fragroute_negsize and fragroute_badrules to the tcprewrite group, gated on COMPILE_FRAGROUTE. The fragroute tree previously had no test coverage at all, which is how these went unnoticed.

Note the limit: fragroute_valid cannot catch the one-byte ip_chaff/tcp_chaff overflows in an ordinary build, since they do not crash an unsanitized binary — it needs --enable-asan. The other two catch their bugs via SIGSEGV in a plain build. This is documented above the target.

Verification

Built with --enable-asan and replayed six proof-of-concept rules files: all clean on this branch, and all six still trip AddressSanitizer on pristine 4.5.4 built identically (negative-size-param ×2, heap-buffer-overflow ×2, stack-buffer-overflow ×2). The tcprewrite test group passes, including the three new targets.

Tagged v4.5.5, signed per the release checklist with -u tcpreplay@appneta.com.

Reported by tinyb0y.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W2Rdq79uuiVVq9G9GyuvDw

galastar and others added 3 commits July 23, 2026 16:07
Every one of these bugs is present in the released 4.5.4; until now the
fixes existed only on the unreleased 4.6.0-beta2 branch, so the advisories
had no shippable remedy for the 4.5.x line that distributions package.

Backported from 4.6.0-beta2 (7f614de, 08b3c6c):

  GHSA-777w-9599-w8g4  mod_open() built a rule-list diagnostic in a BUFSIZ
    (8192) local and sprintf()'d it into the caller's 1024-byte errbuf,
    smashing an ancestor stack frame. Removed - it was written only on the
    success path, where errbuf is never read. Remaining errbuf writes now
    use snprintf().

  GHSA-p7xp-4gj2-x56c  The same code trimmed a trailing " -> " with
    buf[strlen(buf) - 4], underflowing size_t when a rules file parsed
    cleanly but yielded no rules (empty or comment-only).

  GHSA-m655-53p4-6qm8  ip_chaff_apply() passed (pkt_end - pkt_ip_data + 1)
    to rand_strset(), writing one byte past the duplicate's allocation.
    Also: pkt_dup() left the duplicate's pkt_buf_size uninitialized, and
    its OOM path freed the source packet - still linked in the caller's
    pktq - with free() instead of releasing the duplicate with brel().

  GHSA-v8c4-9w98-9v6v  tcp_chaff_apply() had the identical off-by-one.

  GHSA-27v4-xhfx-g2rx  ip_frag and tcp_seg rejected only a zero size, and
    ip_frag's "multiple of 8" test admits negatives (-8 % 8 == 0). Both now
    require 1..IP_LEN_MAX at parse time.

Also checks pkt_new()/pkt_dup() for failure at six call sites, and stops
mod_open() freeing a rule that is still linked into the rule list.

The 4.5.4 tcp_opt/ip6_opt/ip_opt fixes are untouched and still present;
this is strictly additive to that work.

Verified by building this branch with --enable-asan and replaying the six
proof-of-concept rules files: all are clean here, and all six still trip
AddressSanitizer on pristine 4.5.4 built the same way (negative-size-param
x2, heap-buffer-overflow x2, stack-buffer-overflow x2).

Reported by tinyb0y.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backport of 4b628de from 4.6.0-beta2, adapted to this branch: EXTRA_DIST
here has no test_nano.pcap, which is a 4.6 addition.

Adds three targets to the tcprewrite group, gated on COMPILE_FRAGROUTE.
fragroute output embeds random IP IDs and random chaff bytes, so there is
no golden file to diff; these check exit status, distinguishing a clean
rejection (tcprewrite exits 255) from a crash (128..254 is a signal):

  fragroute_valid     twelve valid rule sets must parse, run and produce
                      output
  fragroute_negsize   negative and zero sizes refused at parse time
  fragroute_badrules  empty, comment-only and 300-directive rules files

Note that fragroute_valid cannot catch the one-byte ip_chaff/tcp_chaff
overflows in an ordinary build - they do not crash an unsanitized binary -
so it needs --enable-asan for those. The other two catch their bugs via
SIGSEGV in a plain build. This is documented above the target.

test.pcap is unusable here: fragroute treats the first non-IP packet as
fatal. test_fragroute.pcap is a 20-packet IP-only subset (5 KB), 15 of
them TCP with ACK and payload so tcp_seg and tcp_chaff have work to do.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The target checked only that tcprewrite exited non-zero and not from a
signal. tcprewrite exits 255 for any fatal error, so the test passed even
when it never evaluated the rule at all - a missing input pcap produced
the same 255 and read as success. That surfaced when the fixture was
absent from a build tree: fragroute_valid and fragroute_badrules failed
correctly while fragroute_negsize reported OK.

It now also requires the expected size-rejection message in the output,
so a failure for any other reason is a failure. Verified both ways: it
passes with the fixture present and fails with it removed, where it
previously false-passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@fklassen
fklassen merged commit 89dff7b into master Jul 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants