Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/jsapi-tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 9 kB image not shown  

Quelle  testDynamicCodeBrandChecks.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 *
 * Tests that the column number of error reports is properly copied over from
 * other reports when invoked from the C++ api.
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "jsapi-tests/tests.h"

BEGIN_TEST(testDynamicCodeBrandChecks_DefaultHostGetCodeForEval) {
  JS::RootedValue v(cx);

  // String arguments are evaluated.
  EVAL("eval('5*8');", &v);
  CHECK(v.isNumber() && v.toNumber() == 40);

  // Other arguments are returned as is by eval.
  EVAL("eval({myProp: 41});", &v);
  CHECK(v.isObject());
  JS::RootedObject obj(cx, &v.toObject());
  JS::RootedValue myProp(cx);
  CHECK(JS_GetProperty(cx, obj, "myProp", &myProp));
  CHECK(myProp.isNumber() && myProp.toNumber() == 41);

  EVAL("eval({trustedCode: '6*7'}).trustedCode;", &v);
  CHECK(v.isString());
  JSString* str = v.toString();
  CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "6*7"));

  EVAL("eval({trustedCode: 42}).trustedCode;", &v);
  CHECK(v.isNumber() && v.toNumber() == 42);

  return true;
}
END_TEST(testDynamicCodeBrandChecks_DefaultHostGetCodeForEval)

static bool ExtractTrustedCodeStringProperty(
    JSContext* aCx, JS::Handle<JSObject*> aCode,
    JS::MutableHandle<JSString*> outCode) {
  JS::RootedValue value(aCx);
  if (!JS_GetProperty(aCx, aCode, "trustedCode", &value)) {
    return false;
  }
  if (value.isUndefined()) {
    // If the property is undefined, return NO-CODE.
    outCode.set(nullptr);
    return true;
  }
  if (value.isString()) {
    // If the property is a string, return it.
    outCode.set(value.toString());
    return true;
  }
  // Otherwise, emulate a failure.
  JS_ReportErrorASCII(aCx, "Unsupported value for trustedCode property");
  return false;
}

BEGIN_TEST(testDynamicCodeBrandChecks_CustomHostGetCodeForEval) {
  JSSecurityCallbacks securityCallbacksWithEvalAcceptingObject = {
      nullptr,                           // contentSecurityPolicyAllows
      ExtractTrustedCodeStringProperty,  // codeForEvalGets
      nullptr                            // subsumes
  };
  JS_SetSecurityCallbacks(cx, &securityCallbacksWithEvalAcceptingObject);
  JS::RootedValue v(cx);

  // String arguments are evaluated.
  EVAL("eval('5*8');", &v);
  CHECK(v.isNumber() && v.toNumber() == 40);

  // Other arguments are returned as is by eval...
  EVAL("eval({myProp: 41});", &v);
  CHECK(v.isObject());
  JS::RootedObject obj(cx, &v.toObject());
  JS::RootedValue myProp(cx);
  CHECK(JS_GetProperty(cx, obj, "myProp", &myProp));
  CHECK(myProp.isNumber() && myProp.toNumber() == 41);

  // ... but Objects are first tentatively converted to String by the
  // codeForEvalGets callback.
  EVAL("eval({trustedCode: '6*7'});", &v);
  CHECK(v.isNumber() && v.toNumber() == 6 * 7);

  // And if that codeForEvalGets callback fails, then so does the eval call.
  CHECK(!execDontReport("eval({trustedCode: 6*7});", __FILE__, __LINE__));
  cx->clearPendingException();

  return true;
}
END_TEST(testDynamicCodeBrandChecks_CustomHostGetCodeForEval)

// This snippet defines a TrustedType that wraps some trustedCode string and
// stringifies to that string, as well as a helper to create a fake instance
// that can stringify to a different string.
const char* customTypesSnippet =
    "function TrustedType(aTrustedCode) { this.trustedCode = aTrustedCode; };"
    "TrustedType.prototype.toString = function() { return this.trustedCode; };"
    "function CreateFakeTrustedType(aTrustedCode, aString) {"
    " let fake = new TrustedType(aTrustedCode);"
    " fake.toString = () => { return aString; };"
    " return fake;"
    "};";

