[tor-commits] [tor-browser] 30/37: Bug 1771084 part 2 - Add Realm option to freeze builtins. r=tcampbell, nika a=RyanVM

gitolite role git at cupani.torproject.org
Wed Jun 22 18:27:39 UTC 2022


This is an automated email from the git hooks/post-receive script.

richard pushed a commit to branch tor-browser-91.11.0esr-11.5-1
in repository tor-browser.

commit e8f8421e34d7d33ed129d6942a277785657233dc
Author: Jan de Mooij <jdemooij at mozilla.com>
AuthorDate: Tue Jun 7 15:40:44 2022 +0000

    Bug 1771084 part 2 - Add Realm option to freeze builtins. r=tcampbell,nika a=RyanVM
    
    Differential Revision: https://phabricator.services.mozilla.com/D147281
---
 js/public/Realm.h                              |  6 +++++
 js/public/RealmOptions.h                       | 10 ++++++++
 js/src/jit-test/tests/basic/freeze-builtins.js | 21 ++++++++++++++++
 js/src/shell/js.cpp                            | 10 ++++++++
 js/src/vm/GlobalObject.cpp                     | 33 ++++++++++++++++++++++++--
 js/src/vm/Realm.cpp                            | 17 +++++++++++++
 6 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/js/public/Realm.h b/js/public/Realm.h
index c3b0d20901bee..501c8af65f6ff 100644
--- a/js/public/Realm.h
+++ b/js/public/Realm.h
@@ -94,6 +94,12 @@ extern JS_PUBLIC_API JSObject* GetRealmGlobalOrNull(Realm* realm);
 // for Number).
 extern JS_PUBLIC_API bool InitRealmStandardClasses(JSContext* cx);
 
