Back to V8

JS-Fuzzer

tools/clusterfuzz/js_fuzzer/README.md

15.0.104.9 KB
Original Source

JS-Fuzzer

JavaScript fuzzer for stand-alone shells like D8, Chakra, JSC or Spidermonkey.

Original author: Oliver Chang

Building

This fuzzer may require versions of node that are newer than available on ClusterFuzz, so we use pkg to create a self-contained binary out of this.

Prereqs

You need to install nodejs and npm. Run npm install in this directory.

Fuzzing DB

This fuzzer requires a fuzzing DB. To build one, get the latest web_tests.zip from gs://clusterfuzz-data/web_tests.zip and unzip it (note https://crbug.com/40643747 for making this data publicly available). Then run:

bash
$ mkdir db
$ node build_db.js -i /path/to/web_tests -o db chakra v8 spidermonkey WebKit/JSTests fuzzilli
$ node validate_db.js -i db -o db/index.json

This may take a while. Optionally test the fuzzing DB with:

bash
$ node test_db.js -i db

Building fuzzer

Then, to build the fuzzer,

bash
$ ./node_modules/.bin/pkg -t node18-linux-x64 .

Replace "linux" with either "win" or "macos" for those platforms.

This builds a binary named ochang_js_fuzzer for Linux / macOS OR ochang_js_fuzzer.exe for Windows.

Packaging

Use ./package.sh, ./package.sh win or ./package.sh macos to build and create the output.zip archive or use these raw commands:

bash
$ mkdir output
$ cd output
$ ln -s ../db db
$ ln -s ../ochang_js_fuzzer run
$ zip -r /path/output.zip *

NOTE: Add .exe to ochang_js_fuzzer and run filename above if archiving for Windows platform.

Development

Run the tests with:

bash
$ npm test

When test expectations change, generate them with:

bash
$ GENERATE=1 npm test

Generating exceptional configurations

Tests that fail to parse or show very bad performance can be automatically skipped or soft-skipped with the following script (takes >1h):

bash
$ WEB_TESTS=/path/to/web_tests OUTPUT=/path/to/output/folder ./gen_exceptions.sh

Experimenting (limited to differential fuzzing)

To locally evaluate the fuzzer, set up a work directory as follows:

bash
$ workdir/
$ workdir/app_dir
$ workdir/fuzzer
$ workdir/input
$ workdir/output

The app_dir folder can be a symlink or should contain the bundled version of d8 with all files required for execution. Copy the packaged ochang_js_fuzzer executable and the db folder to the fuzzer directory or use a symlink. The input directory is the root folder of the corpus, i.e., pointing to the unzipped data of gs://clusterfuzz-data/web_tests.zip. The output directory is expected to be empty. It'll contain all output of the fuzzing session. Start the experiments with:

bash
$ # Around ~40000 corresponds to 24h of fuzzing on a workstation.
$ NUM_RUNS=40000
$ python tools/workbench.py $NUM_RUNS

You can check current stats with:

bash
$ cat workdir/output/stats.json | python -m json.tool

When failures are found, you can forge minimization command lines with:

bash
$ MINIMIZER_PATH=path/to/minimizer
$ python tools/minimize.py $MINIMIZER_PATH

The path should point to a local checkout of the minimizer.

Local Execution (Clusterfuzz Simulation)

To simulate Clusterfuzz's behavior locally—generating test cases and running them against a d8 binary to find crashes—use the tools/run_locally_against_d8.py script.

This script automates:

  1. Generating a batch of test cases using the fuzzer.
  2. Executing each test case with d8 (applying any generated flags).
  3. Detecting crashes (via signals, exit codes, or "FATAL" error messages).
  4. Saving crashing test cases and their flags to a local directory.

Usage

bash
$ python3 tools/run_locally_against_d8.py [options]

Options

  • --num-tests <n>: Total number of test cases to generate and run (default: 10000).
  • --num-crashes <n>: Stop execution after finding this many crashes (default: 10).
  • --d8 <path>: Path to the d8 binary to test (default: ../../../../out/x64.release/d8 relative to script).
  • --crash-dir <path>: Directory where crashing test cases will be saved (default: workdir/crash/ in js_fuzzer directory).
  • --batch-size <n>: Number of tests to generate in each fuzzer invocation (default: 100).
  • --extra-flags "<flags>": Extra flags to always pass to d8 (e.g. --extra-flags "--turbofan --allow-natives-syntax").
  • --jobs <n>: Number of parallel d8 jobs to run (default: CPU count).

Results

  • Crashes: Any test cases that cause d8 to crash are saved in the crash/ directory (or the directory specified by --crash-dir). Each crash artifact includes the .js test file and its corresponding flags-N.js file if applicable.
  • Progress: The script outputs real-time progress to the terminal, showing how many tests have been run and how many crashes have been found so far.