summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Harrison <rharrison@chromium.org>2017-10-19 14:37:06 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-10-19 18:56:15 +0000
commitc136b3146257d0f12d1347a9f1a4784372e19a56 (patch)
tree84da176326c028f2c3b888924a73367cb9446c31
parent943360187bb881fe94f14571c955e03f81203573 (diff)
downloadpdfium-c136b3146257d0f12d1347a9f1a4784372e19a56.tar.xz
Implement fuzzer for LZW decompressor
This adds a fuzzer that tests the LZW decompression code used by our GIF decoder. BUG=pdfium:908 Change-Id: I1381f3ebb2eddf8d2c6f0394b1bb00f67d64a600 Reviewed-on: https://pdfium-review.googlesource.com/16310 Commit-Queue: Ryan Harrison <rharrison@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
-rw-r--r--testing/libfuzzer/BUILD.gn7
-rw-r--r--testing/libfuzzer/pdf_lzw_fuzzer.cc58
2 files changed, 65 insertions, 0 deletions
diff --git a/testing/libfuzzer/BUILD.gn b/testing/libfuzzer/BUILD.gn
index 2952444421..d23fb88376 100644
--- a/testing/libfuzzer/BUILD.gn
+++ b/testing/libfuzzer/BUILD.gn
@@ -46,6 +46,7 @@ group("libfuzzer") {
":pdf_codec_tiff_fuzzer",
":pdf_css_fuzzer",
":pdf_fm2js_fuzzer",
+ ":pdf_lzw_fuzzer",
":pdf_xml_fuzzer",
]
}
@@ -129,6 +130,12 @@ if (pdf_enable_xfa) {
]
}
+ pdfium_fuzzer("pdf_lzw_fuzzer") {
+ sources = [
+ "pdf_lzw_fuzzer.cc",
+ ]
+ }
+
pdfium_fuzzer("pdf_xml_fuzzer") {
sources = [
"pdf_xml_fuzzer.cc",
diff --git a/testing/libfuzzer/pdf_lzw_fuzzer.cc b/testing/libfuzzer/pdf_lzw_fuzzer.cc
new file mode 100644
index 0000000000..71c258969d
--- /dev/null
+++ b/testing/libfuzzer/pdf_lzw_fuzzer.cc
@@ -0,0 +1,58 @@
+// Copyright 2017 The PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "core/fxcodec/gif/cfx_lzwdecompressor.h"
+#include "third_party/base/numerics/safe_conversions.h"
+
+// Between 2x and 5x is a standard range for LZW according to a quick
+// search of papers. Running up to 10x to catch any niche cases.
+constexpr uint32_t kMinCompressionRatio = 2;
+constexpr uint32_t kMaxCompressionRatio = 10;
+
+void LZWFuzz(const uint8_t* src_buf,
+ size_t src_size,
+ uint8_t color_exp,
+ uint8_t code_exp) {
+ std::unique_ptr<CFX_LZWDecompressor> decompressor =
+ CFX_LZWDecompressor::Create(color_exp, code_exp);
+ if (!decompressor)
+ return;
+
+ for (uint32_t compressions_ratio = kMinCompressionRatio;
+ compressions_ratio <= kMaxCompressionRatio; compressions_ratio++) {
+ std::vector<uint8_t> des_buf(compressions_ratio * src_size);
+ // This cast should be safe since the caller is checking for overflow on
+ // the initial data.
+ uint32_t des_size = static_cast<uint32_t>(des_buf.size());
+ if (CFX_GifDecodeStatus::InsufficientDestSize !=
+ decompressor->Decode(const_cast<uint8_t*>(src_buf), src_size,
+ des_buf.data(), &des_size))
+ return;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // Need at least 3 bytes to do anything.
+ if (size < 3)
+ return 0;
+
+ // Normally the GIF would provide the code and color sizes, instead, going
+ // to assume they are the first two bytes of data provided.
+ uint8_t color_exp = data[0];
+ uint8_t code_exp = data[1];
+ const uint8_t* lzw_data = data + 2;
+ uint32_t lzw_data_size = static_cast<uint32_t>(size - 2);
+ // Check that there isn't going to be an overflow in the destination buffer
+ // size.
+ if (lzw_data_size >
+ std::numeric_limits<uint32_t>::max() / kMaxCompressionRatio) {
+ return 0;
+ }
+
+ LZWFuzz(lzw_data, lzw_data_size, color_exp, code_exp);
+
+ return 0;
+}