Skip to content

fuzzing: build with the sanitizers, seed the corpus, leave the caller's tree alone - #178

Merged
giuseppe merged 3 commits into
containers:mainfrom
kolyshkin:fuzzing-fixes
Oct 12, 2026
Merged

giuseppe merged 3 commits into
containers:mainfrom
kolyshkin:fuzzing-fixes

Conversation

@kolyshkin

Copy link
Copy Markdown
Collaborator

The fuzzing job does fuzz -- unlike the one in crun, the harness is linked
and coverage is real -- but it has been running without the sanitizers it
asks for, from a seven-file corpus, and it wipes and builds in whatever tree
the caller mounted.

The sanitizers were not in the build. hfuzz-clang decides whether to add
-fsanitize=address and -fsanitize=undefined by looking HFUZZ_CC_ASAN and
HFUZZ_CC_UBSAN up with getenv(2) as it compiles, but they were passed to
configure as arguments, which puts them in the environment of configure and
nowhere else, so none of the compiler invocations make runs ever saw them.
Exporting them takes the binary from no __asan_report* symbols at all to 48
of them, and the coverage guards honggfuzz reports from 13821 to 36707.

(The __ubsan* symbols are in the binary either way -- libhfuzz brings the
runtime along -- so they are not evidence that UBSan is instrumenting anything.)

The job built in the caller's tree. git clean -fdx and a full hfuzz-clang
build ran in /libocispec, the bind mount. In CI that is a fresh checkout, but
anyone following the same recipe locally loses every untracked file in their
working tree. The script now copies the tree to /tmp and works there.

The corpus was seven files. Seeded from
giuseppe/containers-fuzzing-corpus
now, whose config-json directory is 923 config.json units the three
runtime-spec modes can use, and kept outside the source tree so honggfuzz can
write to it.

Measured with the job run end to end from tests/fuzzing/Dockerfile:

before after
__asan_report* symbols 0 48
coverage guards 13821 36707
corpus units 7 936

All seven modes report crashes_count:0 on a clean tree with the sanitizers
in, so nothing here needed a fix in the library itself. The failure path was
checked separately: an abort() reachable from a crafted input makes the job
report crashes_count:1 and exit 1.

hfuzz-clang decides whether to add -fsanitize=address and
-fsanitize=undefined by looking HFUZZ_CC_ASAN and HFUZZ_CC_UBSAN up with
getenv(2) as it compiles.  They were passed to configure as arguments,
which puts them in the environment of configure and nowhere else, so the
compiler invocations make runs never saw them.

Export them instead: the fuzzing binary goes from no __asan_report*
symbols at all to 48 of them, and the number of coverage guards
honggfuzz reports from 13821 to 36707.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The script ran git clean -fdx and a full build in /libocispec, which is
the directory the caller bind mounts.  In CI that is a fresh checkout, but
anyone following the same recipe locally loses every untracked file in
their working tree and gets a hfuzz-clang build left in it afterwards.

Copy the tree to /tmp first and work there.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Every run started from the seven JSON files in tests/data, and honggfuzz
stores the units it discovers in its input directory, which is inside the
tree the run begins by wiping.

Seed the corpus from giuseppe/containers-fuzzing-corpus instead, whose
config-json directory is 923 config.json units the three runtime-spec
modes can use, and keep it out of the source tree.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin

Copy link
Copy Markdown
Collaborator Author

@giuseppe PTAL

@giuseppe
giuseppe merged commit abb7ab8 into containers:main Oct 12, 2026
7 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