Repository navigation
Native fuzzing on Jazzer: hostile read + round trip, smoke, nightly, negative control - #17
Merged
Merged
Conversation
…ke, nightly, negative control The reference runs a 60 s libFuzzer smoke per push and a nightly extended fuzz; serialize.java had no fuzzing. This adds the Java counterpart of fuzz.cpp on Jazzer 0.30.0 (standalone release, pinned and sha256 checked by the Makefile, recorded in tending/PINS.md), compiled with --release 17 -Xlint:all -Werror against the library classes only. - fuzz/serialize/fuzz/HostileReadFuzzer: arbitrary bytes through every ReadStream primitive under an op program; traps on a throw, an out of contract value, or a refusal breaking the refusal contract (latched, reason from the closed Refusal list, destination unwritten, the next read refuses without consuming bits); exact-array vs slack-array readers must agree. - fuzz/serialize/fuzz/RoundTripFuzzer: write -> measure -> read of generated values through one serialize body; traps on any asymmetry, an under-measure, a read not ending where the writer stopped, and a trailing byte not refused as trailing_data. - make fuzz / fuzz-read / fuzz-roundtrip (FUZZ_TIME, default 60). - make fuzz-control (and SABOTAGE=1): a scratch library with one int64 write asymmetry planted must be caught within the smoke budget. - ci.yml job fuzz (ubuntu-24.04): control + 60 s per target. - nightly-fuzz.yml: daily cron, workflow_dispatch duration (3600), cached cumulative corpus, crash reproducer upload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gap
The C++ reference runs a 60 s libFuzzer smoke on every push and a nightly extended fuzz; serialize.java had no fuzzing at all.
What this adds
A native coverage-guided harness on Jazzer 0.30.0 (standalone release, Apache-2.0), pinned and sha256-verified by a Makefile rule before anything is unpacked (hashes for linux-x86-64, linux-arm64 and macos recorded in
tending/PINS.md). The harness has no compile-time Jazzer dependency: each target is a plainfuzzerTestOneInput( byte[] )class compiled with the same--release 17 -Xlint:all -Werroragainst the library classes only. Runs with assertions on (-ea:serialize...), as the reference fuzzes its Debug build.fuzz/serialize/fuzz/HostileReadFuzzer.java: the reference's FuzzRead. A 32-byte op program drives arbitrary bytes through every ReadStream primitive: bits (1..32), bits64, bool, uint8/16/32/64, uint128, align, int (three range shapes), int64 (full and ranged), int128 (ranged over 1 to 4 groups, and full), fixed Q16.16, Q48.16 and Q112.16, int_relative, float, double, compressed_float, bytes, string, end. Traps on any throw, any accepted value outside its contract (range, finiteness, string length, NUL, unpaired surrogates, an end that leaves a bit behind), and any refusal that breaks the refusal contract: the stream not latched, no reason or one outside the closedRefusallist, a scalar destination written, or a later read that is accepted, consumes bits or changes the reason. In place of the reference's InitializePadded pass, the same bytes are read twice, from an exact-size array and from one with 8 bytes of set bits past the end, and the two readers must agree on every value, where they stop and why.fuzz/serialize/fuzz/RoundTripFuzzer.java: the reference's FuzzRoundTrip. Values generated from the input go through one serialize body against WriteStream, MeasureStream and ReadStream. Traps on any write/read asymmetry, on a measure that under-measures, on a read that doesn't end where the writer stopped (serializeEnd), and on a stream one byte longer whose end isn't refused astrailing_data.make fuzz(both),make fuzz-read,make fuzz-roundtrip(FUZZ_TIME, default 60), andmake fuzz-control. Fuzzing is the functional tier and isn't part ofmake all.fuzz(ubuntu-24.04): the negative control, then 60 s of each target. Crash reproducers are uploaded on failure..github/workflows/nightly-fuzz.yml, shaped like the reference's: daily cron at 08:00 UTC,workflow_dispatchinputduration(default 3600, per target), corpus restored and saved with actions/cache keyed by run id, crash reproducers uploaded on failure, ubuntu-24.04.Negative control (reversed witness)
make fuzz-control(equivalently, any fuzz target withSABOTAGE=1) builds a scratch copy ofsrc/with one write/read asymmetry planted byfuzz/serialize/fuzz/Sabotage.java.WriteStream.serializeInt64writes a value whose low 16 bits are0x5A5Aone higher than it is. If the needle stops matching, the tool fails; it never silently becomes a no-op. The round trip target then runs against that library from an empty corpus within the 60 s smoke budget. The control is green only if the fuzzer traps, and only on the planted int64 asymmetry. CI runs it on every push before the smoke.Local evidence (studio, 4 runs, under
nice -n 19):Clean-library smokes (20 s locally): hostile read ran 1,841,069 executions (about 88k/s) and round trip ran 272,547 (about 13k/s). Neither produced a finding.
make all(test, test-release, controls) is unchanged and green.🤖 Generated with Claude Code