Firefox · DOM
CVE-2026-117935
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/bindings/BindingUtils.h |
modified |
Files Changed
dom/bindings/BindingUtils.hdom/bindings/Codegen.pydom/bindings/DOMJSProxyHandler.cppdom/bindings/DOMJSProxyHandler.h
Patch
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index 19bf4535deb..9ade09b0bc6 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2843,6 +2843,9 @@ class MOZ_STACK_CLASS BindingJSObjectCreator {
~BindingJSObjectCreator() {
if (mReflector) {
+ if (IsDOMProxy(mReflector)) {
+ js::SetProxyPrivate(mReflector, JS::UndefinedValue());
+ }
JS::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
}
}
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index e5208d330be..4c22bdccd64 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4708,6 +4708,14 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
)
if self.descriptor.proxy:
+ if self.descriptor.hasLegacyUnforgeableMembers:
+ failureCode = fill(
+ """
+ DOMProxyHandler::ClearExpandoOnWrapFailure(aReflector);
+ $*{failureCode}
+ """,
+ failureCode=failureCode,
+ )
finalize = "DOMProxyHandler::getInstance()->finalize"
else:
finalize = FINALIZE_HOOK_NAME
@@ -4848,8 +4856,6 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
)
def definition_body(self):
- failureCode = "return false;\n"
-
declareProto = DeclareProto(self.descriptor, noGivenProto=self.noGivenProto)
if self.noGivenProto:
assertGivenProto = ""
@@ -4859,6 +4865,15 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
"""
)
+ failureCode = "return false;\n"
+ if self.descriptor.proxy and self.descriptor.hasLegacyUnforgeableMembers:
+ failureCode = fill(
+ """
+ DOMProxyHandler::ClearExpandoOnWrapFailure(aReflector);
+ $*{failureCode}
+ """,
+ failureCode=failureCode,
+ )
return fill(
"""
$*{assertions}
diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp
index d9ba5df6bf8..d2fdfd6bfbd 100644
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -154,6 +154,27 @@ JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx,
return expando;
}
+// static
+void DOMProxyHandler::ClearExpandoOnWrapFailure(JSObject* obj) {
+ MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
+
+ JS::Value v = js::GetProxyPrivate(obj);
+ if (v.isObject() || v.isUndefined()) {
+ return;
+ }
+
+ MOZ_ASSERT(!js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).isUndefined(),
+ "Must not clear the native slot before stopping tracing the "
+ "expando owned by native object");
+
+ auto* expandoAndGeneration =
+ static_cast<JS::ExpandoAndGeneration*>(v.toPrivate());
+ // If wrapper initialization fails, the proxy no longer owns the native
+ // object, so it should not trace the expando owned by the native object.
+ // Reset the expando as well to avoid leaving an untraced reference to it.
+ expandoAndGeneration->expando = JS::UndefinedValue();
+}
+
bool DOMProxyHandler::preventExtensions(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::ObjectOpResult& result) const {
@@ -290,9 +311,12 @@ void ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const {
JS::Value v = js::GetProxyPrivate(proxy);
MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!");
- // The proxy's private slot is set when we allocate the proxy,
- // so it cannot be |undefined|.
- MOZ_ASSERT(!v.isUndefined());
+ if (v.isUndefined()) {
+ MOZ_ASSERT(js::GetProxyReservedSlot(proxy, DOM_OBJECT_SLOT).isUndefined(),
+ "Only a proxy whose initialization failed should have an "
+ "undefined private slot");
+ return;
+ }
auto* expandoAndGeneration =
static_cast<JS::ExpandoAndGeneration*>(v.toPrivate());
diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h
index 0e4d3e1c616..b325450566c 100644
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -125,6 +125,12 @@ class DOMProxyHandler : public BaseDOMProxyHandler {
static JSObject* EnsureExpandoObject(JSContext* cx,
JS::Handle<JSObject*> obj);
+ /*
+ * Clear the ExpandoAndGeneration from a proxy whose initialization failed.
+ * This must be called before releasing the native object.
+ */
+ static void ClearExpandoOnWrapFailure(JSObject* obj);
+
static const char family;
};
Loading diff…
References
On This Page