+// If the current realm has the non-standard freezeBuiltins option set to true,
+// freeze the constructor object and seal the prototype.
+extern JS_PUBLIC_API bool MaybeFreezeCtorAndPrototype(JSContext* cx,
+                                                      HandleObject ctor,
+                                                      HandleObject maybeProto);
+
 /*
  * Ways to get various per-Realm objects. All the getters declared below operate
  * on the JSContext's current Realm.
diff --git a/js/public/RealmOptions.h b/js/public/RealmOptions.h
index 5a1609bb981d7..f57b0e209dd33 100644
--- a/js/public/RealmOptions.h
+++ b/js/public/RealmOptions.h
@@ -252,6 +252,15 @@ class JS_PUBLIC_API RealmCreationOptions {
     return *this;
   }
 
+  // Non-standard option to freeze certain builtin constructors and seal their
+  // prototypes. Also defines these constructors on the global as non-writable
+  // and non-configurable.
+  bool freezeBuiltins() const { return freezeBuiltins_; }
+  RealmCreationOptions& setFreezeBuiltins(bool flag) {
+    freezeBuiltins_ = flag;
+    return *this;
+  }
+
   uint64_t profilerRealmID() const { return profilerRealmID_; }
   RealmCreationOptions& setProfilerRealmID(uint64_t id) {
     profilerRealmID_ = id;
@@ -282,6 +291,7 @@ class JS_PUBLIC_API RealmCreationOptions {
   bool propertyErrorMessageFix_ = false;
   bool iteratorHelpers_ = false;
   bool secureContext_ = false;
+  bool freezeBuiltins_ = false;
 };
 
 /**
diff --git a/js/src/jit-test/tests/basic/freeze-builtins.js b/js/src/jit-test/tests/basic/freeze-builtins.js
new file mode 100644
index 0000000000000..7f59c4b203c61
--- /dev/null
+++ b/js/src/jit-test/tests/basic/freeze-builtins.js
@@ -0,0 +1,21 @@
+var g = newGlobal({freezeBuiltins: true});
+
+g.evaluate("" + function checkFrozen(name) {
+  // Check constructor on the global is non-writable/non-configurable.
+  let desc = Object.getOwnPropertyDescriptor(this, name);
+  assertEq(desc.writable, false);
+  assertEq(desc.configurable, false);
+
+  // Constructor must be frozen.
+  let ctor = desc.value;
+  assertEq(Object.isFrozen(ctor), true);
+
+  // Prototype must be sealed.
+  if (ctor.prototype) {
+    assertEq(Object.isSealed(ctor.prototype), true);
+  }
+});
+
+g.checkFrozen("Object");
+g.checkFrozen("Array");
+g.checkFrozen("Function");
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 24dd27e27f8a2..4ed85b779274f 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7344,6 +7344,13 @@ static bool NewGlobal(JSContext* cx, unsigned argc, Value* vp) {
       creationOptions.setCoopAndCoepEnabled(v.toBoolean());
     }
 
+    if (!JS_GetProperty(cx, opts, "freezeBuiltins", &v)) {
+      return false;
+    }
+    if (v.isBoolean()) {
+      creationOptions.setFreezeBuiltins(v.toBoolean());
+    }
+
     // On the web, the SharedArrayBuffer constructor is not installed as a
     // global property in pages that aren't isolated in a separate process (and
     // thus can't allow the structured cloning of shared memory).  Specify false
@@ -9790,6 +9797,9 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
 "         (default false).\n"
 "      useWindowProxy: the global will be created with a WindowProxy attached. In this\n"
 "          case, the WindowProxy will be returned.\n"
+"      freezeBuiltins: certain builtin constructors will be frozen when created and\n"
+"          their prototypes will be sealed. These constructors will be defined on the\n"
+"          global as non-configurable and non-writable.\n"
 "      immutablePrototype: whether the global's prototype is immutable.\n"
 "      principal: if present, its value converted to a number must be an\n"
 "         integer that fits in 32 bits; use that as the new realm's\n"
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index e60c9f64d8650..842403eed2ff5 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -209,6 +209,27 @@ bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
   }
 }
 
+static bool ShouldFreezeBuiltin(JSProtoKey key) {
+  switch (key) {
+    case JSProto_Object:
+    case JSProto_Array:
+    case JSProto_Function:
+      return true;
+    default:
+      return false;
+  }
+}
+
+static unsigned GetAttrsForResolvedGlobal(GlobalObject* global,
+                                          JSProtoKey key) {
+  unsigned attrs = JSPROP_RESOLVING;
+  if (global->realm()->creationOptions().freezeBuiltins() &&
+      ShouldFreezeBuiltin(key)) {
+    attrs |= JSPROP_PERMANENT | JSPROP_READONLY;
+  }
+  return attrs;
+}
+
 /* static*/
 bool GlobalObject::resolveConstructor(JSContext* cx,
                                       Handle<GlobalObject*> global,
@@ -326,7 +347,8 @@ bool GlobalObject::resolveConstructor(JSContext* cx,
   if (isObjectOrFunction) {
     if (clasp->specShouldDefineConstructor()) {
       RootedValue ctorValue(cx, ObjectValue(*ctor));
-      if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
+      unsigned attrs = GetAttrsForResolvedGlobal(global, key);
+      if (!DefineDataProperty(cx, global, id, ctorValue, attrs)) {
         return false;
       }
     }
@@ -371,6 +393,12 @@ bool GlobalObject::resolveConstructor(JSContext* cx,
     }
   }
 
+  if (ShouldFreezeBuiltin(key)) {
+    if (!JS::MaybeFreezeCtorAndPrototype(cx, ctor, proto)) {
+      return false;
+    }
+  }
+
   if (!isObjectOrFunction) {
     // Any operations that modifies the global object should be placed
     // after any other fallible operations.
@@ -396,7 +424,8 @@ bool GlobalObject::resolveConstructor(JSContext* cx,
 
       if (shouldReallyDefine) {
         RootedValue ctorValue(cx, ObjectValue(*ctor));
-        if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
+        unsigned attrs = GetAttrsForResolvedGlobal(global, key);
+        if (!DefineDataProperty(cx, global, id, ctorValue, attrs)) {
           return false;
         }
       }
diff --git a/js/src/vm/Realm.cpp b/js/src/vm/Realm.cpp
index 1885dec878399..53b7670cda33d 100644
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -760,6 +760,23 @@ JS_PUBLIC_API bool JS::InitRealmStandardClasses(JSContext* cx) {
   return GlobalObject::initStandardClasses(cx, cx->global());
 }
 
+JS_PUBLIC_API bool JS::MaybeFreezeCtorAndPrototype(JSContext* cx,
+                                                   HandleObject ctor,
+                                                   HandleObject maybeProto) {
+  if (MOZ_LIKELY(!cx->realm()->creationOptions().freezeBuiltins())) {
+    return true;
+  }
+  if (!SetIntegrityLevel(cx, ctor, IntegrityLevel::Frozen)) {
+    return false;
+  }
+  if (maybeProto) {
+    if (!SetIntegrityLevel(cx, maybeProto, IntegrityLevel::Sealed)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 JS_PUBLIC_API JSObject* JS::GetRealmObjectPrototype(JSContext* cx) {
   CHECK_THREAD(cx);
   return GlobalObject::getOrCreateObjectPrototype(cx, cx->global());

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tor-commits mailing list