Skip to content

gpac: add extension-aware demux/render harnesses and seed corpora#65

Open
tc-agent wants to merge 2 commits into
masterfrom
improve-gpac-fuzzing-coverage
Open

gpac: add extension-aware demux/render harnesses and seed corpora#65
tc-agent wants to merge 2 commits into
masterfrom
improve-gpac-fuzzing-coverage

Conversation

@tc-agent

Copy link
Copy Markdown
Owner

Motivation

The five existing GPAC OSS-Fuzz harnesses all write their input to a
file at /tmp/libfuzzer.<pid> with no extension and then feed it
through a full GPAC filter session. Because GPAC's text and scene
source filters (load_bt_xmt, load_svg, dashin, hlsin, nhml,
...) declare their inputs by extension via CAP_STRING(... GF_PROP_PID_FILE_EXT, "bt|xmt|wrl|x3d|x3dv|swf|..."), none of those
filters can ever be selected from the upstream harnesses. Per
Fuzz Introspector,
the project overall sits at 15.84% line coverage (78,594 / 496,264);
fuzz_scene 1.03%, fuzz_route 1.44%, fuzz_parse 3.87%, and
fuzz_m2ts_probe 0.07% all reflect that most of the GPAC source tree
is unreachable from the current harness set.

Changes

Two extension-aware harnesses (added to projects/gpac/harnesses/
and compiled by build.sh, alongside the upstream testsuite/oss-fuzzers/
loop):

  • fuzz_demux.c reads the first input byte as an index into a
    63-entry extension table, writes the rest to
    /tmp/fzd_<pid>.<ext>, and runs gf_fs_load_source +
    inspect:deep:analyze=bs. This unlocks the text/scene source
    filters that are unreachable from fuzz_probe_analyze.
  • fuzz_render.c uses the same selector byte but routes the input to
    an .mp4 destination via gf_fs_load_destination. The session
    resolver inserts the compositor (for scene sources) or the
    reframe-and-mux chain (for media sources), exercising
    filters/mux_isom.c, isomedia/isom_write.c, the compositor, and
    the scene-graph node constructors — none of which are reachable
    from the inspect-only harnesses. A fuzz_render.options file
    disables libFuzzer leak detection because the GPAC filter session
    retains ~96 B of long-lived state at teardown that the run-shutdown
    leak check otherwise flags on every input.

Both harnesses use a pthread watchdog that calls gf_fs_abort after
7–10 seconds so unbounded scene animations and DASH/HLS manifests
cannot stall the session past libFuzzer's per-input timeout.

Self-contained seed generator (projects/gpac/gen_fuzz_seeds.py,
invoked from build.sh): synthesises small, probe-valid files for
~40 container, codec and scene formats (WAV, AIFF, AVI, FLV, OGG /
Opus, MPEG-PS / TS / M2TS, MKV / WebM, FLAC, AC-3, DTS, GIF, BMP, AMR,
NHML, raw H.264 / HEVC, ADTS-AAC, M4V, M1V, ISOBMFF with rich box
trees, DASH MPD, HLS M3U8, SVG, BIFS-text, XMT, ...) and reuses the
real media samples that already live in testsuite/media/auxiliary_files/
plus a selection of the scene assets under testsuite/media/{bifs, laser,svg,x3d}/. The generator writes one
<harness>_seed_corpus.zip per broad harness into $OUT. No
binary blobs are committed to oss-fuzz
— every byte is either
generated by the Python script or sourced from the testsuite
submodule that the Dockerfile already pulls.

The upstream harness build loop in build.sh is left untouched; the
new code is appended after it and only adds new files. The existing
fuzz_parse_seed_corpus.zip produced by the upstream loop is
overwritten by the generator with a superset (still ISOBMFF-only and
≤64 KiB, matching the fuzz_parse 65,536-byte cap).

Coverage

Baseline numbers are taken from
https://introspector.oss-fuzz.com/project-profile?project=gpac
(retrieved while preparing this PR): 15.84% overall, with the
existing harnesses at 12.52% (fuzz_probe_analyze), 3.87%
(fuzz_parse), 1.44% (fuzz_route), 1.03% (fuzz_scene), and 0.07%
(fuzz_m2ts_probe).

After 5 minutes of libFuzzer per harness, running all harnesses
concurrently with the standard OSS-Fuzz run_fuzzer driver, the
coverage build (infra/helper.py coverage) reports a harness-excluded
global line coverage of 19.56% (97,093 / 496,380) — a +3.72-point
absolute lift on the baseline (a ~24% relative increase in lines
covered). The single new fuzz_render harness alone reaches 15.70%
line coverage on the same corpus.

Selected per-file moves (FI baseline → this PR, coverage build):

File Lines Baseline This PR
compositor/compositor.c 3,405 0.00% 38.1%
scene_manager/loader_xmt.c 2,709 0.00% 66.4%
scene_manager/loader_bt.c 3,077 0.00% 33.6%
scenegraph/mpeg4_nodes.c 35,223 0.00% 13.2%
scenegraph/svg_attributes.c 5,149 0.00% 31.8%
filters/mux_isom.c 6,930 0.00% 25.4%
isomedia/isom_write.c 7,015 2.40% 20.3%
quickjs/quickjs.c 45,187 0.00% 18.5%
media_tools/av_parsers.c 12,899 36.7% 32.6%

The dominant remaining 0%-covered files are GPAC components that need
either a graphical backend (most of compositor/svg_*.c, much of
evg/), encoders compiled against libraries not present in the
OSS-Fuzz base-builder (filters/ff_*, dasher's segmented output), or
operations beyond demux/remux (network downloaders, ROUTE demux, the
TS muxer). Reaching them is not addressed by this PR.

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Fuzzing Coverage Report

Tested: project gpac · base 2de60f9 → head 05e4872 · 300s total fuzz budget · updated 2026-05-27 18:12 UTC · workflow run

Metric Before After Delta
Static reachability >45m >45m
Line coverage 5.5% (27403/496444) 21.1% (104738/496444) +282.2%
Branch coverage 4.8% (15279/320731) 17.0% (54570/320731) +257.2%
Function coverage 11.0% (1747/15885) 32.8% (5206/15885) +198.0%

Per-harness

Harness Lines before Lines after Δ
fuzz_demux 0% 8.6% (42445/496312) new
fuzz_m2ts_probe 0.1% (331/496324) 0.1% (331/496324) +0.0%
fuzz_parse 1.5% (7276/496347) 1.6% (8059/496347) +10.8%
fuzz_probe_analyze 2.0% (9838/496329) 8.7% (42959/496329) +336.7%
fuzz_render 0% 15.7% (78001/496312) new
fuzz_route 1.1% (5686/496339) 1.1% (5627/496339) -1.0%
fuzz_scene 1.8% (8960/496353) 1.4% (7075/496353) -21.0%

Δ = (after − before) / before, to accommodate that denominators may change. "new" when before is 0; "deleted" when after is 0.

@tc-agent
tc-agent force-pushed the improve-gpac-fuzzing-coverage branch from 06e09b0 to 08626a8 Compare May 27, 2026 06:33
@tc-agent
tc-agent force-pushed the master branch 5 times, most recently from b5fd10c to 712a52f Compare May 27, 2026 16:16
@tc-agent
tc-agent force-pushed the improve-gpac-fuzzing-coverage branch from 08626a8 to 05e4872 Compare May 27, 2026 16:42
@tc-agent
tc-agent force-pushed the master branch 6 times, most recently from af7f9a7 to 806b281 Compare May 28, 2026 18:05
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.

1 participant