Firefox · DOM
CVE-2025-4085
Logic Error in DOM
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
handleEventbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
isTestingOriginbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
ifbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
isSafeSchemebrowser/components/uitour/UITourChild.sys.mjs |
modified | |
ensureTrustedOriginbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
receiveMessagebrowser/components/uitour/UITourChild.sys.mjs |
modified | |
switchbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
sendPageEventbrowser/components/uitour/UITourChild.sys.mjs |
modified | |
receiveMessagebrowser/components/uitour/UITourParent.sys.mjs |
modified | |
switchbrowser/components/uitour/UITourParent.sys.mjs |
modified | |
ifbrowser/components/uitour/UITourParent.sys.mjs |
modified | |
isTestingOriginbrowser/components/uitour/UITourUtils.sys.mjs |
modified | |
ifbrowser/components/uitour/UITourUtils.sys.mjs |
modified | |
ensureTrustedOriginbrowser/components/uitour/UITourUtils.sys.mjs |
modified |
Files Changed
browser/components/uitour/UITourChild.sys.mjsbrowser/components/uitour/UITourParent.sys.mjsbrowser/components/uitour/UITourUtils.sys.mjsbrowser/components/uitour/moz.buildbrowser/components/uitour/test/browser_UITour_private_browsing.jsdom/chrome-webidl/WindowGlobalActors.webidldom/ipc/WindowGlobalChild.cppdom/ipc/WindowGlobalChild.h
Patch
diff --git a/browser/components/uitour/UITourChild.sys.mjs b/browser/components/uitour/UITourChild.sys.mjs
index 969b6923520..2df3b6e4c51 100644
--- a/browser/components/uitour/UITourChild.sys.mjs
+++ b/browser/components/uitour/UITourChild.sys.mjs
@@ -2,12 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-const PREF_TEST_ORIGINS = "browser.uitour.testingOrigins";
-const UITOUR_PERMISSION = "uitour";
+import { UITourUtils } from "moz-src:///browser/components/uitour/UITourUtils.sys.mjs";
export class UITourChild extends JSWindowActorChild {
handleEvent(event) {
- if (!this.ensureTrustedOrigin()) {
+ if (!UITourUtils.ensureTrustedOrigin(this.manager)) {
return;
}
@@ -18,62 +17,6 @@ export class UITourChild extends JSWindowActorChild {
});
}
- isTestingOrigin(aURI) {
- let testingOrigins = Services.prefs.getStringPref(PREF_TEST_ORIGINS, "");
- if (!testingOrigins) {
- return false;
- }
-
- // Allow any testing origins (comma-seperated).
- for (let origin of testingOrigins.split(/\s*,\s*/)) {
- try {
- let testingURI = Services.io.newURI(origin);
- if (aURI.prePath == testingURI.prePath) {
- return true;
- }
- } catch (ex) {
- console.error(ex);
- }
- }
- return false;
- }
-
- // This function is copied from UITour.sys.mjs.
- isSafeScheme(aURI) {
- let allowedSchemes = new Set(["https", "about"]);
- if (!allowedSchemes.has(aURI.scheme)) {
- return false;
- }
-
- return true;
- }
-
- ensureTrustedOrigin() {
- if (this.browsingContext.top != this.browsingContext) {
- return false;
- }
-
- let uri = this.document.documentURIObject;
-
- if (uri.schemeIs("chrome")) {
- return true;
- }
-
- if (!this.isSafeScheme(uri)) {
- return false;
- }
-
- let permission = Services.perms.testPermissionFromPrincipal(
- this.document.nodePrincipal,
- UITOUR_PERMISSION
- );
- if (permission == Services.perms.ALLOW_ACTION) {
- return true;
- }
-
- return this.isTestingOrigin(uri);
- }
-
receiveMessage(aMessage) {
switch (aMessage.name) {
case "UITour:SendPageCallback":
@@ -86,7 +29,7 @@ export class UITourChild extends JSWindowActorChild {
}
sendPageEvent(type, detail) {
- if (!this.ensureTrustedOrigin()) {
+ if (!UITourUtils.ensureTrustedOrigin(this.manager)) {
return;
}
diff --git a/browser/components/uitour/UITourParent.sys.mjs b/browser/components/uitour/UITourParent.sys.mjs
index 56222251074..61506d358db 100644
--- a/browser/components/uitour/UITourParent.sys.mjs
+++ b/browser/components/uitour/UITourParent.sys.mjs
@@ -3,9 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { UITour } from "moz-src:///browser/components/uitour/UITour.sys.mjs";
+import { UITourUtils } from "moz-src:///browser/components/uitour/UITourUtils.sys.mjs";
export class UITourParent extends JSWindowActorParent {
receiveMessage(message) {
+ if (!UITourUtils.ensureTrustedOrigin(this.manager)) {
+ return;
+ }
switch (message.name) {
case "UITour:onPageEvent":
if (this.manager.rootFrameLoader) {
diff --git a/browser/components/uitour/UITourUtils.sys.mjs b/browser/components/uitour/UITourUtils.sys.mjs
new file mode 100644
index 00000000000..b390b2b53dc
--- /dev/null
+++ b/browser/components/uitour/UITourUtils.sys.mjs
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const PREF_TEST_ORIGINS = "browser.uitour.testingOrigins";
+const UITOUR_PERMISSION = "uitour";
+
+export let UITourUtils = {
+ /**
+ * Check if we've got a testing origin.
+ *
+ * @param {nsIURI} uri
+ * The URI to check
+ * @returns {boolean}
+ * Whether or not it's a testing origin.
+ */
+ isTestingOrigin(uri) {
+ let testingOrigins = Services.prefs.getStringPref(PREF_TEST_ORIGINS, "");
+ if (!testingOrigins) {
+ return false;
+ }
+
+ // Allow any testing origins (comma-seperated).
+ for (let origin of testingOrigins.split(/\s*,\s*/)) {
+ try {
+ let testingURI = Services.io.newURI(origin);
+ if (uri.prePath == testingURI.prePath) {
+ return true;
+ }
+ } catch (ex) {
+ console.error(ex);
+ }
+ }
+ return false;
+ },
+
+ /**
+ *
+ * @param {WindowGlobalChild|WindowGlobalParent} windowGlobal
+ * The parent/child representation of a window global to check if we can
+ * use UITour.
+ * @returns {boolean}
+ * Whether or not we can use UITour here.
+ */
+ ensureTrustedOrigin(windowGlobal) {
+ // If we're not top-most or no longer current, bail out immediately.
+ if (windowGlobal.browsingContext.parent || !windowGlobal.isCurrentGlobal) {
+ return false;
+ }
+
+ let principal, uri;
+ // We can get either a WindowGlobalParent or WindowGlobalChild, depending on
+ // what process we're called in, and determining the secure context-ness and
+ // principal + URI needs different approaches based on this.
+ if (WindowGlobalParent.isInstance(windowGlobal)) {
+ if (!windowGlobal.browsingContext.secureBrowserUI?.isSecureContext) {
+ return false;
+ }
+ principal = windowGlobal.documentPrincipal;
+ uri = windowGlobal.documentURI;
+ } else {
+ if (!windowGlobal.contentWindow?.isSecureContext) {
+ return false;
+ }
+ let document = windowGlobal.contentWindow.document;
+ principal = document?.nodePrincipal;
+ uri = document?.documentURIObject;
+ }
+
+ if (!principal) {
+ return false;
+ }
+
+ let permission = Services.perms.testPermissionFromPrincipal(
+ principal,
+ UITOUR_PERMISSION
+ );
+ if (permission == Services.perms.ALLOW_ACTION) {
+ return true;
+ }
+
+ return uri && this.isTestingOrigin(uri);
+ },
+};
diff --git a/browser/components/uitour/moz.build b/browser/components/uitour/moz.build
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/browser/components/uitour/test/browser_UITour_private_browsing.js b/browser/components/uitour/test/browser_UITour_private_browsing.js
index 0c5a52f6674..d69bb30fbb9 100644
--- a/browser/components/uitour/test/browser_UITour_private_browsing.js
+++ b/browser/components/uitour/test/browser_UITour_private_browsing.js
@@ -16,6 +16,10 @@ add_task(async function test_privatebrowsing_window() {
const ABOUT_ORIGIN_WITH_UITOUR_DEFAULT = "about:newtab";
const HTTPS_ORIGIN_WITH_UITOUR_DEFAULT = "https://www.mozilla.org";
+ let { UITourUtils } = ChromeUtils.importESModule(
+ "moz-src:///browser/components/uitour/UITourUtils.sys.mjs"
+ );
+
let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
let browser = win.gBrowser.selectedBrowser;
@@ -26,10 +30,21 @@ add_task(async function test_privatebrowsing_window() {
BrowserTestUtils.startLoadingURIString(browser, uri);
await BrowserTestUtils.browserLoaded(browser);
+ Assert.ok(
+ UITourUtils.ensureTrustedOrigin(
+ browser.browsingContext.currentWindowGlobal
+ ),
+ "Page should be considered trusted for UITour in the parent."
+ );
+
await SpecialPowers.spawn(browser, [], async () => {
let actor = content.windowGlobalChild.getActor("UITour");
+ // eslint-disable-next-line no-shadow
+ let { UITourUtils } = ChromeUtils.importESModule(
+ "moz-src:///browser/components/uitour/UITourUtils.sys.mjs"
+ );
Assert.ok(
- actor.ensureTrustedOrigin(),
+ UITourUtils.ensureTrustedOrigin(actor.manager),
"Page should be considered trusted for UITour."
);
});
Loading diff…
References
On This Page