1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * * This Source Code Form is subject to the terms of the Mozilla Public
3  * * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include <cstdlib>
7 
8 #include "FuzzerRunner.h"
9 #include "mozilla/Attributes.h"
10 #include "prenv.h"
11 
12 #include "FuzzerTestHarness.h"
13 
14 namespace mozilla {
15 
16 // We use a static var 'fuzzerRunner' defined in nsAppRunner.cpp.
17 // fuzzerRunner is initialized to nullptr but if this file is linked in,
18 // then fuzzerRunner will be set here indicating that
19 // we want to call into either LibFuzzer's main or the AFL entrypoint.
20 class _InitFuzzer {
21  public:
_InitFuzzer()22   _InitFuzzer() { fuzzerRunner = new FuzzerRunner(); }
InitXPCOM()23   void InitXPCOM() { mScopedXPCOM = new ScopedXPCOM("Fuzzer"); }
DeinitXPCOM()24   void DeinitXPCOM() {
25     if (mScopedXPCOM) delete mScopedXPCOM;
26     mScopedXPCOM = nullptr;
27   }
28 
29  private:
30   ScopedXPCOM* mScopedXPCOM;
31 } InitLibFuzzer;
32 
DeinitXPCOM()33 static void DeinitXPCOM() { InitLibFuzzer.DeinitXPCOM(); }
34 
Run(int * argc,char *** argv)35 int FuzzerRunner::Run(int* argc, char*** argv) {
36   /*
37    * libFuzzer uses exit() calls in several places instead of returning,
38    * so the destructor of ScopedXPCOM is not called in some cases.
39    * For fuzzing, this does not make a difference, but in debug builds
40    * when running a single testcase, this causes an assertion when destroying
41    * global linked lists. For this reason, we allocate ScopedXPCOM on the heap
42    * using the global InitLibFuzzer class, combined with an atexit call to
43    * destroy the ScopedXPCOM instance again.
44    */
45   InitLibFuzzer.InitXPCOM();
46   std::atexit(DeinitXPCOM);
47 
48   const char* fuzzerEnv = getenv("FUZZER");
49 
50   if (!fuzzerEnv) {
51     fprintf(stderr,
52             "Must specify fuzzing target in FUZZER environment variable\n");
53     exit(1);
54   }
55 
56   std::string moduleNameStr(fuzzerEnv);
57   FuzzerFunctions funcs =
58       FuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr);
59   FuzzerInitFunc initFunc = funcs.first;
60   FuzzerTestingFunc testingFunc = funcs.second;
61   if (initFunc) {
62     int ret = initFunc(argc, argv);
63     if (ret) {
64       fprintf(stderr, "Fuzzing Interface: Error: Initialize callback failed\n");
65       exit(1);
66     }
67   }
68 
69   if (!testingFunc) {
70     fprintf(stderr, "Fuzzing Interface: Error: No testing callback found\n");
71     exit(1);
72   }
73 
74 #ifdef LIBFUZZER
75   int ret = mFuzzerDriver(argc, argv, testingFunc);
76 #else
77   // For AFL, testingFunc points to the entry function we need.
78   int ret = testingFunc(NULL, 0);
79 #endif
80 
81   InitLibFuzzer.DeinitXPCOM();
82   return ret;
83 }
84 
85 #ifdef LIBFUZZER
setParams(LibFuzzerDriver aDriver)86 void FuzzerRunner::setParams(LibFuzzerDriver aDriver) {
87   mFuzzerDriver = aDriver;
88 }
89 #endif
90 
91 }  // namespace mozilla
92