Objective-C image fuzzing app and local harness set for exercising Apple image decoding and re-encoding paths through CoreGraphics, ImageIO, ColorSync, and related consumers.
XNU Image Fuzzer/contains the iOS app target, bundled sample inputs, and the core fuzzer implementation inxnuimagefuzzer.m..github/scripts/build-native.shis a Bash helper that builds a native arm64 Mac Catalyst-style binary with ASAN, UBSAN, and source-based coverage.fuzz-apps.shfeeds generated images into macOS parser consumers such assips, QuickLook,mdimport, andtiffutil.fuzz-gallery.pyserves a local WebKit/Safari decode gallery for browser-side exercising.contrib/scripts/extract-icc-seeds.pyextracts ICC profiles and TIFF seeds from run output for downstream corpus use.codeql-queries/contains repository-local CodeQL queries for Objective-C/C security checks.fuzzed-images/stores timestamped sample outputs committed by CI runs.
processImage()supports 17 bitmap-context permutations.- The default no-argument mode generates 19 seed specs, saves
seed_*andcorrupted_*PNGs, and then runs the matched permutation for each seed. - When
FUZZ_ICC_DIRis set, the default mode also writesseed_icc_*PNGs plus real-ICC, mutated-ICC, no-ICC, and ICC-mismatch siblings for PNG/TIFF context outputs. - Additional CLI modes are
<imagePath> <permutation>,--chain <image>,--input-dir <dir>, and--pipeline <dir>. - Chained fuzzing now cycles permutations
1..17; the regular chain output remains decodable and any intentional final corruption is written separately undercorrupted_*. - Metrics are written as
*.metrics.jsonsidecars plusfuzz_metrics_summary.csv. - The checked-in Xcode project targets
iphoneosandiphonesimulatorand enables Mac Catalyst. - The maintainer also verifies broader GitHub Actions build and output coverage, including watch-related outputs, separately from the local project file declared in this checkout.
.github/scripts/build-native.shRun it as an executable or with bash. Do not invoke it with sh; the helper uses Bash syntax.
Artifacts land in:
/tmp/native-build/xnuimagefuzzer/tmp/fuzzed-output//tmp/profraw//tmp/coverage-report/
xcodebuild build \
-project "XNU Image Fuzzer.xcodeproj" \
-scheme "XNU Image Fuzzer" \
-destination 'platform=macOS,variant=Mac Catalyst' \
-configuration Debug \
-derivedDataPath /tmp/DerivedData \
CODE_SIGN_IDENTITY="-" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NOLaunch the built app bundle with open, not by executing the Mach-O directly:
APP=$(find /tmp/DerivedData -name "XNU Image Fuzzer.app" -type d | sed -n '1p')
open --env FUZZ_OUTPUT_DIR=/tmp/fuzzed-output "$APP"/tmp/native-build/xnuimagefuzzer
/tmp/native-build/xnuimagefuzzer /path/to/image.png 12
/tmp/native-build/xnuimagefuzzer --chain /path/to/image.png --iterations 3
/tmp/native-build/xnuimagefuzzer --input-dir /path/to/images --iterations 2
/tmp/native-build/xnuimagefuzzer --pipeline /path/to/images --iterations 2Environment variables:
FUZZ_OUTPUT_DIRFUZZ_ICC_DIRLLVM_PROFILE_FILE
Default mode writes directly into the output directory:
seed_perm##_###.pngcorrupted_perm##_###.pngseed_icc_perm##_<profile>_###.pngwhen ICC profiles are availablefuzzed_image_<context>.<ext>plus ICC, no-ICC, and mismatch variants for PNG and TIFF outputscorrupted_<input>_perm##_inj##_<icc-or-none>_###.<ext>for intentionally corrupted final chained outputs*.metrics.jsonfuzz_metrics_summary.csv
Pipeline mode adds subdirectories:
pipeline-cleanpipeline-formatspipeline-fuzzedpipeline-iccpipeline-combopipeline-chainedpipeline-profiles
./fuzz-apps.sh <dir>exercises macOS parser consumers and captures crash reports.python3 fuzz-gallery.py <dir>serves a local gallery for Safari/WebKit decode paths.python3 contrib/scripts/extract-icc-seeds.py --input <dir> --output <dir>extracts ICC and TIFF seeds.python3 read-magic-numbers.pyis an ad hoc report generator that currently uses a hard-coded directory at the bottom of the script.python3 exr-channel-subsampling-example.pyandpython3 fuzzing-memory-pattern-generator.pyare focused helper scripts, not polished CLIs.
performPipelineFuzzing()uses a curated subset of 14 permutations and currently skips alpha-only, Display P3, and BT.2020 outputs in its fuzz phase.saveFuzzedImage()uses fixedfuzzed_image_*names, so repeated default runs overwrite context outputs; provenance-style naming is used for seeds, corrupted outputs, and chained outputs instead.- The simulator
build-and-testworkflow now setsFUZZ_ICC_DIR=/System/Library/ColorSync/Profilesand validates a 287-file top-level corpus: 19seed_perm*.png, 19corrupted_perm*.png, 19seed_icc_perm*.png, 62 basefuzzed_image_*files, 32 each of_no_icc,_icc_mismatch, real_icc_<profile>, and_icc_mutatedvariants, 11Bit_Monochrome.png, 38 metrics JSON sidecars, and 1 summary CSV with 39 lines. - Treat structurally broken files as intentional only when they are named
corrupted_*. Regularseed_*,seed_icc_*,fuzzed_image_*, and1Bit_*outputs are expected to remain decodable.
GPL-3.0-or-later. See LICENSE.