diff --git a/browser/app/moz.build b/browser/app/moz.build index 68092c7b12303306a599d9744d45a759ad3ed034..520ce4425d044f118b30e23ddf74eede572b0f1c 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -33,6 +33,9 @@ USE_LIBS += [ 'mozglue', ] +if CONFIG['LIBFUZZER']: + USE_LIBS += [ 'fuzzer' ] + if CONFIG['_MSC_VER']: # Always enter a Windows program through wmain, whether or not we're # a console application. diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index 019bf6043f5241c859f3523e62f12a0325c73f7c..335b32354daa20b43cfd167216fb896cda6c30a6 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -127,6 +127,10 @@ XRE_GetProcessTypeType XRE_GetProcessType; XRE_SetProcessTypeType XRE_SetProcessType; XRE_InitChildProcessType XRE_InitChildProcess; XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc; +#ifdef LIBFUZZER +XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain; +XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs; +#endif static const nsDynamicFunctionLoad kXULFuncs[] = { { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, @@ -141,9 +145,24 @@ static const nsDynamicFunctionLoad kXULFuncs[] = { { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType }, { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess }, { "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc }, +#ifdef LIBFUZZER + { "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain }, + { "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs }, +#endif { nullptr, nullptr } }; +#ifdef LIBFUZZER +int libfuzzer_main(int argc, char **argv); + +/* This wrapper is used by the libFuzzer main to call into libxul */ + +void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc, + LibFuzzerTestingFunc* testingFunc) { + return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc); +} +#endif + static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory) { nsCOMPtr<nsIFile> appini; @@ -254,6 +273,11 @@ static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory) appData.sandboxBrokerServices = brokerServices; #endif +#ifdef LIBFUZZER + if (getenv("LIBFUZZER")) + XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main); +#endif + return XRE_main(argc, argv, &appData, mainFlags); } diff --git a/moz.build b/moz.build index fee89428deeac1ef1bf1be2c3854a0ea39979931..ea1e3af117a25d45040b154530a3370014cd1f8e 100644 --- a/moz.build +++ b/moz.build @@ -57,6 +57,7 @@ DIRS += [ 'memory', 'mfbt', 'mozglue', + 'tools/fuzzing', ] if not CONFIG['JS_STANDALONE']: diff --git a/toolkit/moz.configure b/toolkit/moz.configure index facd2a9dd9d5f7ad2658eed42b7b7e3e652b5ac7..0c98c7ad4a0cfae0c6da734a5ce21079ad1d52b5 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -764,3 +764,15 @@ def skia_includes(skia, skia_gpu): return includes set_config('SKIA_INCLUDES', skia_includes) + +# Support various fuzzing options +# ============================================================== +option('--enable-libfuzzer', help='Enable libfuzzer support') + +@depends('--enable-libfuzzer') +def enable_libfuzzer(value): + if value: + return True + +set_config('LIBFUZZER', enable_libfuzzer) +set_define('LIBFUZZER', enable_libfuzzer) diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 15ebf9efd28cfb22a91c802054c94ae4a3658ac7..08521f8799533fe52a43de55b707975cb1eda6ae 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -259,6 +259,18 @@ nsString gAbsoluteArgv0Path; extern "C" MFBT_API bool IsSignalHandlingBroken(); #endif +#ifdef LIBFUZZER +#include "LibFuzzerRunner.h" + +namespace mozilla { +LibFuzzerRunner* libFuzzerRunner = 0; +} // namespace mozilla + +extern "C" MOZ_EXPORT void XRE_LibFuzzerSetMain(int argc, char** argv, LibFuzzerMain main) { + mozilla::libFuzzerRunner->setParams(argc, argv, main); +} +#endif + namespace mozilla { int (*RunGTest)() = 0; } // namespace mozilla @@ -3669,6 +3681,13 @@ XREMain::XRE_mainStartup(bool* aExitFlag) return 1; #endif /* MOZ_WIDGET_GTK */ +#ifdef LIBFUZZER + if (PR_GetEnv("LIBFUZZER")) { + *aExitFlag = true; + return mozilla::libFuzzerRunner->Run(); + } +#endif + if (PR_GetEnv("MOZ_RUN_GTEST")) { int result; #ifdef XP_WIN diff --git a/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp b/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2293efd95d8ee1decf07b25004c7e0bc02925097 --- /dev/null +++ b/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <cstdlib> + +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" +#include "harness/LibFuzzerRegistry.h" + +/* This is a wrapper defined in browser/app/nsBrowserApp.cpp, + * encapsulating the XRE_ equivalent defined in libxul */ +extern void libFuzzerGetFuncs(const char*, LibFuzzerInitFunc*, + LibFuzzerTestingFunc*); + +int libfuzzer_main(int argc, char **argv) { + LibFuzzerInitFunc initFunc = nullptr; + LibFuzzerTestingFunc testingFunc = nullptr; + + libFuzzerGetFuncs(getenv("LIBFUZZER"), &initFunc, &testingFunc); + + if (initFunc) { + int ret = initFunc(&argc, &argv); + if (ret) { + fprintf(stderr, "LibFuzzer: Error: Initialize callback failed\n"); + return ret; + } + } + + if (!testingFunc) { + fprintf(stderr, "LibFuzzer: Error: No testing callback found\n"); + return 1; + } + + return fuzzer::FuzzerDriver(&argc, &argv, testingFunc); +} diff --git a/tools/fuzzing/libfuzzer/Makefile.in b/tools/fuzzing/libfuzzer/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..7ffe876852a4d65edd03cc035e59cc24bd03f174 --- /dev/null +++ b/tools/fuzzing/libfuzzer/Makefile.in @@ -0,0 +1,12 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +# According to the LLVM docs, LibFuzzer isn't supposed to be built with any +# sanitizer flags and in fact, building it with ASan coverage currently causes +# Clang 3.9+ to crash, so we filter out all sanitizer-related flags here. +CXXFLAGS := $(filter-out -fsanitize%,$(CXXFLAGS)) +CFLAGS := $(filter-out -fsanitize%,$(CFLAGS)) +LDFLAGS := $(filter-out -fsanitize%,$(LDFLAGS)) diff --git a/tools/fuzzing/libfuzzer/clone_libfuzzer.sh b/tools/fuzzing/libfuzzer/clone_libfuzzer.sh new file mode 100755 index 0000000000000000000000000000000000000000..6170362ac9fbf8fc2a41ce8c3b97e9045fe4b3a3 --- /dev/null +++ b/tools/fuzzing/libfuzzer/clone_libfuzzer.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +mkdir tmp/ +git clone --no-checkout --depth 1 https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer tmp/ +mv tmp/.git . +rm -Rf tmp +git reset --hard HEAD diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5390c91c2a4b7a7366a51da94cbf7846c4155ef6 --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LibFuzzerRegistry.h" + +extern "C" { + void MOZ_EXPORT XRE_LibFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc, LibFuzzerTestingFunc* testingFunc) { + std::string moduleNameStr(moduleName); + mozilla::LibFuzzerFunctions funcs = mozilla::LibFuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr); + *initFunc = funcs.first; + *testingFunc = funcs.second; + } +} + +namespace mozilla { + +LibFuzzerRegistry& LibFuzzerRegistry::getInstance() { + static LibFuzzerRegistry instance; + return instance; +} + +void LibFuzzerRegistry::registerModule(std::string moduleName, LibFuzzerInitFunc initFunc, LibFuzzerTestingFunc testingFunc) { + moduleMap.insert(std::pair<std::string, LibFuzzerFunctions>(moduleName,LibFuzzerFunctions(initFunc, testingFunc))); +} + +LibFuzzerFunctions LibFuzzerRegistry::getModuleFunctions(std::string& moduleName) { + return moduleMap[moduleName]; +} + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h new file mode 100644 index 0000000000000000000000000000000000000000..e459ade33e7148957b5f8e75f51a053274bc0a56 --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _LibFuzzerRegistry_h__ +#define _LibFuzzerRegistry_h__ + +#include <cstdint> +#include <map> +#include <string> +#include <utility> + +#include "mozilla/Attributes.h" + +typedef int(*LibFuzzerMain)(int, char**); +typedef int(*LibFuzzerInitFunc)(int*, char***); +typedef int(*LibFuzzerTestingFunc)(const uint8_t*, size_t); + +namespace mozilla { + +typedef std::pair<LibFuzzerInitFunc, LibFuzzerTestingFunc> LibFuzzerFunctions; + +class LibFuzzerRegistry { + public: + MOZ_EXPORT static LibFuzzerRegistry& getInstance(); + MOZ_EXPORT void registerModule(std::string moduleName, LibFuzzerInitFunc initFunc, LibFuzzerTestingFunc testingFunc); + MOZ_EXPORT LibFuzzerFunctions getModuleFunctions(std::string& moduleName); + + LibFuzzerRegistry(LibFuzzerRegistry const&) = delete; + void operator=(LibFuzzerRegistry const&) = delete; + + private: + LibFuzzerRegistry() {}; + std::map<std::string, LibFuzzerFunctions> moduleMap; +}; + +} // namespace mozilla + + +#endif // _LibFuzzerRegistry_h__ diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2eda9d2dde54247b190ac28d8c7f93ecc5df6c31 --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LibFuzzerRunner.h" +#include "mozilla/Attributes.h" +#include "testing/TestHarness.h" +#include "prenv.h" + +namespace mozilla { + +// We use a static var 'libFuzzerRunner' defined in nsAppRunner.cpp. +// libFuzzerRunner is initialized to nullptr but if LibFuzzer (this file) +// is linked in then libFuzzerRunner will be set here indicating that +// we want to call into LibFuzzer's main. +class _InitLibFuzzer { +public: + _InitLibFuzzer() { + libFuzzerRunner = new LibFuzzerRunner(); + } +} InitLibFuzzer; + +int LibFuzzerRunner::Run() { + ScopedXPCOM xpcom("LibFuzzer"); + return mFuzzerMain(mArgc, mArgv); +} + +typedef int(*LibFuzzerMain)(int, char**); + +void LibFuzzerRunner::setParams(int argc, char** argv, LibFuzzerMain main) { + mArgc = argc; + mArgv = argv; + mFuzzerMain = main; +} + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h new file mode 100644 index 0000000000000000000000000000000000000000..c2362f4e99eca116ae1480d13a7296860b01118f --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace mozilla { + +typedef int(*LibFuzzerMain)(int, char**); + +class LibFuzzerRunner { +public: + int Run(); + void setParams(int argc, char** argv, LibFuzzerMain main); + +private: + int mArgc; + char** mArgv; + LibFuzzerMain mFuzzerMain; +}; + +extern LibFuzzerRunner* libFuzzerRunner; + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/moz.build b/tools/fuzzing/libfuzzer/harness/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..596018cb3c74f5570dc6b3bddcecf2091401364f --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/moz.build @@ -0,0 +1,19 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library('fuzzer-runner') + +SOURCES += [ + 'LibFuzzerRegistry.cpp', + 'LibFuzzerRunner.cpp', +] + +EXPORTS += [ + 'LibFuzzerRegistry.h', + 'LibFuzzerRunner.h', +] + +FINAL_LIBRARY = "xul" diff --git a/tools/fuzzing/libfuzzer/moz.build b/tools/fuzzing/libfuzzer/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..b37afdf9ce1fa9861134ad2fc46b0048c14e44d7 --- /dev/null +++ b/tools/fuzzing/libfuzzer/moz.build @@ -0,0 +1,26 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library('fuzzer') + +DIRS += [ + 'harness', +] + +SOURCES += [ + 'FuzzerCrossOver.cpp', + 'FuzzerCustomMain.cpp', + 'FuzzerDriver.cpp', + 'FuzzerExtFunctionsDlsym.cpp', + 'FuzzerExtFunctionsWeak.cpp', + 'FuzzerIO.cpp', + 'FuzzerLoop.cpp', + 'FuzzerMutate.cpp', + 'FuzzerSHA1.cpp', + 'FuzzerTracePC.cpp', + 'FuzzerTraceState.cpp', + 'FuzzerUtil.cpp', +] diff --git a/tools/fuzzing/moz.build b/tools/fuzzing/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..527b7c1d50b02fe7411cc355407758501e515049 --- /dev/null +++ b/tools/fuzzing/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG['LIBFUZZER']: + DIRS += [ + 'libfuzzer', + ] diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index a87e85ab1445ce4b9818835b27ddd07c4657f842..7551cb20a1916ced3e34b21cc615ee90662cf75a 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -520,4 +520,16 @@ XRE_API(void, XRE_GlibInit, ()) #endif + +#ifdef LIBFUZZER +#include "LibFuzzerRegistry.h" + +XRE_API(void, + XRE_LibFuzzerSetMain, (int, char**, LibFuzzerMain)) + +XRE_API(void, + XRE_LibFuzzerGetFuncs, (const char*, LibFuzzerInitFunc*, + LibFuzzerTestingFunc*)) +#endif // LIBFUZZER + #endif // _nsXULAppAPI_h__