tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

parsing-evaluate.js (3069B)


      1 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      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 // This fuzzing target aims to stress the SpiderMonkey parser. However, for
      7 // this purpose, it does *not* use `parse()` because some past bugs in the
      8 // parser could only be triggered in the runtime later. Instead, we use
      9 // the `evaluate` function which parses and runs the code. This brings in
     10 // other problems like timeouts and permanent side-effects. We try to minimize
     11 // the amount of permanent side-effects from running the code by running it
     12 // in a fresh global for each iteration. We also use a special function
     13 // called `sanitizeGlobal` to remove any harmful shell functions from the
     14 // global prior to running. Many of these shell functions would otherwise
     15 // have permanent side-effects of some sort or be disruptive to testing like
     16 // increasing the amount of timeouts or leak memory. Finally, the target also
     17 // tries to catch timeouts locally and signal back any timeouts by returning 1
     18 // from the iteration function.
     19 
     20 // This global will hold the current fuzzing buffer for each iteration.
     21 var fuzzBuf;
     22 
     23 loadRelativeToScript("util/sanitize.js");
     24 
     25 deterministicgc(true);
     26 
     27 // Set a default value for timeouts to 1 second, but allow this to
     28 // be set on the command line as well using -e fuzzTimeout=VAL.
     29 if (typeof fuzzTimeout === "undefined") {
     30  fuzzTimeout = 1;
     31 }
     32 
     33 function JSFuzzIterate() {
     34  try {
     35    let code = String.fromCharCode(...fuzzBuf);
     36    let result = null;
     37 
     38    // Create a new global and sanitize it such that its potentially permanent
     39    // side-effects are reduced to a minimum.
     40    let global = newGlobal();
     41    sanitizeGlobal(global);
     42 
     43    // Work around memory leaks when the hook is not set
     44    evaluate(`
     45      setModuleResolveHook(function(module, specifier) {
     46        throw "Module '" + specifier + "' not found";
     47      });
     48      setModuleResolveHook = function() {};
     49    `, { global: global, catchTermination: true });
     50 
     51    // Start a timer and set a timeout in addition
     52    let lfStart = monotonicNow();
     53    timeout(fuzzTimeout, function() { return false; });
     54 
     55    try {
     56      result = evaluate(code, { global: global, catchTermination: true });
     57    } catch(exc) {
     58      print(exc);
     59    }
     60 
     61    timeout(-1);
     62    let lfStop = monotonicNow();
     63 
     64    // Reset some things that could have been altered by the code we ran
     65    gczeal(0);
     66    schedulegc(0);
     67    setGCCallback({ action: "majorGC" });
     68    clearSavedFrames();
     69 
     70    // If we either ended terminating the script, or we took longer than
     71    // the timeout set (but timeout didn't kick in), then we return 1 to
     72    // signal libFuzzer that the sample just be abandoned.
     73    if (result === "terminated" || (lfStop - lfStart > (fuzzTimeout * 1000 + 200))) {
     74      return 1;
     75    }
     76 
     77    return 0;
     78  } catch(exc) {
     79    print("Caught toplevel exception: " + exc);
     80  }
     81 
     82  return 1;
     83 }