CVE-2023-24832 (C++, published 2023-05-18T22:15Z)
Description: value: A null pointer dereference bug in Hermes prior to commit 5cae9f72975cf0e5a62b27fdd8b01f103e198708 could have been used by an attacker to crash an Hermes runtime where the EnableHermesInternal config option was set to true. Note that this is only exploitable in cases where Hermes is used to execute untrusted JavaScript. Hence, most React Native applications are not affected.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-476 \u2014 NULL Pointer Dereference
The product dereferences a pointer that it expects to be valid but is NULL.
Repository: https://github.com/facebook/hermes
Files changed:
include/hermes/BCGen/HBC/BytecodeProviderFromSrc.h
lib/VM/JSLib/HermesInternal.cpp
test/hermes/regress-hermes-internal-get-lazy-function-location.js
Commit message: Avoid accessing the DebugInfo for BCProviderLazy

Summary: Fixes CVE-2023-24832 by avoiding accessing the DebugInfo for lazy CodeBlocks.

Reviewed By: mattbfb

Differential Revision: D42688370

fbshipit-source-id: fc7eb4168b1f21549cbfd080a9e010c6d8609256


Vulnerable code:
    llvm_unreachable("Accessing debug info from a lazy module");
    llvm_unreachable("Accessing string table from a lazy module");
    llvm_unreachable("Accessing bytecode from a lazy module");
    llvm_unreachable("Accessing exception info from a lazy module");
    llvm_unreachable("Accessing debug offsets from a lazy module");
  if (location) {
    auto debugInfo = runtimeModule->getBytecode()->getDebugInfo();
    return StringPrimitive::createEfficient(
        runtime, debugInfo->getFilenameByID(location->filenameId));
  } else {
    llvh::StringRef sourceURL = runtimeModule->getSourceURL();
    if (!sourceURL.empty()) {
      return StringPrimitive::createEfficient(runtime, sourceURL);

Fixed code:
    hermes_fatal("Accessing debug info from a lazy module");
    hermes_fatal("Accessing string table from a lazy module");
    hermes_fatal("Accessing bytecode from a lazy module");
    hermes_fatal("Accessing exception info from a lazy module");
    hermes_fatal("Accessing debug offsets from a lazy module");
  if (!runtimeModule->getBytecode()->isLazy()) {
    // Lazy code blocks do not have debug information (and will hermes_fatal if
    // you try to access it), so only touch it for non-lazy blocks.
    if (location) {
      auto debugInfo = runtimeModule->getBytecode()->getDebugInfo();
      return StringPrimitive::createEfficient(
          runtime, debugInfo->getFilenameByID(location->filenameId));
    } else {
      llvh::StringRef sourceURL = runtimeModule->getSourceURL();
      if (!sourceURL.empty()) {
        return StringPrimitive::createEfficient(runtime, sourceURL);
      }
static CallResult<HermesValue>
hermesInternalIsLazy(void *, Runtime &runtime, NativeArgs args) {
  auto callable = args.dyncastArg<Callable>(0);
  if (!callable) {
    return HermesValue::encodeBoolValue(false);
  }

  auto codeBlock = getLeafCodeBlock(callable, runtime);
  if (!codeBlock) {
    // Native function is never lazy.
    return HermesValue::encodeBoolValue(false);
  }

  RuntimeModule *runtimeModule = codeBlock->getRuntimeModule();
  return HermesValue::encodeBoolValue(
      runtimeModule && runtimeModule->getBytecode()->isLazy());
}

    defineInternMethodAndSymbol("isLazy", hermesInternalIsLazy);
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// RUN: %hermes -g --lazy --Xhermes-internal-test-methods -O %s | %FileCheck %s
// RUN: %hermes -g --lazy --Xhermes-internal-test-methods -O0 %s | %FileCheck %s

"use strict";

// isLazy should be able to handle native functions.
print(HermesInternal.isLazy(print));
// CHECK: false

// isLazy should be able to handle non-callables.
print(HermesInternal.isLazy(10));
// CHECK: false

function lazyFunc() {}

print(HermesInternal.isLazy(lazyFunc));
// CHECK: true

print(JSON.stringify(HermesInternal.getFunctionLocation(lazyFunc)));
// CHECK: {"isNative":false,"lineNumber":21,"columnNumber":1}

lazyFunc();

print(HermesInternal.isLazy(lazyFunc));
// CHECK: false

print(JSON.stringify(HermesInternal.getFunctionLocation(lazyFunc)));
// CHECK: {"isNative":false,"lineNumber":21,"columnNumber":1,"fileName":"{{.*}}regress-hermes-internal-get-lazy-function-location.js"}