Skip to content

ossfuzz: add zip_source_zip_fuzzer for partial-window extraction paths#543

Open
tejgokani wants to merge 1 commit into
nih-at:mainfrom
tejgokani:test/fuzz-zip-source-zip-windowing
Open

ossfuzz: add zip_source_zip_fuzzer for partial-window extraction paths#543
tejgokani wants to merge 1 commit into
nih-at:mainfrom
tejgokani:test/fuzz-zip-source-zip-windowing

Conversation

@tejgokani

Copy link
Copy Markdown

Overview

This adds a new OSS-Fuzz target, zip_source_zip_fuzzer, that exercises the
zip_source_zip windowing and raw-extraction code in zip_source_zip_new.c,
which the current read-side fuzzers do not reach.

Coverage gap

zip_read_fuzzer, zip_read_file_fuzzer and zip_read_metadata_fuzzer all read
entry data through zip_fopen_index(). That path always calls
zip_source_zip_file_create() with flags = 0, start = 0 and len = -1, i.e.
"decode the whole entry from the beginning". As a result several branches of
zip_source_zip_file_create() are never executed during fuzzing:

  • Partial windows (start > 0 and/or len >= 0): the sub-range offset
    arithmetic and the overflow / past-the-end-of-file checks
    (start + len < start, start + len > st.size, the ZIP_INT64_MAX clamps).
  • ZIP_FL_COMPRESSED: returning the raw compressed bytes wrapped in a window
    source instead of decompressing.
  • ZIP_FL_UNCHANGED: dirent/stat selection for the original on-disk entry.
  • zip_source_zip_create() itself, the public API used to read an entry of
    one archive as a source for another.

These combine caller-supplied start/len with sizes parsed from the central
directory and then layer window → decrypt → decompress → crc sources on top, so
they are worth fuzzing directly.

What the target does

For the fuzz input interpreted as an archive, it iterates every entry and, for
each, creates a zip_source_zip with several flag / start / len combinations
derived from the entry's stated size:

  • whole-entry decode, ZIP_FL_COMPRESSED raw window, and ZIP_FL_UNCHANGED;
  • in-range partial windows ([1, size/2], the second half, [0, size-1]);
  • boundary and past-the-end ranges (start == size, start == size + 1) to
    drive the rejection paths.

Each resulting source is opened and drained through the source interface so the
window, decrypt, decompress and crc layers actually run. A default password is
set so encrypted entries reach the decrypt layer.

The target builds on the existing fuzz_main.c driver and is registered in
ossfuzz/CMakeLists.txt, so make list-fuzzers (and therefore ossfuzz.sh)
picks it up automatically; no change to ossfuzz.sh is required.

Testing

  • Builds cleanly with -fsanitize=address,undefined and no new warnings.
  • Ran the target over the full regress/*.zip set (165 inputs) under
    ASan + UBSan with no harness-side errors or leaks.
  • Coverage-guided fuzzing runs on the OSS-Fuzz infrastructure.

Checklist

  • CLA signed
  • New fuzz target only; no library code changes

The existing read harnesses (zip_read_fuzzer, zip_read_file_fuzzer,
zip_read_metadata_fuzzer) reach entry data only through
zip_fopen_index(), which always calls zip_source_zip_file_create() with
flags = 0, start = 0 and len = -1. The partial-window and raw-extraction
logic in zip_source_zip_new.c is therefore never exercised:

  - start > 0 / len >= 0 sub-range reads and their offset arithmetic and
    overflow / past-end-of-file checks,
  - ZIP_FL_COMPRESSED (raw compressed bytes wrapped in a window),
  - ZIP_FL_UNCHANGED dirent/stat selection,
  - the public zip_source_zip_create() entry point.

Add a fuzz target that opens the input as an archive and, for every
entry, creates a zip_source_zip for a range of flag/start/len
combinations derived from the entry's stated size (in-range partial
ranges as well as boundary and past-the-end ranges) and drains each
source through the source interface so the window, decrypt, decompress
and crc layers run.
@tejgokani tejgokani force-pushed the test/fuzz-zip-source-zip-windowing branch from b127bf0 to 0c30df0 Compare June 16, 2026 09:47
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