BEGIN_TEST(testDynamicCodeBrandChecks_CustomHostEnsureCanCompileStrings) {
  JSSecurityCallbacks securityCallbacksWithCustomHostEnsureCanCompileStrings = {
      StringifiedObjectsMatchTrustedCodeProperties,  // contentSecurityPolicyAllows
      ExtractTrustedCodeStringProperty,              // codeForEvalGets
      nullptr                                        // subsumes
  };
  JS_SetSecurityCallbacks(
      cx, &securityCallbacksWithCustomHostEnsureCanCompileStrings);
  JS::RootedValue v(cx);

  EXEC(customTypesSnippet);

  // String arguments are evaluated.
  EVAL("eval('5*8');", &v);
  CHECK(v.isNumber() && v.toNumber() == 40);
  EVAL("(new Function('a', 'b', 'return a * b'))(6, 7);", &v);
  CHECK(v.isNumber() && v.toNumber() == 42);

  // The same works with TrustedType wrappers.
  EVAL("eval(new TrustedType('5*8'));", &v);
  CHECK(v.isNumber() && v.toNumber() == 40);
  EVAL(
      "(new Function(new TrustedType('a'), new TrustedType('b'), new "
      "TrustedType('return a * b')))(6, 7);",
      &v);
  CHECK(v.isNumber() && v.toNumber() == 42);

  // new Function fails if one of the stringified argument does not match the
  // trustedCode property.
  CHECK(!execDontReport(
      "new Function(CreateFakeTrustedType('a', 'c'), 'b', 'return b');",
      __FILE__, __LINE__));
  cx->clearPendingException();
  CHECK(!execDontReport(
      "new Function('a', CreateFakeTrustedType('b', 'c'), 'return a');",
      __FILE__, __LINE__));
  cx->clearPendingException();
  CHECK(
      !execDontReport("new Function('a', 'b', CreateFakeTrustedType('return a "
                      "* b', 'return a + b'));",
                      __FILE__, __LINE__));
  cx->clearPendingException();

  // new Function also fails if StringifiedObjectsMatchTrustedCodeProperties
  // returns false.
  CHECK(!execDontReport("new Function('a', 'b', new TrustedType(undefined));",
                        __FILE__, __LINE__));
  cx->clearPendingException();

  // PerformEval relies on ExtractTrustedCodeProperty rather than toString() to
  // obtain the code to execute, so StringifiedObjectsMatchTrustedCodeProperties
  // will always allow the code execution for the specified security callbacks.
  EVAL("eval(CreateFakeTrustedType('5*8', '6*7'));", &v);
  CHECK(v.isNumber() && v.toNumber() == 40);
  EVAL("eval(new TrustedType(undefined));", &v);
  CHECK(v.isObject());
  JS::RootedObject obj(cx, &v.toObject());
  JS::RootedValue trustedCode(cx);
  CHECK(JS_GetProperty(cx, obj, "trustedCode", &trustedCode));
  CHECK(trustedCode.isUndefined());

  return true;
}

// This is a HostEnsureCanCompileStrings() implementation similar to some checks
// described in the CSP spec: verify that aBodyString and aParameterStrings
// match the corresponding trustedCode property on aBodyArg and aParameterArgs
// objects. See https://w3c.github.io/webappsec-csp/#can-compile-strings
static bool StringifiedObjectsMatchTrustedCodeProperties(
    JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
    JS::CompilationType aCompilationType,
    JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
    JS::Handle<JSString*> aBodyString,
    JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
    JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
  bool isTrusted = true;
  auto comparePropertyAndString = [&aCx, &isTrusted](
                                      JS::Handle<JS::Value> aValue,
                                      JS::Handle<JSString*> aString) {
    if (!aValue.isObject()) {
      // Just trust non-Objects.
      return true;
    }
    JS::RootedObject obj(aCx, &aValue.toObject());

    JS::RootedString trustedCode(aCx);
    if (!ExtractTrustedCodeStringProperty(aCx, obj, &trustedCode)) {
      // Propagate the failure.
      return false;
    }
    if (!trustedCode) {
      // Emulate a failure if trustedCode is undefined.
      JS_ReportErrorASCII(aCx,
                          "test failed, trustedCode property is undefined");
      return false;
    }
    bool equals;
    if (!EqualStrings(aCx, trustedCode, aString, &equals)) {
      // Propagate the failure.
      return false;
    }
    if (!equals) {
      isTrusted = false;
    }
    return true;
  };
  if (!comparePropertyAndString(aBodyArg, aBodyString)) {
    // Propagate the failure.
    return false;
  }
  if (isTrusted) {
    MOZ_ASSERT(aParameterArgs.length() == aParameterStrings.length());
    for (size_t index = 0; index < aParameterArgs.length(); index++) {
      if (!comparePropertyAndString(aParameterArgs[index],
                                    aParameterStrings[index])) {
        // Propagate the failure.
        return false;
      }
      if (!isTrusted) {
        break;
      }
    }
  }
  // Allow compilation if arguments are trusted.
  *aOutCanCompileStrings = isTrusted;
  return true;
}

END_TEST(testDynamicCodeBrandChecks_CustomHostEnsureCanCompileStrings)

BEGIN_TEST(testDynamicCodeBrandChecks_RejectObjectForEval) {
  JSSecurityCallbacks securityCallbacksRejectObjectBody = {
      DisallowObjectsAndFailOtherwise,   // contentSecurityPolicyAllows
      ExtractTrustedCodeStringProperty,  // codeForEvalGets
      nullptr                            // subsumes
  };

  JS_SetSecurityCallbacks(cx, &securityCallbacksRejectObjectBody);
  JS::RootedValue v(cx);

  EXEC(customTypesSnippet);

  // With the specified security callbacks, eval() will always fail.
  CHECK(!execDontReport("eval('5*8))", __FILE__, __LINE__));
  cx->clearPendingException();
  CHECK(!execDontReport("eval(new TrustedType('5*8'))", __FILE__, __LINE__));
  cx->clearPendingException();

  return true;
}

static bool DisallowObjectsAndFailOtherwise(
    JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
    JS::CompilationType aCompilationType,
    JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
    JS::Handle<JSString*> aBodyString,
    JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
    JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
  if (aBodyArg.isObject()) {
    // Disallow compilation for objects.
    *aOutCanCompileStrings = false;
    return true;
  }
  // Otherwise, emulate a failure.
  JS_ReportErrorASCII(aCx, "aBodyArg is not an Object");
  return false;
}

END_TEST(testDynamicCodeBrandChecks_RejectObjectForEval)

98%


¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.