Firefox · DOM
CVE-2026-117930
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/base/nsGlobalWindowInner.cpp |
modified | |
ifdom/base/nsGlobalWindowOuter.cpp |
modified |
Files Changed
dom/base/nsGlobalWindowInner.cppdom/base/nsGlobalWindowInner.hdom/base/nsGlobalWindowOuter.cpp
Patch
diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp
index 62d2e74bb29..095b2f6fd47 100644
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -310,6 +310,8 @@
#include "nsTLiteralString.h"
#include "nsTObserverArray.h"
#include "nsTStringRepr.h"
+#include "nsThread.h"
+#include "nsThreadManager.h"
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "nsWindowMemoryReporter.h"
@@ -3918,8 +3920,13 @@ already_AddRefed<BrowsingContext> nsGlobalWindowInner::GetChildWindow(
}
void nsGlobalWindowInner::RefreshRealmPrincipal() {
- JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
- nsJSPrincipals::get(mDoc->NodePrincipal()));
+ JS::Realm* realm = js::GetNonCCWObjectRealm(GetWrapperPreserveColor());
+ nsJSPrincipals* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
+ nsJSPrincipals* jsPrincipals = nsJSPrincipals::get(mDoc->NodePrincipal());
+ if (existing != jsPrincipals) {
+ HoldOldPrincipal(existing);
+ }
+ JS::SetRealmPrincipals(realm, jsPrincipals);
}
void nsGlobalWindowInner::RefreshReduceTimerPrecisionCallerType() {
@@ -7977,6 +7984,25 @@ void nsGlobalWindowInner::UnnoteMediaSourceURL(const nsACString& aURL) {
MOZ_ASSERT(found, "MediaSourceURL should have been noted");
}
+void nsGlobalWindowInner::HoldOldPrincipal(nsIPrincipal* aPrincipal) {
+ mOldPrincipals.AppendElement(aPrincipal);
+ Dispatch(NewRunnableMethod(
+ "nsGlobalWindowInner::ClearOldPrincipalsIfNotNestedEventLoop", this,
+ &nsGlobalWindowInner::ClearOldPrincipalsIfNotNestedEventLoop));
+}
+
+void nsGlobalWindowInner::ClearOldPrincipalsIfNotNestedEventLoop() {
+ MOZ_ASSERT(NS_IsMainThread());
+ nsThread* mainThread = nsThreadManager::get().GetCurrentThread();
+ if (mainThread && mainThread->RecursionDepth() > 1) {
+ // Not OK to clear old principals from a nested event loop. In order
+ // to avoid spamming the nested event loop with runnables, just give
+ // up and leave the old principals around.
+ return;
+ }
+ mOldPrincipals.Clear();
+}
+
void nsPIDOMWindowInner::MaybeSetHasPointerRawUpdateEventListeners() {
if (HasPointerRawUpdateEventListeners() || !IsSecureContext()) {
return;
diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h
index 635262a0485..e804afe5ba7 100644
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -1321,7 +1321,11 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
return mClientSource.get();
}
+ void HoldOldPrincipal(nsIPrincipal* aPrincipal);
+
private:
+ void ClearOldPrincipalsIfNotNestedEventLoop();
+
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;
RefPtr<mozilla::dom::WebTaskSchedulerMainThread> mWebTaskScheduler;
@@ -1537,6 +1541,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
nsTArray<nsCString> mMediaSourceURLs;
+ // Holder for past principals to keep them alive so that we need to refcount
+ // them only when we actually swap principals and we don't need to refcount
+ // them on hot code paths in bindings that use raw pointers and must not
+ // get the principal deleted from underneath them.
+ nsTArray<nsCOMPtr<nsIPrincipal>> mOldPrincipals;
+
// These fields are used by the inner and outer windows to prevent
// programatically moving the window while the mouse is down.
static bool sMouseDown;
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index 9d5ac55c4c5..ddbc2ca41bb 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2269,14 +2269,19 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
// currentInner->RefreshRealmPrincipals() here because we haven't yet set
// its mDoc to aDocument.
JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
+ nsJSPrincipals* existing =
+ nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
+ nsJSPrincipals* jsPrincipals =
+ nsJSPrincipals::get(aDocument->NodePrincipal());
+ if (existing != jsPrincipals) {
+ newInnerWindow->HoldOldPrincipal(existing);
+ }
#ifdef DEBUG
bool sameOrigin = false;
- nsIPrincipal* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
MOZ_ASSERT(sameOrigin);
#endif
- JS::SetRealmPrincipals(realm,
- nsJSPrincipals::get(aDocument->NodePrincipal()));
+ JS::SetRealmPrincipals(realm, jsPrincipals);
} else {
if (aState) {
newInnerWindow = wsh->GetInnerWindow();
Loading diff…
References
On This Page