[tbb-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 tbb-commits
mailing list