Skip to content

fix(fuzz): build a minimal libpcap for oss-fuzz targets instead of linking the system one (#1092) - #1117

Merged
fklassen merged 1 commit into
4.6.1-beta1from
fix-oss-fuzz-static-libpcap
Aug 2, 2026
Merged

fix(fuzz): build a minimal libpcap for oss-fuzz targets instead of linking the system one (#1092)#1117
fklassen merged 1 commit into
4.6.1-beta1from
fix-oss-fuzz-static-libpcap

Conversation

@fklassen

@fklassen fklassen commented Aug 2, 2026

Copy link
Copy Markdown
Member

Fixing this ahead of a resubmission to OSS-Fuzz - found by the actual OSS-Fuzz build matrix (google/oss-fuzz#15924), not locally.

The failure

Every target across every engine/sanitizer combination OSS-Fuzz tried failed at startup:

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

The build itself succeeded. OSS-Fuzz's separate builder and runner images are the reason: the builder has libpcap.so because that's what apt-get install libpcap-dev put there, but the runner - where the built binaries actually execute during check_build/fuzzing - installs libcap2 only (per upstream infra/base-images/base-runner/install_deps.sh), not libpcap. A build that reports success but produces nothing that can run is worse than one that fails outright.

Why simply linking libpcap statically doesn't work

I tried that first. It doesn't fix anything - it just moves the missing library. Debian/Ubuntu's libpcap is built with D-Bus, Bluetooth, and USB-sniffing support enabled, so the static archive pulls in libdbus-1 and libsystemd (which itself needs libcap's cap_* symbols). Verified locally by trying exactly that and watching the missing-shared-library error move from libpcap.so to libdbus-1.so to a cap_get_proc link failure, one hop at a time.

The actual fix

None of that capture-backend code (D-Bus, Bluetooth, USB) is reachable from reading a pcap file, which is all these targets ever do. build.sh now clones and builds its own libpcap from source with -DDISABLE_DBUS=ON -DDISABLE_BLUETOOTH=ON -DDISABLE_LINUX_USBMON=ON -DDISABLE_RDMA=ON - matching what the actual libpcap OSS-Fuzz project's own build.sh already does, for this same reason. The result depends on nothing beyond libc/libstdc++/libm.

libpcap-dev stays in the Dockerfile for tcpreplay's own normal build (which still links the system package, unchanged) - only the fuzz targets' link step now uses the self-built copy.

Verification

Built a fake $SRC locally with both a fresh tcpreplay checkout and a fresh libpcap clone - exactly what the Dockerfile produces - and ran the actual updated build.sh against it with $CC=clang/$CXX=clang++/ASan+UBSan+libFuzzer flags:

  • All three targets built.
  • ldd on each shows only libstdc++/libm/libresolv/libgcc_s/libc/ld-linux - no libpcap.so, libdbus-1, or libsystemd.
  • Each passes OSS-Fuzz's own bad_build_check invocation exactly: -rss_limit_mb=2560 -timeout=25 -seed=1337 -runs=4 < /dev/null → exit 0. That's the precise check that was failing in the real CI run.
  • Each still runs cleanly against the checked-in corpus.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NBmWiWg46r8BLbdwozKo6v

…nking the system one (#1092)

Found by the actual OSS-Fuzz build matrix, not locally: every target across
every engine/sanitizer combination failed at startup with

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

The build itself succeeded - the OSS-Fuzz *builder* image has libpcap.so,
since that's what apt installed it there for. The separate *runner* image,
where the built binaries actually execute, does not: it installs libcap2
only (per upstream infra/base-images/base-runner/install_deps.sh), not
libpcap. A build that reports success but produces nothing that can run is
worse than one that fails outright.

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

None of that capture-backend code is reachable from reading a pcap file,
which is all these targets ever do, so it's built out entirely: build.sh now
clones and builds its own libpcap from source with
-DDISABLE_DBUS/DISABLE_BLUETOOTH/DISABLE_LINUX_USBMON/DISABLE_RDMA, matching
what the actual libpcap OSS-Fuzz project's own build.sh already does for
this same reason. The result depends on nothing beyond libc/libstdc++/libm,
verified with ldd against all three targets.

The Dockerfile (submitted separately to google/oss-fuzz, not tracked in this
repo per test/fuzz/README.md) gains a second git clone of tcpdump-group's
libpcap plus cmake/flex/bison to build it; libpcap-dev stays for tcpreplay's
own normal build, which still uses the system package as it always has -
only the fuzz targets' *link* step changes.

Verified end-to-end against a full simulated OSS-Fuzz environment (a fake
$SRC with both tcpreplay and a fresh libpcap clone, exactly what the
Dockerfile produces): all three targets build, `ldd` shows only
libc/libstdc++/libm/libgcc_s/libresolv, and each passes OSS-Fuzz's own
bad_build_check invocation
(-rss_limit_mb=2560 -timeout=25 -seed=1337 -runs=4 < /dev/null), which is
the exact check that was failing.
@fklassen
fklassen merged commit 3811d48 into 4.6.1-beta1 Aug 2, 2026
6 checks passed
@fklassen
fklassen deleted the fix-oss-fuzz-static-libpcap branch August 2, 2026 02:28
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