Skip to content

Add tcpreplay project - #15924

Open
fklassen wants to merge 3 commits into
google:masterfrom
fklassen:add-tcpreplay
Open

Add tcpreplay project#15924
fklassen wants to merge 3 commits into
google:masterfrom
fklassen:add-tcpreplay

Conversation

@fklassen

Copy link
Copy Markdown

tcpreplay replays and rewrites captured network traffic (pcap files): https://github.com/appneta/tcpreplay

Motivation

15 security advisories were published against it in 2026, every one found by an outside researcher rather than the project itself. The bug classes are what a fuzzer finds quickly - off-by-one writes, unchecked attacker-supplied lengths, sign confusion, unbounded copies - and there was no fuzzing infrastructure in the repository at all.

The three targets

Target Surface
fuzz_pcap libpcap read path + shared header parsers, DLT chosen by the input so one target reaches the whole link-layer plugin matrix
fuzz_fragroute the fragroute rules-file parser, then runs a packet through the module chain it builds - several past advisories are in the modules' apply paths, not the parser
fuzz_services tcpprep's --services parser

They're also built as a plain standalone corpus-replay program (no libFuzzer/clang needed) and run under make check on every build of the project, so a crash this finds and gets committed to the corpus becomes a permanent regression test for everyone, not just people with a fuzzing toolchain installed.

One thing worth flagging

The Dockerfile pins git clone -b 4.6.1-beta1, not the default branch - the fuzz targets haven't reached the project's master yet (they landed this cycle). Noted in project.yaml's own comment for whoever revisits it: drop the branch pin once that release merges to master.

Verification

No Docker available in the environment I built this in, so I couldn't run infra/helper.py build_fuzzers/check_build directly. Instead:

  • Ran build.sh manually against a fresh checkout with $CC=clang $CXX=clang++ and $CFLAGS/$CXXFLAGS/$LIB_FUZZING_ENGINE set to what this environment supplies (ASan+UBSan, -fsanitize=fuzzer). All three targets built and linked cleanly.
  • Ran each against the checked-in seed corpus with no crashes, then ran each in actual fuzzing mode for several seconds - several million iterations apiece, no crashes:
    fuzz_pcap:      3,955,633 runs in 6s
    fuzz_services:     49,278 runs in 6s
    fuzz_fragroute:    83,771 runs in 6s
    
  • python3 infra/presubmit.py (license, project.yaml schema, $LIB_FUZZING_ENGINE usage, seed-corpus, apt-update-before-install) passes clean.

Happy to iterate based on your own CI if the actual OSS-Fuzz build environment surfaces anything this couldn't catch.

tcpreplay replays and rewrites captured network traffic (pcap files). 15
security advisories were published against it in 2026, every one of them
found by an outside researcher rather than the project itself - the bug
classes were exactly what a fuzzer finds quickly (off-by-one writes,
unchecked attacker-supplied lengths, sign confusion, unbounded copies), and
there was no fuzzing infrastructure in the repository at all.

Three libFuzzer harnesses, covering the surfaces behind most of that history:

  fuzz_pcap       the libpcap read path + shared header parsers, DLT chosen
                  by the input so one target reaches the whole plugin matrix
  fuzz_fragroute  the fragroute rules-file parser, and then runs a packet
                  through the module chain it builds - several of the past
                  advisories are in the modules' apply paths, not the parser
  fuzz_services   tcpprep's --services parser

The harnesses are also built as a plain standalone corpus-replay program
(no libFuzzer/clang needed) and run under `make check` on every build of the
project, so a crash OSS-Fuzz finds and gets committed to the corpus becomes
a permanent regression test for everyone, not just people with a fuzzing
toolchain installed.

Branch pinned to 4.6.1-beta1 rather than the default branch: the fuzz
targets haven't reached the project's master yet (see the comment in
project.yaml). Verified build.sh manually against a fresh checkout with
$CC=clang $CXX=clang++ and the ASan+UBSan+libFuzzer flags this environment
would supply - all three targets build, run cleanly against the checked-in
corpus, and ran several million iterations apiece in a few seconds with no
crashes. `infra/presubmit.py` passes clean.
@google-cla

google-cla Bot commented Jul 29, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions

Copy link
Copy Markdown

fklassen is integrating a new project:
- Main repo: https://github.com/appneta/tcpreplay.git
- Criticality score: 0.49610

@DavidKorczynski DavidKorczynski left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better late than never :D #5546

Project looks good, can you sign the CLA?

Comment thread projects/tcpreplay/project.yaml Outdated
main_repo: "https://github.com/appneta/tcpreplay.git"
language: c
primary_contact: "tcpreplay.dev@gmail.com"
file_github_issue: true

@DavidKorczynski DavidKorczynski Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means a public github issue will be created once an issue is found, potentially disclosing security vulns. Are you sure you want this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you word it that way, maybe this isn’t what I want. Let me discuss this with others.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed - set to false. Findings will route to primary_contact by email instead. Thanks for the review!

The initial submission's build succeeded, but every target failed at
startup in the runner image:

    error while loading shared libraries: libpcap.so.0.8: cannot open
    shared object file: No such file or directory

The base-builder image has libpcap.so (apt installed it there); the
runner image, where check_build/fuzzing actually execute the binary,
installs libcap2 only, not libpcap.

Statically linking the system libpcap.a doesn't fix it, it just moves the
missing library one hop: Debian/Ubuntu's package is built with D-Bus,
Bluetooth and USB-sniffing support, so the static archive itself pulls in
libdbus-1 and libsystemd (which needs libcap's cap_* symbols in turn) -
verified by trying exactly that.

None of that capture-backend code is reachable from reading a pcap file,
which is all these targets do, so it's built out entirely: build.sh now
clones and builds its own libpcap with
-DDISABLE_DBUS/DISABLE_BLUETOOTH/DISABLE_LINUX_USBMON/DISABLE_RDMA - the
same thing the libpcap project's own OSS-Fuzz integration already does,
for this same reason. The result depends on nothing beyond
libc/libstdc++/libm - verified with ldd against all three targets, and
each passes check_build's exact invocation
(-rss_limit_mb=2560 -timeout=25 -seed=1337 -runs=4 < /dev/null).

libpcap-dev/cmake/flex/bison added to the Dockerfile (cmake/flex/bison to
build libpcap from source; libpcap-dev unchanged, still used by
tcpreplay's own normal build).
Flagged in review by David Korczynski: file_github_issue: true means a
public GitHub issue gets filed on appneta/tcpreplay the instant a crash is
found, before anyone there has had a chance to look at it privately. For a
project whose whole reason for adding fuzzing is 15 externally reported
CVEs in one year, that's the wrong default. Findings now route to
primary_contact by email instead.
GabrielGanne pushed a commit to GabrielGanne/tcpreplay that referenced this pull request Aug 3, 2026
appneta#1092)

Flagged in review on the submission PR (google/oss-fuzz#15924) by a project
maintainer: file_github_issue: true means OSS-Fuzz auto-files a *public*
GitHub issue on this repo the instant it finds a crash. For a project whose
entire reason for adding fuzzing is 15 externally reported CVEs in one year,
that's backwards - it discloses a vulnerability, potentially with a
reproducer attached, before anyone here has had a chance to look at it
privately.

Set to false. Findings now route to primary_contact by email instead, which
is what OSS-Fuzz's own responsible-disclosure timeline (private first, then
public after a fix ships or 90 days pass) actually assumes.
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.

3 participants