tor-browser

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

xpcrtfuzzing.cpp (4950B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "xpcrtfuzzing/xpcrtfuzzing.h"
      8 
      9 #include "mozilla/Assertions.h"  // MOZ_CRASH
     10 #include "mozilla/Utf8.h"        // mozilla::Utf8Unit
     11 
     12 #include <stdio.h>  // fflush, fprintf, fputs
     13 
     14 #include "FuzzingInterface.h"
     15 #include "jsapi.h"
     16 
     17 #include "js/CompilationAndEvaluation.h"  // JS::Evaluate
     18 #include "js/CompileOptions.h"            // JS::CompileOptions
     19 #include "js/Conversions.h"               // JS::Conversions
     20 #include "js/ErrorReport.h"               // JS::PrintError
     21 #include "js/Exception.h"                 // JS::StealPendingExceptionStack
     22 #include "js/experimental/TypedData.h"  // JS_GetUint8ClampedArrayData, JS_NewUint8ClampedArray
     23 #include "js/PropertyAndElement.h"  // JS_SetProperty, JS_HasOwnProperty
     24 #include "js/RootingAPI.h"          // JS::Rooted
     25 #include "js/SourceText.h"          // JS::Source{Ownership,Text}
     26 #include "js/Value.h"               // JS::Value
     27 
     28 using mozilla::dom::AutoJSAPI;
     29 
     30 static AutoJSAPI* gJsapi = nullptr;
     31 MOZ_RUNINIT static std::string gFuzzModuleName;
     32 
     33 static void CrashOnPendingException() {
     34  if (gJsapi->HasException()) {
     35    gJsapi->ReportException();
     36 
     37    MOZ_CRASH("Unhandled exception from JS runtime!");
     38  }
     39 }
     40 
     41 int FuzzXPCRuntimeStart(AutoJSAPI* jsapi, int* argc, char*** argv,
     42                        const XREShellData* aShellData) {
     43  gFuzzModuleName = getenv("FUZZER");
     44  gJsapi = jsapi;
     45 
     46  int ret = FuzzXPCRuntimeInit();
     47  if (ret) {
     48    fprintf(stderr, "Fuzzing Interface: Error: Initialize callback failed\n");
     49    return ret;
     50  }
     51 
     52 #ifdef AFLFUZZ
     53  ret = aShellData->fuzzerDriver(FuzzXPCRuntimeFuzz);
     54 #else
     55  ret = aShellData->fuzzerDriver(argc, argv, FuzzXPCRuntimeFuzz);
     56 #endif
     57  if (!ret) {
     58    fprintf(stdout, "Trying to shutdown!\n");
     59    int shutdown = FuzzXPCRuntimeShutdown();
     60    if (shutdown) {
     61      fprintf(stderr, "Fuzzing Interface: Error: Shutdown callback failed\n");
     62      return shutdown;
     63    }
     64  }
     65 
     66  return ret;
     67 }
     68 
     69 int FuzzXPCRuntimeInit() {
     70  JSContext* cx = gJsapi->cx();
     71  JS::Rooted<JS::Value> v(cx);
     72  JS::CompileOptions opts(cx);
     73 
     74  // Load the fuzzing module specified in the FUZZER environment variable
     75  JS::EvaluateUtf8Path(cx, opts, gFuzzModuleName.c_str(), &v);
     76 
     77  // Any errors while loading the fuzzing module should be fatal
     78  CrashOnPendingException();
     79 
     80  return 0;
     81 }
     82 
     83 int FuzzXPCRuntimeFuzz(const uint8_t* buf, size_t size) {
     84  if (!size) {
     85    return 0;
     86  }
     87 
     88  JSContext* cx = gJsapi->cx();
     89 
     90  JS::Rooted<JSObject*> arr(cx, JS_NewUint8ClampedArray(cx, size));
     91  if (!arr) {
     92    MOZ_CRASH("OOM");
     93  }
     94 
     95  do {
     96    JS::AutoCheckCannotGC nogc;
     97    bool isShared;
     98    uint8_t* data = JS_GetUint8ClampedArrayData(arr, &isShared, nogc);
     99    MOZ_RELEASE_ASSERT(!isShared);
    100    memcpy(data, buf, size);
    101  } while (false);
    102 
    103  JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
    104  JS::RootedValue arrVal(cx, JS::ObjectValue(*arr));
    105  if (!JS_SetProperty(cx, global, "fuzzBuf", arrVal)) {
    106    MOZ_CRASH("JS_SetProperty failed");
    107  }
    108 
    109  JS::Rooted<JS::Value> v(cx);
    110  JS::CompileOptions opts(cx);
    111 
    112  static const char data[] = "JSFuzzIterate();";
    113 
    114  JS::SourceText<mozilla::Utf8Unit> srcBuf;
    115  if (!srcBuf.init(cx, data, strlen(data), JS::SourceOwnership::Borrowed)) {
    116    return 1;
    117  }
    118 
    119  if (!JS::Evaluate(cx, opts.setFileAndLine(__FILE__, __LINE__), srcBuf, &v) &&
    120      !JS_IsExceptionPending(cx)) {
    121    // A return value of `false` without a pending exception indicates
    122    // a timeout as triggered by the `timeout` shell function.
    123    return 1;
    124  }
    125 
    126  // The fuzzing module is required to handle any exceptions
    127  CrashOnPendingException();
    128 
    129  int32_t ret = 0;
    130  if (!ToInt32(cx, v, &ret)) {
    131    MOZ_CRASH("Must return an int32 compatible return value!");
    132  }
    133 
    134  return ret;
    135 }
    136 
    137 int FuzzXPCRuntimeShutdown() {
    138  JSContext* cx = gJsapi->cx();
    139  JS::Rooted<JS::Value> v(cx);
    140  JS::CompileOptions opts(cx);
    141  JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
    142 
    143  bool found = false;
    144  if (JS_HasOwnProperty(cx, global, "JSFuzzShutdown", &found)) {
    145    if (found) {
    146      static const char data[] = "JSFuzzShutdown();";
    147      JS::SourceText<mozilla::Utf8Unit> srcBuf;
    148      if (!srcBuf.init(cx, data, strlen(data), JS::SourceOwnership::Borrowed)) {
    149        return 1;
    150      }
    151 
    152      if (!JS::Evaluate(cx, opts.setFileAndLine(__FILE__, __LINE__), srcBuf,
    153                        &v) &&
    154          !JS_IsExceptionPending(cx)) {
    155        // A return value of `false` without a pending exception indicates
    156        // a timeout as triggered by the `timeout` shell function.
    157        return 1;
    158      }
    159    }
    160  }
    161 
    162  // The fuzzing module is required to handle any exceptions
    163  CrashOnPendingException();
    164 
    165  return 0;
    166 }