diff options
-rw-r--r-- | build/all.gyp | 3 | ||||
-rw-r--r-- | testing/libfuzzer/BUILD.gn | 51 | ||||
-rw-r--r-- | testing/libfuzzer/fuzzers.gyp | 65 | ||||
-rw-r--r-- | testing/libfuzzer/pdf_fm2js_fuzzer.cc | 25 | ||||
-rw-r--r-- | testing/libfuzzer/pdf_xml_fuzzer.cc | 76 | ||||
-rw-r--r-- | testing/libfuzzer/unittest_main.cc | 41 |
6 files changed, 260 insertions, 1 deletions
diff --git a/build/all.gyp b/build/all.gyp index 7e2ea613ff..47097e39b4 100644 --- a/build/all.gyp +++ b/build/all.gyp @@ -10,7 +10,8 @@ 'dependencies': [ '../pdfium.gyp:*', '../samples/samples.gyp:*', + '../testing/libfuzzer/fuzzers.gyp:*', ], } ] -}
\ No newline at end of file +} diff --git a/testing/libfuzzer/BUILD.gn b/testing/libfuzzer/BUILD.gn new file mode 100644 index 0000000000..46cf0589d3 --- /dev/null +++ b/testing/libfuzzer/BUILD.gn @@ -0,0 +1,51 @@ +# Copyright 2016 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. + +import("../../pdfium.gni") + +config("libfuzzer_config") { + defines = [ + "PNG_PREFIX", + "PNGPREFIX_H", + "PNG_USE_READ_MACROS", + ] + include_dirs = [ "../.." ] + if (pdf_enable_v8) { + defines += [ "PDF_ENABLE_V8" ] + } + if (pdf_enable_xfa) { + defines += [ "PDF_ENABLE_XFA" ] + } +} + +if (pdf_enable_xfa) { + source_set("pdf_fm2js_fuzzer") { + testonly = true + sources = [ + "pdf_fm2js_fuzzer.cc", + ] + deps = [ + "//third_party/pdfium:pdfium", + ] + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + ":libfuzzer_config", + ] + } + source_set("pdf_xml_fuzzer") { + testonly = true + sources = [ + "pdf_xml_fuzzer.cc", + ] + deps = [ + "//third_party/pdfium:pdfium", + ] + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + ":libfuzzer_config", + ] + } +} diff --git a/testing/libfuzzer/fuzzers.gyp b/testing/libfuzzer/fuzzers.gyp new file mode 100644 index 0000000000..a3c0d452b5 --- /dev/null +++ b/testing/libfuzzer/fuzzers.gyp @@ -0,0 +1,65 @@ +# Copyright 2016 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. + +{ + 'variables': { + 'pdf_enable_v8%': 1, + 'pdf_enable_xfa%': 0, # Set to 1 in standalone builds by standalone.gypi. + }, + 'target_defaults': { + 'defines' : [ + 'PNG_PREFIX', + 'PNGPREFIX_H', + 'PNG_USE_READ_MACROS', + ], + 'include_dirs': [ + # This is implicit in GN. + '<(DEPTH)', + ], + 'conditions': [ + ['pdf_enable_v8==1', { + 'defines': [ + 'PDF_ENABLE_V8', + ], + 'include_dirs': [ + '<(DEPTH)/v8', + '<(DEPTH)/v8/include', + ], + }], + ['pdf_enable_xfa==1', { + 'defines': [ + 'PDF_ENABLE_XFA', + ], + }], + ], + }, + 'conditions': [ + ['pdf_enable_xfa==1 and OS!="win"', { + 'targets': [ + { + 'target_name': 'pdf_fm2js_fuzzer', + 'type': 'executable', + 'dependencies': [ + '../../pdfium.gyp:pdfium', + ], + 'sources': [ + 'pdf_fm2js_fuzzer.cc', + 'unittest_main.cc', + ], + }, + { + 'target_name': 'pdf_xml_fuzzer', + 'type': 'executable', + 'dependencies': [ + '../../pdfium.gyp:pdfium', + ], + 'sources': [ + 'pdf_xml_fuzzer.cc', + 'unittest_main.cc', + ], + }, + ], + }], + ] +} diff --git a/testing/libfuzzer/pdf_fm2js_fuzzer.cc b/testing/libfuzzer/pdf_fm2js_fuzzer.cc new file mode 100644 index 0000000000..803ef7c843 --- /dev/null +++ b/testing/libfuzzer/pdf_fm2js_fuzzer.cc @@ -0,0 +1,25 @@ +// Copyright 2016 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 <cstddef> +#include <cstdint> + +#include "core/include/fxcrt/fx_basic.h" +#include "core/include/fxcrt/fx_string.h" +#include "xfa/src/fxfa/src/fm2js/xfa_fm2js.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size > std::numeric_limits<FX_STRSIZE>::max()) + return 0; + + CFX_WideString input = CFX_WideString::FromUTF8( + reinterpret_cast<const char*>(data), static_cast<FX_STRSIZE>(size)); + CXFA_FMProgram program; + if (program.Init(input) || program.ParseProgram()) + return 0; + + CFX_WideTextBuf js; + program.TranslateProgram(js); + return 0; +} diff --git a/testing/libfuzzer/pdf_xml_fuzzer.cc b/testing/libfuzzer/pdf_xml_fuzzer.cc new file mode 100644 index 0000000000..3eb1c8b5e5 --- /dev/null +++ b/testing/libfuzzer/pdf_xml_fuzzer.cc @@ -0,0 +1,76 @@ +// Copyright 2016 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 <cstddef> +#include <cstdint> +#include <limits> +#include <memory> + +#include "core/include/fxcrt/fx_basic.h" +#include "core/include/fxcrt/fx_system.h" +#include "xfa/src/foxitlib.h" +#include "xfa/src/fxfa/src/common/xfa_common.h" +#include "xfa/src/fxfa/src/parser/xfa_parser_imp.h" + +namespace { + +IFDE_XMLNode* XFA_FDEExtension_GetDocumentNode( + IFDE_XMLDoc* pXMLDoc, + FX_BOOL bVerifyWellFormness = FALSE) { + if (!pXMLDoc) { + return nullptr; + } + IFDE_XMLNode* pXMLFakeRoot = pXMLDoc->GetRoot(); + for (IFDE_XMLNode* pXMLNode = + pXMLFakeRoot->GetNodeItem(IFDE_XMLNode::FirstChild); + pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { + if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + if (bVerifyWellFormness) { + for (IFDE_XMLNode* pNextNode = + pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling); + pNextNode; + pNextNode = pNextNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { + if (pNextNode->GetType() == FDE_XMLNODE_Element) { + return FALSE; + } + } + } + return pXMLNode; + } + } + return nullptr; +} + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size > std::numeric_limits<FX_STRSIZE>::max()) + return 0; + + CFX_WideString input = CFX_WideString::FromUTF8( + reinterpret_cast<const char*>(data), static_cast<FX_STRSIZE>(size)); + std::unique_ptr<IFX_Stream, ReleaseDeleter<IFX_Stream>> stream( + XFA_CreateWideTextRead(input)); + if (!stream) + return 0; + + std::unique_ptr<IFDE_XMLDoc> doc(IFDE_XMLDoc::Create()); + if (!doc) + return 0; + + std::unique_ptr<IFDE_XMLParser, ReleaseDeleter<IFDE_XMLParser>> parser( + new CXFA_XMLParser(doc->GetRoot(), stream.get())); + if (!parser) + return 0; + + if (!doc->LoadXML(parser.release())) + return 0; + + int32_t load_result = doc->DoLoad(nullptr); + if (load_result < 100) + return 0; + + (void)XFA_FDEExtension_GetDocumentNode(doc.get()); + return 0; +} diff --git a/testing/libfuzzer/unittest_main.cc b/testing/libfuzzer/unittest_main.cc new file mode 100644 index 0000000000..f6b29e483f --- /dev/null +++ b/testing/libfuzzer/unittest_main.cc @@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A simple unit-test style driver for libfuzzer tests. +// Usage: <fuzzer_test> <file>... + +#include <fstream> +#include <iostream> +#include <iterator> +#include <vector> + +// Libfuzzer API. +extern "C" { +// User function. +int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size); +// Initialization function. +__attribute__((weak)) int LLVMFuzzerInitialize(int* argc, char*** argv); +} + +std::vector<char> readFile(std::string path) { + std::ifstream in(path); + return std::vector<char>((std::istreambuf_iterator<char>(in)), + std::istreambuf_iterator<char>()); +} + +int main(int argc, char** argv) { + if (argc == 1) { + std::cerr << "Usage: " << argv[0] << " <file>..." << std::endl; + exit(1); + } + + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + + for (int i = 1; i < argc; ++i) { + std::cout << argv[i] << std::endl; + auto v = readFile(argv[i]); + LLVMFuzzerTestOneInput((const unsigned char*)v.data(), v.size()); + } +} |