High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionJavaScript code running while transforming a document with the XSLTProcessor could lead to a use-after-free.
ComponentDOM
Bug ClassUAF
Tracker1941002
Fix commitbf261e3396f4 (firefox) +26/-9
CISA KEVNot listed
CreditedIvan Fratric of Google Project Zero
Disclosed2025-04-01

Changed Functions

FunctionChangeNotes
if
dom/xslt/xslt/txMozillaXSLTProcessor.cpp
modified

Files Changed

  • dom/xml/nsXMLPrettyPrinter.cpp
  • dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
  • dom/xslt/xslt/txMozillaXSLTProcessor.cpp
  • dom/xslt/xslt/txMozillaXSLTProcessor.h
diff --git a/dom/xml/nsXMLPrettyPrinter.cpp b/dom/xml/nsXMLPrettyPrinter.cpp
index c587dd0e86b..b697acd6b51 100644
--- a/dom/xml/nsXMLPrettyPrinter.cpp
+++ b/dom/xml/nsXMLPrettyPrinter.cpp
@@ -80,7 +80,7 @@ nsresult nsXMLPrettyPrinter::PrettyPrint(Document* aDocument,
   }
 
   RefPtr<DocumentFragment> resultFragment =
-      transformer->TransformToFragment(*aDocument, *aDocument, err);
+      transformer->TransformToFragment(*aDocument, false, *aDocument, err);
   if (NS_WARN_IF(err.Failed())) {
     return err.StealNSResult();
   }
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
index 1809668fedf..35933a17b38 100644
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -486,7 +486,7 @@ static nsresult handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) {
     // explicitly destroy the attrs here since we no longer need it
     atts = nullptr;
 
-    for (nsIContent* child = element->GetFirstChild(); child;
+    for (nsCOMPtr<nsIContent> child = element->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       rv = handleNode(child, aCompiler);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -500,7 +500,7 @@ static nsresult handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) {
     rv = aCompiler->characters(chars);
     NS_ENSURE_SUCCESS(rv, rv);
   } else if (aNode->IsDocument()) {
-    for (nsIContent* child = aNode->GetFirstChild(); child;
+    for (nsCOMPtr<nsIContent> child = aNode->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       rv = handleNode(child, aCompiler);
       NS_ENSURE_SUCCESS(rv, rv);
diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
index 906dcf2a3e8..50e755a4abf 100644
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -550,7 +550,10 @@ already_AddRefed<Document> txMozillaXSLTProcessor::TransformToDocument(
     return nullptr;
   }
 
-  mSource = &aSource;
+  mSource = aSource.CloneNode(true, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
 
   nsCOMPtr<Document> doc;
   rv = TransformToDoc(getter_AddRefs(doc), true);
@@ -718,7 +721,7 @@ nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult,
 }
 
 already_AddRefed<DocumentFragment> txMozillaXSLTProcessor::TransformToFragment(
-    nsINode& aSource, Document& aOutput, ErrorResult& aRv) {
+    nsINode& aSource, bool aCloneSource, Document& aOutput, ErrorResult& aRv) {
   if (NS_WARN_IF(NS_FAILED(mCompileResult))) {
     aRv.Throw(mCompileResult);
     return nullptr;
@@ -738,8 +741,17 @@ already_AddRefed<DocumentFragment> txMozillaXSLTProcessor::TransformToFragment(
     return nullptr;
   }
 
-  UniquePtr<txXPathNode> sourceNode(
-      txXPathNativeNode::createXPathNode(&aSource));
+  nsCOMPtr<nsINode> source;
+  if (aCloneSource) {
+    source = aSource.CloneNode(true, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  } else {
+    source = &aSource;
+  }
+
+  UniquePtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(source));
   if (!sourceNode) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
@@ -1046,7 +1058,7 @@ nsresult txMozillaXSLTProcessor::ensureStylesheet() {
 
   NS_ENSURE_TRUE(mStylesheetDocument, NS_ERROR_NOT_INITIALIZED);
 
-  nsINode* style = mEmbeddedStylesheetRoot;
+  nsCOMPtr<nsINode> style = mEmbeddedStylesheetRoot;
   if (!style) {
     style = mStylesheetDocument;
   }
diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.h b/dom/xslt/xslt/txMozillaXSLTProcessor.h
index b000f804c61..c8ef94aae79 100644
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.h
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h
@@ -94,7 +94,12 @@ class txMozillaXSLTProcessor final : public nsIDocumentTransformer,
 
   void ImportStylesheet(nsINode& stylesheet, mozilla::ErrorResult& aRv);
   already_AddRefed<mozilla::dom::DocumentFragment> TransformToFragment(
-      nsINode& source, mozilla::dom::Document& docVal,
+      nsINode& aSource, mozilla::dom::Document& aDocument,
+      mozilla::ErrorResult& aRv) {
+    return TransformToFragment(aSource, true, aDocument, aRv);
+  }
+  already_AddRefed<mozilla::dom::DocumentFragment> TransformToFragment(
+      nsINode& aSource, bool aCloneSource, mozilla::dom::Document& aOutput,
       mozilla::ErrorResult& aRv);
   already_AddRefed<mozilla::dom::Document> TransformToDocument(
       nsINode& source, mozilla::ErrorResult& aRv);
Loading diff…