aboutsummaryrefslogtreecommitdiff
path: root/projects/libpng-proto
diff options
context:
space:
mode:
authorKostya Serebryany <konstantin.s.serebryany@gmail.com>2019-01-25 22:30:11 -0800
committerVitaly Buka <vitalybuka@gmail.com>2019-01-25 22:30:11 -0800
commitedf33327b6587ec38131bac7a42965122b292e01 (patch)
tree8fd6d4dbbe0e05cb00d2ffeb23d0927316b180e1 /projects/libpng-proto
parent456eded09c7f24c5ee3f14fd2e358edc7de9064c (diff)
downloadoss-fuzz-edf33327b6587ec38131bac7a42965122b292e01.tar.gz
[libpng-proto] add libpng_transforms_fuzzer, a fuzz target with more coverage than the in-tree one currently has (#2114)
Diffstat (limited to 'projects/libpng-proto')
-rw-r--r--projects/libpng-proto/Dockerfile2
-rwxr-xr-xprojects/libpng-proto/build.sh13
-rw-r--r--projects/libpng-proto/libpng_transforms_fuzzer.cc104
3 files changed, 117 insertions, 2 deletions
diff --git a/projects/libpng-proto/Dockerfile b/projects/libpng-proto/Dockerfile
index e10689255..f68cca559 100644
--- a/projects/libpng-proto/Dockerfile
+++ b/projects/libpng-proto/Dockerfile
@@ -23,4 +23,4 @@ RUN git clone --depth 1 https://github.com/glennrp/libpng.git
RUN git clone --depth 1 https://github.com/google/libprotobuf-mutator.git
RUN git clone --depth 1 https://github.com/google/fuzzer-test-suite
RUN (mkdir LPM && cd LPM && cmake ../libprotobuf-mutator -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release && ninja)
-COPY build.sh png_fuzz_proto.proto png_proto_fuzzer_example.cc $SRC/
+COPY build.sh png_fuzz_proto.proto png_proto_fuzzer_example.cc libpng_transforms_fuzzer.cc $SRC/
diff --git a/projects/libpng-proto/build.sh b/projects/libpng-proto/build.sh
index e22b4fb63..28b8f5568 100755
--- a/projects/libpng-proto/build.sh
+++ b/projects/libpng-proto/build.sh
@@ -29,7 +29,7 @@ $CXX $CXXFLAGS png_proto_fuzzer_example.cc libpng_read_fuzzer.o genfiles/png_fuz
echo > dummy.cc
-# Also compile another target, w/o protos but with a specialized custom mutator.
+# A target, w/o protos but with a specialized custom mutator.
$CXX $CXXFLAGS -c libpng/contrib/oss-fuzz/libpng_read_fuzzer.cc -I libpng
$CXX $CXXFLAGS dummy.cc \
-include fuzzer-test-suite/libpng-1.2.56/png_mutator.h \
@@ -40,3 +40,14 @@ $CXX $CXXFLAGS dummy.cc \
$LIB_FUZZING_ENGINE \
-o $OUT/png_custom_mutator_fuzzer_example
+# An experimental out-of-tree target, with a specialized custom mutator.
+$CXX $CXXFLAGS libpng_transforms_fuzzer.cc \
+ -include fuzzer-test-suite/libpng-1.2.56/png_mutator.h \
+ -D PNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR \
+ -I libpng \
+ -lz \
+ libpng/.libs/libpng16.a \
+ $LIB_FUZZING_ENGINE \
+ -o $OUT/png_transforms_fuzzer
+
+
diff --git a/projects/libpng-proto/libpng_transforms_fuzzer.cc b/projects/libpng-proto/libpng_transforms_fuzzer.cc
new file mode 100644
index 000000000..470545d3f
--- /dev/null
+++ b/projects/libpng-proto/libpng_transforms_fuzzer.cc
@@ -0,0 +1,104 @@
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "png.h"
+
+namespace {
+
+struct PngReader {
+ png_structp png_ptr = nullptr;
+ png_infop info_ptr = nullptr;
+ png_infop end_info = nullptr;
+};
+
+struct PngArrayStream {
+ const uint8_t *data;
+ size_t size;
+ size_t pos;
+};
+
+void PngArrayStreamCallback(png_structp png_ptr, png_bytep data,
+ png_size_t size) {
+ PngArrayStream *stream =
+ static_cast<PngArrayStream *>(png_get_io_ptr(png_ptr));
+ if (stream->pos + size > stream->size) {
+ memset(data, 0, size);
+ stream->pos = size;
+ } else {
+ memcpy(data, &stream->data[stream->pos], size);
+ stream->pos += size;
+ }
+}
+
+static bool PngVerboseWarnings = getenv("PNG_VERBOSE_WARNINGS") != nullptr;
+
+void PngErrorHandler(png_structp png_ptr, png_const_charp error_message) {
+ if (PngVerboseWarnings) fprintf(stderr, "%s\n", error_message);
+ longjmp(png_jmpbuf(png_ptr), 1);
+}
+
+void PngWarningHandler(png_structp png_ptr, png_const_charp warning_message) {
+ if (PngVerboseWarnings) fprintf(stderr, "%s\n", warning_message);
+ longjmp(png_jmpbuf(png_ptr), 1);
+}
+
+} // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ const size_t kPngSignatureSize = 8;
+ const size_t kIHDRSize = 4 + 4 + 13 + 4;
+ const size_t kMaxImageSize = 1 << 20;
+
+ auto Read32 = [&](const uint8_t *p) {
+ uint32_t res;
+ assert(p >= data);
+ assert(p + sizeof(res) < data + size);
+ memcpy(&res, p, sizeof(res));
+ return res;
+ };
+
+ if (size < kPngSignatureSize + kIHDRSize) return 0;
+ if (png_sig_cmp(data, 0, kPngSignatureSize)) return 0;
+ uint32_t width = __builtin_bswap32(Read32(data + kPngSignatureSize + 8));
+ uint32_t height = __builtin_bswap32(Read32(data + kPngSignatureSize + 12));
+ if ((uint64_t)width * height > kMaxImageSize) return 0;
+
+ // Find the fUZz chunk and it's contents.
+ const size_t fUZz_chunk_size = 16;
+ const uint8_t fUZz_signature[8] = {0, 0, 0, fUZz_chunk_size,
+ 'f', 'U', 'Z', 'z'};
+ const uint8_t *fUZz_beg =
+ std::search(data, data + size, fUZz_signature,
+ fUZz_signature + sizeof(fUZz_signature));
+ if (fUZz_beg + sizeof(fUZz_signature) + fUZz_chunk_size < data + size)
+ fUZz_beg += sizeof(fUZz_signature);
+ else
+ fUZz_beg = nullptr;
+
+ PngReader reader;
+ reader.png_ptr =
+ png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ assert(reader.png_ptr);
+ reader.info_ptr = png_create_info_struct(reader.png_ptr);
+ assert(reader.info_ptr);
+ reader.end_info = png_create_info_struct(reader.png_ptr);
+ assert(reader.end_info);
+
+ png_set_error_fn(reader.png_ptr, png_get_error_ptr(reader.png_ptr),
+ PngErrorHandler, PngWarningHandler);
+
+ PngArrayStream stream{data, size, 0};
+
+ if (setjmp(png_jmpbuf(reader.png_ptr)) == 0) {
+ png_set_read_fn(reader.png_ptr, &stream, PngArrayStreamCallback);
+
+ // Take transforms from the fUZz chunk. By default, enable all.
+ int transforms = fUZz_beg ? Read32(fUZz_beg) : ~0;
+ png_read_png(reader.png_ptr, reader.info_ptr, transforms, nullptr);
+ }
+ png_destroy_read_struct(&reader.png_ptr, &reader.info_ptr, &reader.end_info);
+ return 0;
+}