Skip to content

Commit

Permalink
Adding internal fuzzilli function
Browse files Browse the repository at this point in the history
Summary:
As specified in the comment above the function. Fuzzilli requires a "fuzzilli" function to run. This is used, among other things, to test crash detection (e.g. that an assert violation actually produces a crash).

In the past this function was defined in the REPRL used by fuzzilli to interface w/ Hermes. Though, this approach has some shortcoming (which I believe have caused a number of bugs to be missed few years ago when we first ran fuzzilli on Hermes): the REPRL is compiled separately by buck and the flags (e.g. to enable assert) are not forwarded to its dependencies (the VM).

Therefore, we should move this builtin inside Hermes VM. This will ensure that bugs in our build system for fuzzilli harnesses don't go undetected.

Otherwise, if something changes in the current way we propagate buck modes (T130118820), our harnesses will break w/o us knowing.

Reviewed By: jpporto

Differential Revision: D38905466

fbshipit-source-id: 71891818864f207e1d5ff7558885ee1dc083c82f
  • Loading branch information
Luigi Coniglio authored and facebook-github-bot committed Sep 14, 2022
1 parent ef1d502 commit d449a76
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
5 changes: 5 additions & 0 deletions include/hermes/VM/NativeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ NATIVE_FUNCTION(hermesInternalUseEngineQueue)
NATIVE_FUNCTION(hermesInternalEnqueueJob)
NATIVE_FUNCTION(hermesInternalDrainJobs)

#ifdef HERMES_ENABLE_FUZZILLI
NATIVE_FUNCTION(hermesInternalFuzzilli)
#endif


#ifdef HERMES_ENABLE_DEBUGGER
NATIVE_FUNCTION(isDebuggerAttached)
NATIVE_FUNCTION(shouldPauseOnThrow)
Expand Down
5 changes: 5 additions & 0 deletions include/hermes/VM/PredefinedStrings.def
Original file line number Diff line number Diff line change
Expand Up @@ -519,4 +519,9 @@ STR(__rnReserved18, "nativeQPLMarkerAnnotate")
STR(__rnReserved20, "nativeGetThreadMajorPageFaults")
STR(__rnReserved21, "__jsiExecutorDescription")

#ifdef HERMES_ENABLE_FUZZILLI
STR(fuzzilli, "fuzzilli")
#endif


#undef STR
81 changes: 81 additions & 0 deletions lib/VM/JSLib/HermesInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,83 @@ CallResult<HermesValue> hermesInternalEnablePromiseRejectionTracker(
.toCallResultHermesValue();
}

#ifdef HERMES_ENABLE_FUZZILLI

/// Internal "fuzzilli" function used by the Fuzzilli fuzzer
/// (https://github.com/googleprojectzero/fuzzilli) to sanity-check the engine.
/// This function is conditionally defined in Hermes internal VM code rather
/// than in an external fuzzing module so to catch build misconfigurations, e.g.
/// we want to make sure that the VM is compiled with assertions enabled and
/// doing this check out of the VM (e.g. in the fuzzing harness) doesn't
/// guarantee that the VM has asserts on.
///
/// This function is defined as follow:
/// \code
/// HermesInternal.fuzzilli = function(op, arg) {}
/// \endcode
/// The first argument "op", is a string specifying the operation to be
/// performed. Currently supported values of "op" are "FUZZILLI_CRASH", used to
/// simulate a crash, and "FUZZILLI_PRINT", used to send data over Fuzzilli's
/// ata write file decriptor (REPRL_DWFD). The secong argument "arg" can be an
/// integer specifying the type of crash (if op is "FUZZILLI_CRASH") or a string
/// which value will be sent to fuzzilli (if op is "FUZZILLI_PRINT")
CallResult<HermesValue>
hermesInternalFuzzilli(void *, Runtime &runtime, NativeArgs args) {
// REPRL = read-eval-print-reset-loop
// This file descriptor is being opened by Fuzzilli
constexpr int REPRL_DWFD = 103; // Data write file decriptor

auto operationRes = toString_RJS(runtime, args.getArgHandle(0));
if (LLVM_UNLIKELY(operationRes == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
auto operation = StringPrimitive::createStringView(
runtime, runtime.makeHandle(std::move(*operationRes)));

if (operation.equals(createUTF16Ref(u"FUZZILLI_CRASH"))) {
auto crashTypeRes = toIntegerOrInfinity(runtime, args.getArgHandle(1));
if (LLVM_UNLIKELY(crashTypeRes == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
switch (crashTypeRes->getNumberAs<int>()) {
case 0:
*((int *)0x41414141) = 0x1337;
break;
case 1:
assert(0);
break;
case 2:
std::abort();
break;
}
} else if (operation.equals(createUTF16Ref(u"FUZZILLI_PRINT"))) {
static FILE *fzliout = fdopen(REPRL_DWFD, "w");
if (!fzliout) {
fprintf(
stderr,
"Fuzzer output channel not available, printing to stdout instead\n");
fzliout = stdout;
}

auto printRes = toString_RJS(runtime, args.getArgHandle(1));
if (LLVM_UNLIKELY(printRes == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
auto print = StringPrimitive::createStringView(
runtime, runtime.makeHandle(std::move(*printRes)));

vm::SmallU16String<32> allocator;
std::string outputString;
::hermes::convertUTF16ToUTF8WithReplacements(
outputString, print.getUTF16Ref(allocator));
fprintf(fzliout, "%s\n", outputString.c_str());
fflush(fzliout);
}

return HermesValue::encodeUndefinedValue();
}
#endif // HERMES_ENABLE_FUZZILLI

Handle<JSObject> createHermesInternalObject(
Runtime &runtime,
const JSLibFlags &flags) {
Expand Down Expand Up @@ -805,6 +882,10 @@ Handle<JSObject> createHermesInternalObject(
hermesInternalEnablePromiseRejectionTracker);
defineInternMethod(P::useEngineQueue, hermesInternalUseEngineQueue);

#ifdef HERMES_ENABLE_FUZZILLI
defineInternMethod(P::fuzzilli, hermesInternalFuzzilli);
#endif

// All functions are known to be safe can be defined above this flag check.
if (!flags.enableHermesInternal) {
JSObject::preventExtensions(*intern);
Expand Down

0 comments on commit d449a76

Please sign in to comment.