High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the DOM: Core & HTML component
ComponentDOM
Bug ClassLogic Error
Tracker2074193
Fix commite2a53ef342d1 (firefox) +50/-29
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
for
dom/html/HTMLSelectElement.cpp
modified
Reset
dom/html/HTMLSelectElement.cpp
modified
if
dom/html/HTMLSelectElement.cpp
modified

Files Changed

  • dom/html/HTMLOptionElement.cpp
  • dom/html/HTMLOptionsCollection.cpp
  • dom/html/HTMLSelectElement.cpp
  • dom/prototype/PrototypeDocumentContentSink.cpp
  • dom/xml/nsXMLContentSink.cpp
diff --git a/dom/html/HTMLOptionElement.cpp b/dom/html/HTMLOptionElement.cpp
index fc17181ef7d..4fe0db3ad31 100644
--- a/dom/html/HTMLOptionElement.cpp
+++ b/dom/html/HTMLOptionElement.cpp
@@ -17,6 +17,7 @@
 #include "mozilla/dom/Document.h"
 #include "nsCOMPtr.h"
 #include "nsContentCreatorFunctions.h"
+#include "nsContentUtils.h"
 #include "nsNodeInfoManager.h"
 #include "nsTextNode.h"
 
@@ -88,6 +89,7 @@ void HTMLOptionElement::SetSelected(bool aValue) {
   // Note: The select content obj maintains all the PresState
   // so defer to it to get the answer
   if (HTMLSelectElement* select = GetSelect()) {
+    nsAutoScriptBlocker scriptBlocker;
     int32_t index = Index();
     HTMLSelectElement::OptionFlags mask{
         HTMLSelectElement::OptionFlag::SetDisabled,
@@ -129,6 +131,7 @@ int32_t HTMLOptionElement::Index() {
     return defaultIndex;
   }
 
+  nsAutoScriptBlocker scriptBlocker;
   int32_t index = defaultIndex;
   MOZ_ALWAYS_SUCCEEDS(options->GetOptionIndex(this, 0, true, &index));
   return index;
diff --git a/dom/html/HTMLOptionsCollection.cpp b/dom/html/HTMLOptionsCollection.cpp
index bbb221d3bde..399f46a4150 100644
--- a/dom/html/HTMLOptionsCollection.cpp
+++ b/dom/html/HTMLOptionsCollection.cpp
@@ -7,6 +7,7 @@
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
 #include "mozilla/dom/HTMLSelectElement.h"
+#include "nsContentUtils.h"
 
 namespace mozilla::dom {
 
@@ -41,6 +42,8 @@ HTMLSelectElement* HTMLOptionsCollection::Select() const {
 nsresult HTMLOptionsCollection::GetOptionIndex(Element* aOption,
                                                int32_t aStartIndex,
                                                bool aForward, int32_t* aIndex) {
+  MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
+             "Callers must hold a script blocker");
   BringSelfUpToDate(true);
 
   // NOTE: aIndex shouldn't be set if the returned value isn't NS_OK.
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index a2ccb9e8965..8d74c97bc0d 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -692,6 +692,7 @@ HTMLOptionElement* HTMLSelectElement::GetSelectedOption(
 }
 
 int32_t HTMLSelectElement::SelectedIndex() const {
+  nsAutoScriptBlocker scriptBlocker;
   uint32_t len = Length();
   for (uint32_t i = 0; i < len; ++i) {
     if (Item(i)->Selected()) {
@@ -702,6 +703,7 @@ int32_t HTMLSelectElement::SelectedIndex() const {
 }
 
 void HTMLSelectElement::SetSelectedIndex(int32_t aIdx) {
+  nsAutoScriptBlocker scriptBlocker;
   SetSelectedIndexInternal(aIdx, true);
   // https://html.spec.whatwg.org/#dom-select-selectedindex
   // Step 4: Run update a select's descendant selectedcontent elements.
@@ -815,6 +817,8 @@ void HTMLSelectElement::OnOptionSelected(int32_t aIndex, bool aSelected,
 bool HTMLSelectElement::SetOptionsSelectedByIndex(int32_t aStartIndex,
                                                   int32_t aEndIndex,
                                                   OptionFlags aOptionsMask) {
+  MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
+             "Callers must hold a script blocker");
 #if 0
   printf("SetOption(%d-%d, %c, ClearAll=%c)\n", aStartIndex, aEndIndex,
                                       (aOptionsMask.contains(OptionFlag::IsSelected) ? 'Y' : 'N'),
@@ -982,6 +986,7 @@ void HTMLSelectElement::GetValue(nsAString& aValue) const {
 
 // https://html.spec.whatwg.org/#dom-select-value
 void HTMLSelectElement::SetValue(const nsAString& aValue) {
+  nsAutoScriptBlocker scriptBlocker;
   uint32_t length = Length();
   int32_t matchIndex = -1;
   for (uint32_t i = 0; i < length; i++) {
@@ -1397,31 +1402,34 @@ void HTMLSelectElement::RestoreStateTo(const SelectContentData& aNewSelected) {
 
 NS_IMETHODIMP
 HTMLSelectElement::Reset() {
-  //
-  // Cycle through the options array and reset the options
-  //
-  uint32_t numOptions = Length();
+  {
+    nsAutoScriptBlocker scriptBlocker;
+    //
+    // Cycle through the options array and reset the options
+    //
+    uint32_t numOptions = Length();
+
+    for (uint32_t i = 0; i < numOptions; i++) {
+      RefPtr<HTMLOptionElement> option = Item(i);
+      if (option) {
+        //
+        // Reset the option to its default value
+        //
+
+        OptionFlags mask = {OptionFlag::SetDisabled, OptionFlag::Notify,
+                            OptionFlag::NoReselect};
+        if (option->DefaultSelected()) {
+          mask += OptionFlag::IsSelected;
+        }
 
-  for (uint32_t i = 0; i < numOptions; i++) {
-    RefPtr<HTMLOptionElement> option = Item(i);
-    if (option) {
-      //
-      // Reset the option to its default value
-      //
-
-      OptionFlags mask = {OptionFlag::SetDisabled, OptionFlag::Notify,
-                          OptionFlag::NoReselect};
-      if (option->DefaultSelected()) {
-        mask += OptionFlag::IsSelected;
+        SetOptionsSelectedByIndex(i, i, mask);
+        option->SetSelectedChanged(false);
       }
-
-      SetOptionsSelectedByIndex(i, i, mask);
-      option->SetSelectedChanged(false);
     }
-  }
 
-  // https://html.spec.whatwg.org/#concept-form-reset-control step 3
-  RunSelectednessSettingAlgorithm();
+    // https://html.spec.whatwg.org/#concept-form-reset-control step 3
+    RunSelectednessSettingAlgorithm();
+  }
 
   OnSelectionChanged();
   SetUserInteracted(false);
@@ -2113,6 +2121,7 @@ void HTMLSelectElement::RemoveOptionFromListBoxSelection(
 
 bool HTMLSelectElement::ExtendedSelection(int32_t aStartIndex,
                                           int32_t aEndIndex, bool aClearAll) {
+  nsAutoScriptBlocker scriptBlocker;
   OptionFlags mask = OptionFlag::Notify;
   mask += OptionFlag::IsSelected;
   if (aClearAll) {
@@ -2122,6 +2131,7 @@ bool HTMLSelectElement::ExtendedSelection(int32_t aStartIndex,
 }
 
 bool HTMLSelectElement::ToggleOptionSelected(int32_t aIndex) {
+  nsAutoScriptBlocker scriptBlocker;
   RefPtr<HTMLOptionElement> option = Item(static_cast<uint32_t>(aIndex));
   NS_ENSURE_TRUE(option, false);
 
@@ -2537,16 +2547,19 @@ nsresult HTMLSelectElement::HandleKeyPress(EventChainPostVisitor& aVisitor) {
                     });
     if (isSelectAll) {
       using OptionFlag = HTMLSelectElement::OptionFlag;
-      uint32_t numOptions = Length();
-      if (numOptions) {
-        HTMLSelectElement::OptionFlags mask = {
-            OptionFlag::IsSelected, OptionFlag::ClearAll, OptionFlag::Notify};
-        const bool wasChanged = SetOptionsSelectedByIndex(
-            0, AssertedCast<int32_t>(numOptions - 1), mask);
-        if (wasChanged) {
-          UserFinishedInteracting(/* aChanged = */ true);
+      bool wasChanged = false;
+      {
+        nsAutoScriptBlocker scriptBlocker;
+        if (uint32_t numOptions = Length()) {
+          HTMLSelectElement::OptionFlags mask = {
+              OptionFlag::IsSelected, OptionFlag::ClearAll, OptionFlag::Notify};
+          wasChanged = SetOptionsSelectedByIndex(
+              0, AssertedCast<int32_t>(numOptions - 1), mask);
         }
       }
+      if (wasChanged) {
+        UserFinishedInteracting(/* aChanged = */ true);
+      }
       aVisitor.mEvent->PreventDefault();
     }
     return NS_OK;
diff --git a/dom/prototype/PrototypeDocumentContentSink.cpp b/dom/prototype/PrototypeDocumentContentSink.cpp
index a916c5ceaa9..a991a397f24 100644
--- a/dom/prototype/PrototypeDocumentContentSink.cpp
+++ b/dom/prototype/PrototypeDocumentContentSink.cpp
@@ -420,6 +420,7 @@ void PrototypeDocumentContentSink::CloseElement(Element* aElement) {
   if (nsIContent::RequiresDoneAddingChildren(
           aElement->NodeInfo()->NamespaceID(),
           aElement->NodeInfo()->NameAtom())) {
+    nsAutoScriptBlocker scriptBlocker;
     aElement->DoneAddingChildren(false);
   }
 
diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp
index a07667efd11..f815a85a3d0 100644
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -630,6 +630,7 @@ nsresult nsXMLContentSink::CloseElement(nsIContent* aContent) {
   // properly (eg form state restoration).
   if (nsIContent::RequiresDoneAddingChildren(nodeInfo->NamespaceID(),
                                              nodeInfo->NameAtom())) {
+    nsAutoScriptBlocker scriptBlocker;
     aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
   }
 
Loading diff…