| name | oss-fuzz-integrator |
| description | Integrates newly written LibFuzzer harnesses (along with their seed corpora and dictionaries) into an existing OSS-Fuzz project, then builds and packages both AddressSanitizer (asan) and UndefinedBehaviorSanitizer (ubsan) versions, saving each to a separate backup directory so neither build is overwritten.
Use this skill whenever the user wants to: - Add new fuzz harnesses to an OSS-Fuzz project - Package new harnesses using the OSS-Fuzz container workflow - Produce asan + ubsan instrumented fuzzer binaries via OSS-Fuzz - Integrate locally written drivers into an existing oss-fuzz build.sh / Dockerfile - "用oss-fuzz打包我写的harness" / "把新harness加入oss-fuzz构建"
Trigger proactively whenever the user has written new .c/.cpp harnesses in a target_project directory and mentions OSS-Fuzz, packaging, or sanitizers.
|
OSS-Fuzz Integrator
Integrates locally written LibFuzzer harnesses into an OSS-Fuzz project and
produces both ASan and UBSan instrumented builds, with each sanitizer's output
saved to a separate backup directory.
Step 1 — Gather facts
Before touching any files, collect these four things:
-
OSS-Fuzz root: the directory containing infra/helper.py
(e.g. /path/to/oss-fuzz)
-
Target project source: the directory containing the library source and
the new harnesses
(e.g. target_project/aom/)
-
OSS-Fuzz project name: search oss-fuzz/projects/ — the name may
differ from the source directory (e.g. aom → libaom)
ls <oss-fuzz>/projects/ | grep -i <libname>
-
New harnesses and seeds: find everything that needs to be added
find <target_project>/<lib> \
\( -name "*fuzzer*.c" -o -name "*fuzzer*.cpp" \
-o -name "*fuzz*.c" -o -name "*fuzz*.cpp" \) | sort
ls <target_project>/<lib>/fuzzing/seeds_*/
find <target_project>/<lib> -name "*.dict"
Read the existing build.sh to see what harnesses are already built. Only
add what is genuinely new — do not duplicate existing entries.
Step 2 — Copy files into the OSS-Fuzz project directory
Files placed in oss-fuzz/projects/<libname>/ are automatically COPY'd into
the Docker container at $SRC/ during build_image.
OSS_PROJECT=<oss-fuzz>/projects/<libname>
cp <target_project>/<lib>/fuzzing/<fuzzer>.c $OSS_PROJECT/
cp -r <target_project>/<lib>/fuzzing/seeds_<fuzzer> $OSS_PROJECT/
cp <target_project>/<lib>/fuzzing/<fuzzer>.dict $OSS_PROJECT/
Step 3 — Modify Dockerfile
Add COPY lines before the final WORKDIR line so the files land in
$SRC/ inside the container.
# New harnesses
COPY fuzzer_a.c fuzzer_b.c $SRC/
# Seed directories (each directory needs its own COPY line)
COPY seeds_fuzzer_a $SRC/seeds_fuzzer_a
COPY seeds_fuzzer_b $SRC/seeds_fuzzer_b
# Dictionary (if any)
COPY fuzzer_a.dict $SRC/
Step 4 — Modify build.sh
Append new compile + package commands after the existing fuzzer section.
Compile pattern for C harnesses
C sources must be compiled with $CC/$CFLAGS and linked with $CXX/$CXXFLAGS
because the LibFuzzer runtime is a C++ library.
for fuzzer in fuzzer_a fuzzer_b fuzzer_c; do
$CC $CFLAGS \
-I$SRC/<libsource> \
-I${build_dir} \
-c $SRC/${fuzzer}.c -o $WORK/${fuzzer}.o
$CXX $CXXFLAGS \
$WORK/${fuzzer}.o \
-o $OUT/${fuzzer} \
${build_dir}/lib<name>.a \
$LIB_FUZZING_ENGINE
if [ -d "$SRC/seeds_${fuzzer}" ] && [ -n "$(ls -A $SRC/seeds_${fuzzer})" ]; then
zip -j $OUT/${fuzzer}_seed_corpus.zip $SRC/seeds_${fuzzer}/*
fi
if [ -f "$SRC/${fuzzer}.dict" ]; then
cp $SRC/${fuzzer}.dict $OUT/${fuzzer}.dict
fi
done
Compile pattern for C++ harnesses
Use $CXX/$CXXFLAGS throughout — no separate compile/link split needed.
$CXX $CXXFLAGS \
-I$SRC/<libsource> \
-I${build_dir} \
$LIB_FUZZING_ENGINE \
$SRC/fuzzer.cpp \
-o $OUT/fuzzer \
${build_dir}/lib<name>.a
MSan special case
If the library uses inline ASM (e.g. libaom, libjpeg-turbo), MSan builds
require disabling ASM via a cmake flag. The existing build.sh usually handles
this already — just make sure your additions don't bypass the existing guard:
if [[ $CFLAGS = *sanitize=memory* ]]; then
extra_cmake_flags+="-DAOM_TARGET_CPU=generic"
fi
Step 5 — Build image
cd <oss-fuzz>
echo "N" | python3 infra/helper.py build_image <libname>
N skips pulling the latest base image (use local cache). If you need fresh
base images, answer y instead.
Confirm the image was built:
docker images | grep <libname>
Step 6 — Build and backup both sanitizers
build_fuzzers writes output to build/out/<libname>/ and overwrites it
on each run. Back up after each sanitizer so both versions are preserved.
OSS_BUILD=<oss-fuzz>/build/out/<libname>
python3 infra/helper.py build_fuzzers <libname> --sanitizer address
cp -r ${OSS_BUILD} ${OSS_BUILD}_address
echo "ASan build saved to: ${OSS_BUILD}_address"
python3 infra/helper.py build_fuzzers <libname> --sanitizer undefined
cp -r ${OSS_BUILD} ${OSS_BUILD}_undefined
echo "UBSan build saved to: ${OSS_BUILD}_undefined"
Final layout:
build/out/
├── <libname>/ ← last build (UBSan, keep or discard)
├── <libname>_address/ ← ASan instrumented binaries + corpora
└── <libname>_undefined/ ← UBSan instrumented binaries + corpora
Step 7 — Verify
for suffix in address undefined; do
echo "=== $suffix ==="
ls -lh <oss-fuzz>/build/out/<libname>_${suffix}/
done
Confirm for each build:
- All expected fuzzer binaries are present and executable
*_seed_corpus.zip files exist for harnesses that had seeds
*.dict files exist if dictionaries were provided
llvm-symbolizer is present
Common pitfalls
| Problem | Cause | Fix |
|---|
COPY failed: file not found | File not copied to projects/<libname>/ first | Run Step 2 again |
| Linker error on C harness | Used $CC for final link step | Split into compile ($CC) + link ($CXX) |
| Missing symbols from library | Wrong -I path or wrong .a path | Check build_dir variable in existing build.sh |
| Seeds not found | Wrong seed dir name | Use exact convention seeds_<fuzzer_name> |
python: command not found | System uses python3 | Replace python with python3 |
EOF when reading a line | build_image prompt not answered | Pipe echo "N" | before the command |
| UBSan build overwrites ASan | Forgot to cp -r after ASan | Always back up immediately after each build_fuzzers call |