Firefox · DOM
CVE-2026-117880
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/xml/crashtests/2075996-1.html |
modified | |
ifdom/xml/crashtests/2075996-2.html |
modified | |
ifdom/xml/crashtests/2075996.sjs |
modified |
Files Changed
dom/xml/crashtests/2075996-1.htmldom/xml/crashtests/2075996-2.htmldom/xml/crashtests/2075996.sjsdom/xml/crashtests/crashtests.listdom/xml/nsXMLContentSink.cppdom/xml/nsXMLPrettyPrinter.cpp
Patch
diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp
index 073827fdfa1..5d6caa7f1c8 100644
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -158,6 +158,11 @@ nsresult nsXMLContentSink::MaybePrettyPrint() {
nsAutoMicroTask mt;
}
+ if (mDocument->GetRootElement() != mDocElement) {
+ mPrettyPrintXML = false;
+ return NS_OK;
+ }
+
// Reenable the CSSLoader so that the prettyprinting stylesheets can load
mDocument->EnsureCSSLoader().SetEnabled(true);
diff --git a/dom/xml/nsXMLPrettyPrinter.cpp b/dom/xml/nsXMLPrettyPrinter.cpp
index fa4dfc5fab2..a20ada9be82 100644
--- a/dom/xml/nsXMLPrettyPrinter.cpp
+++ b/dom/xml/nsXMLPrettyPrinter.cpp
@@ -49,8 +49,9 @@ nsresult nsXMLPrettyPrinter::PrettyPrint(Document* aDocument,
NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
// nsXMLContentSink should not ask us to pretty print an XML doc that comes
- // with a CanAttachShadowDOM() == true root element, but just in case:
- if (rootElement->CanAttachShadowDOM()) {
+ // with a CanAttachShadowDOM() == true root element or a root element that
+ // already has a shadow root, but just in case:
+ if (rootElement->CanAttachShadowDOM() || rootElement->GetShadowRoot()) {
MOZ_DIAGNOSTIC_CRASH("We shouldn't be getting this root element");
return NS_ERROR_UNEXPECTED;
}
diff --git a/dom/xml/crashtests/2075996-1.html b/dom/xml/crashtests/2075996-1.html
new file mode 100644
index 00000000000..f07d1a39d07
--- /dev/null
+++ b/dom/xml/crashtests/2075996-1.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<body>
+<script>
+const KEY = "details";
+const url = `2075996.sjs?start&${KEY}`;
+const frame = document.createElement("iframe");
+frame.onload = () => {
+ const root = frame.contentDocument.documentElement;
+ root.setAttribute("data-a", "b");
+ root.getBoundingClientRect();
+ document.documentElement.removeAttribute("class");
+};
+frame.src = url;
+document.body.append(frame);
+const poll = setInterval(() => {
+ const doc = frame.contentDocument;
+ if (!doc?.URL.endsWith(url)) {
+ return;
+ }
+ clearInterval(poll);
+ doc.addEventListener("readystatechange", () => {
+ if (doc.readyState == "interactive") {
+ const el = doc.createElementNS("http://www.w3.org/1999/xhtml", KEY);
+ el.append("text");
+ doc.replaceChild(el, doc.documentElement);
+ }
+ });
+ fetch(`2075996.sjs?finish&${KEY}`);
+}, 0);
+</script>
+</body>
+</html>
diff --git a/dom/xml/crashtests/2075996-2.html b/dom/xml/crashtests/2075996-2.html
new file mode 100644
index 00000000000..9e10c74b93e
--- /dev/null
+++ b/dom/xml/crashtests/2075996-2.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<body>
+<script>
+const KEY = "div";
+const url = `2075996.sjs?start&${KEY}`;
+const frame = document.createElement("iframe");
+frame.onload = () => {
+ const root = frame.contentDocument.documentElement;
+ root.setAttribute("data-a", "b");
+ root.getBoundingClientRect();
+ document.documentElement.removeAttribute("class");
+};
+frame.src = url;
+document.body.append(frame);
+const poll = setInterval(() => {
+ const doc = frame.contentDocument;
+ if (!doc?.URL.endsWith(url)) {
+ return;
+ }
+ clearInterval(poll);
+ doc.addEventListener("readystatechange", () => {
+ if (doc.readyState == "interactive") {
+ const el = doc.createElementNS("http://www.w3.org/1999/xhtml", KEY);
+ el.append("text");
+ doc.replaceChild(el, doc.documentElement);
+ }
+ });
+ fetch(`2075996.sjs?finish&${KEY}`);
+}, 0);
+</script>
+</body>
+</html>
diff --git a/dom/xml/crashtests/2075996.sjs b/dom/xml/crashtests/2075996.sjs
new file mode 100644
index 00000000000..d8dcedee133
--- /dev/null
+++ b/dom/xml/crashtests/2075996.sjs
@@ -0,0 +1,17 @@
+function handleRequest(request, response) {
+ const [action, key] = request.queryString.split("&");
+ response.setHeader("Cache-Control", "no-cache", false);
+ if (action == "start") {
+ response.processAsync();
+ response.setHeader("Content-Type", "application/xml", false);
+ response.write("<root>");
+ setObjectState(key, response);
+ return;
+ }
+ getObjectState(key, xmlResponse => {
+ xmlResponse.write("</root>");
+ xmlResponse.finish();
+ });
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write("ok");
+}
diff --git a/dom/xml/crashtests/crashtests.list b/dom/xml/crashtests/crashtests.list
index f53f69d6d69..8945f90c92d 100644
--- a/dom/xml/crashtests/crashtests.list
+++ b/dom/xml/crashtests/crashtests.list
@@ -14,3 +14,5 @@ load 1192544.xhtml
load 1405878.xml
load 1523655.xml
load 2073692.html
+HTTP load 2075996-1.html
+HTTP load 2075996-2.html
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/dom/xml/crashtests/2075996-1.html b/dom/xml/crashtests/2075996-1.html
new file mode 100644
index 00000000000..f07d1a39d07
--- /dev/null
+++ b/dom/xml/crashtests/2075996-1.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<body>
+<script>
+const KEY = "details";
+const url = `2075996.sjs?start&${KEY}`;
+const frame = document.createElement("iframe");
+frame.onload = () => {
+ const root = frame.contentDocument.documentElement;
+ root.setAttribute("data-a", "b");
+ root.getBoundingClientRect();
+ document.documentElement.removeAttribute("class");
+};
+frame.src = url;
+document.body.append(frame);
+const poll = setInterval(() => {
+ const doc = frame.contentDocument;
+ if (!doc?.URL.endsWith(url)) {
+ return;
+ }
+ clearInterval(poll);
+ doc.addEventListener("readystatechange", () => {
+ if (doc.readyState == "interactive") {
+ const el = doc.createElementNS("http://www.w3.org/1999/xhtml", KEY);
+ el.append("text");
+ doc.replaceChild(el, doc.documentElement);
+ }
+ });
+ fetch(`2075996.sjs?finish&${KEY}`);
+}, 0);
+</script>
+</body>
+</html>
diff --git a/dom/xml/crashtests/2075996-2.html b/dom/xml/crashtests/2075996-2.html
new file mode 100644
index 00000000000..9e10c74b93e
--- /dev/null
+++ b/dom/xml/crashtests/2075996-2.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<body>
+<script>
+const KEY = "div";
+const url = `2075996.sjs?start&${KEY}`;
+const frame = document.createElement("iframe");
+frame.onload = () => {
+ const root = frame.contentDocument.documentElement;
+ root.setAttribute("data-a", "b");
+ root.getBoundingClientRect();
+ document.documentElement.removeAttribute("class");
+};
+frame.src = url;
+document.body.append(frame);
+const poll = setInterval(() => {
+ const doc = frame.contentDocument;
+ if (!doc?.URL.endsWith(url)) {
+ return;
+ }
+ clearInterval(poll);
+ doc.addEventListener("readystatechange", () => {
+ if (doc.readyState == "interactive") {
+ const el = doc.createElementNS("http://www.w3.org/1999/xhtml", KEY);
+ el.append("text");
+ doc.replaceChild(el, doc.documentElement);
+ }
+ });
+ fetch(`2075996.sjs?finish&${KEY}`);
+}, 0);
+</script>
+</body>
+</html>
diff --git a/dom/xml/crashtests/2075996.sjs b/dom/xml/crashtests/2075996.sjs
new file mode 100644
index 00000000000..d8dcedee133
--- /dev/null
+++ b/dom/xml/crashtests/2075996.sjs
@@ -0,0 +1,17 @@
+function handleRequest(request, response) {
+ const [action, key] = request.queryString.split("&");
+ response.setHeader("Cache-Control", "no-cache", false);
+ if (action == "start") {
+ response.processAsync();
+ response.setHeader("Content-Type", "application/xml", false);
+ response.write("<root>");
+ setObjectState(key, response);
+ return;
+ }
+ getObjectState(key, xmlResponse => {
+ xmlResponse.write("</root>");
+ xmlResponse.finish();
+ });
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write("ok");
+}
diff --git a/dom/xml/crashtests/crashtests.list b/dom/xml/crashtests/crashtests.list
index f53f69d6d69..8945f90c92d 100644
--- a/dom/xml/crashtests/crashtests.list
+++ b/dom/xml/crashtests/crashtests.list
@@ -14,3 +14,5 @@ load 1192544.xhtml
load 1405878.xml
load 1523655.xml
load 2073692.html
+HTTP load 2075996-1.html
+HTTP load 2075996-2.html
Loading diff…
References
On This Page