From 752bc86203e24f7716d5ddcfb6ef74c9c0cd6be7 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 23 Dec 2020 10:10:18 +0100 Subject: [PATCH] proper linpng harness --- fuzzers/libfuzzer_stats/build.rs | 7 +- fuzzers/libfuzzer_stats/harness.c | 24 ---- fuzzers/libfuzzer_stats/harness.cc | 190 +++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 26 deletions(-) delete mode 100644 fuzzers/libfuzzer_stats/harness.c create mode 100644 fuzzers/libfuzzer_stats/harness.cc diff --git a/fuzzers/libfuzzer_stats/build.rs b/fuzzers/libfuzzer_stats/build.rs index 18a03c5ad4..5bc05d03f2 100644 --- a/fuzzers/libfuzzer_stats/build.rs +++ b/fuzzers/libfuzzer_stats/build.rs @@ -13,11 +13,11 @@ fn main() { let out_dir_path = Path::new(&out_dir); println!("cargo:rerun-if-changed=./r&untime/rt.c",); - println!("cargo:rerun-if-changed=harness.c"); + println!("cargo:rerun-if-changed=harness.cc"); cc::Build::new() .file("./runtime/rt.c") - .file("./harness.c") + .file("./harness.cc") .compile("libfuzzer-sys"); let libpng = format!("{}/libpng-1.6.37", &out_dir); @@ -96,5 +96,8 @@ fn main() { println!("cargo:rustc-link-lib=dylib=m"); println!("cargo:rustc-link-lib=dylib=z"); + //For the C++ harness + println!("cargo:rustc-link-lib=static=stdc++"); + println!("cargo:rerun-if-changed=build.rs"); } diff --git a/fuzzers/libfuzzer_stats/harness.c b/fuzzers/libfuzzer_stats/harness.c deleted file mode 100644 index caa73d9393..0000000000 --- a/fuzzers/libfuzzer_stats/harness.c +++ /dev/null @@ -1,24 +0,0 @@ -/* An in mmeory fuzzing example. Fuzzer for libpng library */ - -#include -#include - -#include "png.h" - -/* The actual harness. Using PNG for our example. */ -int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len) { - - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - png_set_user_limits(png_ptr, 65535, 65535); - png_infop info_ptr = png_create_info_struct(png_ptr); - png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - - if (setjmp(png_jmpbuf(png_ptr))) return 0; - - png_set_progressive_read_fn(png_ptr, NULL, NULL, NULL, NULL); - png_process_data(png_ptr, info_ptr, (uint8_t *)input, len); - - return 0; - -} \ No newline at end of file diff --git a/fuzzers/libfuzzer_stats/harness.cc b/fuzzers/libfuzzer_stats/harness.cc new file mode 100644 index 0000000000..979475d10f --- /dev/null +++ b/fuzzers/libfuzzer_stats/harness.cc @@ -0,0 +1,190 @@ +// libpng_read_fuzzer.cc +// Copyright 2017-2018 Glenn Randers-Pehrson +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that may +// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE + +// Last changed in libpng 1.6.35 [July 15, 2018] + +// The modifications in 2017 by Glenn Randers-Pehrson include +// 1. addition of a PNG_CLEANUP macro, +// 2. setting the option to ignore ADLER32 checksums, +// 3. adding "#include " which is needed on some platforms +// to provide memcpy(). +// 4. adding read_end_info() and creating an end_info structure. +// 5. adding calls to png_set_*() transforms commonly used by browsers. + +#include +#include +#include + +#include + +#define PNG_INTERNAL +#include "png.h" + +#define PNG_CLEANUP \ + if(png_handler.png_ptr) \ + { \ + if (png_handler.row_ptr) \ + png_free(png_handler.png_ptr, png_handler.row_ptr); \ + if (png_handler.end_info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + &png_handler.end_info_ptr); \ + else if (png_handler.info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + nullptr); \ + else \ + png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ + png_handler.png_ptr = nullptr; \ + png_handler.row_ptr = nullptr; \ + png_handler.info_ptr = nullptr; \ + png_handler.end_info_ptr = nullptr; \ + } + +struct BufState { + const uint8_t* data; + size_t bytes_left; +}; + +struct PngObjectHandler { + png_infop info_ptr = nullptr; + png_structp png_ptr = nullptr; + png_infop end_info_ptr = nullptr; + png_voidp row_ptr = nullptr; + BufState* buf_state = nullptr; + + ~PngObjectHandler() { + if (row_ptr) + png_free(png_ptr, row_ptr); + if (end_info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); + else if (info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + else + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + delete buf_state; + } +}; + +void user_read_data(png_structp png_ptr, png_bytep data, size_t length) { + BufState* buf_state = static_cast(png_get_io_ptr(png_ptr)); + if (length > buf_state->bytes_left) { + png_error(png_ptr, "read error"); + } + memcpy(data, buf_state->data, length); + buf_state->bytes_left -= length; + buf_state->data += length; +} + +static const int kPngHeaderSize = 8; + +// Entry point for LibFuzzer. +// Roughly follows the libpng book example: +// http://www.libpng.org/pub/png/book/chapter13.html +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < kPngHeaderSize) { + return 0; + } + + std::vector v(data, data + size); + if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { + // not a PNG. + return 0; + } + + PngObjectHandler png_handler; + png_handler.png_ptr = nullptr; + png_handler.row_ptr = nullptr; + png_handler.info_ptr = nullptr; + png_handler.end_info_ptr = nullptr; + + png_handler.png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_handler.png_ptr) { + return 0; + } + + png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.info_ptr) { + PNG_CLEANUP + return 0; + } + + png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.end_info_ptr) { + PNG_CLEANUP + return 0; + } + + png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); +#ifdef PNG_IGNORE_ADLER32 + png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); +#endif + + // Setting up reading from buffer. + png_handler.buf_state = new BufState(); + png_handler.buf_state->data = data + kPngHeaderSize; + png_handler.buf_state->bytes_left = size - kPngHeaderSize; + png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); + png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); + + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + // Reading. + png_read_info(png_handler.png_ptr, png_handler.info_ptr); + + // reset error handler to put png_deleter into scope. + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type; + int filter_type; + + if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, + &height, &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type)) { + PNG_CLEANUP + return 0; + } + + // This is going to be too slow. + if (width && height > 100000000 / width) { + PNG_CLEANUP + return 0; + } + + // Set several transforms that browsers typically use: + png_set_gray_to_rgb(png_handler.png_ptr); + png_set_expand(png_handler.png_ptr); + png_set_packing(png_handler.png_ptr); + png_set_scale_16(png_handler.png_ptr); + png_set_tRNS_to_alpha(png_handler.png_ptr); + + int passes = png_set_interlace_handling(png_handler.png_ptr); + + png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); + + png_handler.row_ptr = png_malloc( + png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, + png_handler.info_ptr)); + + for (int pass = 0; pass < passes; ++pass) { + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_handler.png_ptr, + static_cast(png_handler.row_ptr), nullptr); + } + } + + png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); + + PNG_CLEANUP + return 0; +} +