Firefox · Core
CVE-2026-2777
Logic Error in Core
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
handleEventbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
actorCreatedbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
exportFunctionsbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
ifbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
forbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
MPToggleLightsbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
MPShowMessagebrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
MPShouldShowHintbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs |
modified | |
ifbrowser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs |
modified | |
receiveMessagebrowser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs |
modified | |
switchbrowser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs |
modified |
Files Changed
browser/components/DesktopActorRegistry.sys.mjsbrowser/components/about/AboutRedirector.cppbrowser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjsbrowser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjsbrowser/components/messagepreview/messagepreview.cssbrowser/components/messagepreview/messagepreview.jsbrowser/components/messagepreview/tests/browser/browser.tomlbrowser/components/messagepreview/tests/browser/browser_messagepreview_receivemessage.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_bookmarks_bar.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_cfr.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_featurecallout.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_infobar.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_invalidmessage.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_privatebrowsing.jsbrowser/components/messagepreview/tests/browser/browser_messagepreview_show_spotlight.jsbrowser/components/messagepreview/tests/browser/head.js
Patch
diff --git a/browser/components/DesktopActorRegistry.sys.mjs b/browser/components/DesktopActorRegistry.sys.mjs
index 6bb71df3fee..4f309368c07 100644
--- a/browser/components/DesktopActorRegistry.sys.mjs
+++ b/browser/components/DesktopActorRegistry.sys.mjs
@@ -135,6 +135,9 @@ let JSWINDOWACTORS = {
},
},
matches: ["about:messagepreview", "about:messagepreview?*"],
+ remoteTypes: ["privilegedabout"],
+ enablePreference:
+ "browser.newtabpage.activity-stream.asrouter.devtoolsEnabled",
},
AboutPrivateBrowsing: {
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index 0754291ab98..c63491d2fa9 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -116,6 +116,7 @@ static const RedirEntry kRedirMap[] = {
{"messagepreview",
"chrome://browser/content/messagepreview/messagepreview.html",
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
+ nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
{"settings", "chrome://browser/content/preferences/preferences.xhtml",
diff --git a/browser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs b/browser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs
index cd0944d3c7c..3e8234ebdb7 100644
--- a/browser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs
+++ b/browser/components/messagepreview/actors/AboutMessagePreviewChild.sys.mjs
@@ -2,9 +2,20 @@
* 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/. */
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+
+const lazy = XPCOMUtils.declareLazy({
+ log: () => {
+ const { Logger } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/Logger.sys.mjs"
+ );
+ return new Logger("AboutMessagePreviewChild");
+ },
+});
+
export class AboutMessagePreviewChild extends JSWindowActorChild {
handleEvent(event) {
- console.log(`Received page event ${event.type}`);
+ lazy.log.debug(`Received page event ${event.type}`);
}
actorCreated() {
@@ -13,12 +24,7 @@ export class AboutMessagePreviewChild extends JSWindowActorChild {
exportFunctions() {
if (this.contentWindow) {
- for (const name of [
- "MPShowMessage",
- "MPIsEnabled",
- "MPShouldShowHint",
- "MPToggleLights",
- ]) {
+ for (const name of ["MPShowMessage", "MPIsEnabled", "MPToggleLights"]) {
Cu.exportFunction(this[name].bind(this), this.contentWindow, {
defineAs: name,
});
@@ -42,11 +48,11 @@ export class AboutMessagePreviewChild extends JSWindowActorChild {
/**
* Check the browser theme and switch it.
*/
- MPToggleLights() {
+ async MPToggleLights() {
const isDark = this.contentWindow.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
- this.sendAsyncMessage(`MessagePreview:CHANGE_THEME`, { isDark });
+ await this.sendQuery(`MessagePreview:CHANGE_THEME`, { isDark });
}
/**
@@ -55,16 +61,7 @@ export class AboutMessagePreviewChild extends JSWindowActorChild {
*
* @param {object} message
*/
- MPShowMessage(message) {
- this.sendAsyncMessage(`MessagePreview:SHOW_MESSAGE`, message);
- }
-
- /**
- * Check if a hint should be shown about how to enable Message Preview.
- *
- * @returns {boolean}
- */
- MPShouldShowHint() {
- return !this.MPIsEnabled();
+ async MPShowMessage(message) {
+ await this.sendQuery(`MessagePreview:SHOW_MESSAGE`, message);
}
}
diff --git a/browser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs b/browser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs
index 32501487c57..0dc0040a8ec 100644
--- a/browser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs
+++ b/browser/components/messagepreview/actors/AboutMessagePreviewParent.sys.mjs
@@ -3,12 +3,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/. */
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
import { ASRouter } from "resource:///modules/asrouter/ASRouter.sys.mjs";
import { JsonSchema } from "resource://gre/modules/JsonSchema.sys.mjs";
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
+const lazy = XPCOMUtils.declareLazy({
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
BookmarksBarButton: "resource:///modules/asrouter/BookmarksBarButton.sys.mjs",
CFRPageActions: "resource:///modules/asrouter/CFRPageActions.sys.mjs",
@@ -20,6 +19,13 @@ ChromeUtils.defineESModuleGetters(lazy, {
SpecialMessageActions:
"resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
Spotlight: "resource:///modules/asrouter/Spotlight.sys.mjs",
+
+ log: () => {
+ const { Logger } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/Logger.sys.mjs"
+ );
+ return new Logger("AboutMessagePreviewParent");
+ },
});
const SWITCH_THEMES = {
@@ -114,7 +120,7 @@ export class AboutMessagePreviewParent extends JSWindowActorParent {
}
screen.anchors = [...existingAnchors, fallbackAnchor];
- console.log("ANCHORS: ", screen.anchors);
+ lazy.log.debug("ANCHORS: ", screen.anchors);
}
// Try showing again
await lazy.FeatureCalloutBroker.showFeatureCallout(browser, message);
@@ -137,7 +143,7 @@ export class AboutMessagePreviewParent extends JSWindowActorParent {
try {
message = JSON.parse(data);
} catch (e) {
- console.error("Could not parse message", e);
+ lazy.log.error("Could not parse message", e);
return;
}
@@ -148,7 +154,7 @@ export class AboutMessagePreviewParent extends JSWindowActorParent {
).then(rsp => rsp.json());
const result = JsonSchema.validate(message, schema);
if (!result.valid) {
- console.error(
+ lazy.log.error(
`Invalid message: ${JSON.stringify(result.errors, undefined, 2)}`
);
}
@@ -176,25 +182,27 @@ export class AboutMessagePreviewParent extends JSWindowActorParent {
this.showPrivateBrowsingMessage(message, browser);
return;
default:
- console.error(`Unsupported message template ${message.template}`);
+ lazy.log.error(`Unsupported message template ${message.template}`);
}
}
- receiveMessage(message) {
+ async receiveMessage(message) {
// validationEnabled is used for testing
const { name, data, validationEnabled } = message;
switch (name) {
case "MessagePreview:SHOW_MESSAGE":
- this.showMessage(data, validationEnabled);
+ await this.showMessage(data, validationEnabled);
return;
case "MessagePreview:CHANGE_THEME": {
const theme = data.isDark ? SWITCH_THEMES.LIGHT : SWITCH_THEMES.DARK;
- lazy.AddonManager.getAddonByID(theme).then(addon => addon.enable());
+ await lazy.AddonManager.getAddonByID(theme).then(addon =>
+ addon.enable()
+ );
return;
}
default:
- console.log(`Unexpected event ${name} was not handled.`);
+ lazy.log.debug(`Unexpected event ${name} was not handled.`);
}
}
}
diff --git a/browser/components/messagepreview/messagepreview.css b/browser/components/messagepreview/messagepreview.css
index 18ade19f50d..7d25913e2c2 100644
--- a/browser/components/messagepreview/messagepreview.css
+++ b/browser/components/messagepreview/messagepreview.css
@@ -34,15 +34,3 @@ body {
transform: scaleY(-1);
}
}
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/browser/components/messagepreview/tests/browser/browser.toml b/browser/components/messagepreview/tests/browser/browser.toml
index 827436e4748..880abe1e970 100644
--- a/browser/components/messagepreview/tests/browser/browser.toml
+++ b/browser/components/messagepreview/tests/browser/browser.toml
@@ -20,8 +20,5 @@ prefs = [
["browser_messagepreview_show_invalidmessage.js"]
["browser_messagepreview_show_privatebrowsing.js"]
-skip-if = [
- "true", # Bug 1946629
-]
["browser_messagepreview_show_spotlight.js"]
diff --git a/browser/components/messagepreview/tests/browser/browser_messagepreview_receivemessage.js b/browser/components/messagepreview/tests/browser/browser_messagepreview_receivemessage.js
index 58ec7a65d4a..8382bdd6435 100644
--- a/browser/components/messagepreview/tests/browser/browser_messagepreview_receivemessage.js
+++ b/browser/components/messagepreview/tests/browser/browser_messagepreview_receivemessage.js
@@ -4,24 +4,40 @@ const { AboutMessagePreviewParent } = ChromeUtils.importESModule(
"resource:///actors/AboutWelcomeParent.sys.mjs"
);
+let messageSandbox;
+add_setup(async function () {
+ messageSandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ messageSandbox.restore();
+ });
+});
+
/**
* Test the parent receiveMessage function
*/
add_task(async function test_receive_message() {
- const messageSandbox = sinon.createSandbox();
let { cleanup, browser } = await openMessagePreviewTab();
let aboutMessagePreviewActor = await getAboutMessagePreviewParent(browser);
messageSandbox.spy(aboutMessagePreviewActor, "receiveMessage");
- registerCleanupFunction(() => {
- messageSandbox.restore();
- });
- await aboutMessagePreviewActor.receiveMessage(
- "MessagePreview:SHOW_MESSAGE",
- {}
- );
+ await aboutMessagePreviewActor.receiveMessage({
+ name: "MessagePreview:SHOW_MESSAGE",
+ target: {
+ browsingContext: {
+ currentRemoteType: "privilegedabout",
+ },
+ },
+ });
- await aboutMessagePreviewActor.receiveMessage("MessagePreview:CHANGE_THEME");
+ await aboutMessagePreviewActor.receiveMessage({
+ name: "MessagePreview:CHANGE_THEME",
+ data: {},
+ target: {
+ browsingContext: {
+ currentRemoteType: "privilegedabout",
+ },
+ },
+ });
const { callCount } = aboutMessagePreviewActor.receiveMessage;
let messageCall;
@@ -29,9 +45,9 @@ add_task(async function test_receive_message() {
for (let i = 0; i < callCount; i++) {
const call = aboutMessagePreviewActor.receiveMessage.getCall(i);
info(`Call #${i}: ${JSON.stringify(call.args[0])}`);
- if (call.calledWithMatch("MessagePreview:SHOW_MESSAGE")) {
+ if (call.calledWithMatch({ name: "MessagePreview:SHOW_MESSAGE" })) {
messageCall = call;
- } else if (call.calledWithMatch("MessagePreview:CHANGE_THEME")) {
+ } else if (call.calledWithMatch({ name: "MessagePreview:CHANGE_THEME" })) {
themeCall = call;
}
}
@@ -39,15 +55,16 @@ add_task(async function test_receive_message() {
Assert.greaterOrEqual(callCount, 2, `${callCount} receive spy was called`);
Assert.equal(
- messageCall.args[0],
+ messageCall.args[0]?.name,
"MessagePreview:SHOW_MESSAGE",
"Got call to handle showing a message"
);
Assert.equal(
- themeCall.args[0],
+ themeCall.args[0]?.name,
"MessagePreview:CHANGE_THEME",
"Got call to handle changing the theme"
);
+ messageSandbox.restore();
await cleanup();
});
diff --git a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_bookmarks_bar.js b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_bookmarks_bar.js
index 09fe1a00e43..722303f7cc9 100644
--- a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_bookmarks_bar.js
+++ b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_bookmarks_bar.js
@@ -4,6 +4,8 @@ const { AboutMessagePreviewParent } = ChromeUtils.importESModule(
"resource:///actors/AboutWelcomeParent.sys.mjs"
);
+let messageSandbox;
+
const TEST_BOOKMARKS_BAR_MESSAGE = {
id: "TEST_BMB_BAR_BUTTON",
groups: [],
@@ -26,30 +28,32 @@ const TEST_BOOKMARKS_BAR_MESSAGE = {
targeting: "true",
};
+add_setup(async function () {
+ messageSandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ messageSandbox.restore();
+ });
+});
+
add_task(async function test_show_bookmarks_bar_button_message() {
- const messageSandbox = sinon.createSandbox();
let { cleanup, browser } = await openMessagePreviewTab();
let aboutMessagePreviewActor = await getAboutMessagePreviewParent(browser);
messageSandbox.spy(aboutMessagePreviewActor, "showMessage");
- registerCleanupFunction(() => {
- messageSandbox.restore();
- });
- await aboutMessagePreviewActor.receiveMessage({
- name: "MessagePreview:SHOW_MESSAGE",
- data: JSON.stringify(TEST_BOOKMARKS_BAR_MESSAGE),
- validationEnabled: false,
- });
+ await SpecialPowers.spawn(browser, [TEST_BOOKMARKS_BAR_MESSAGE], message =>
+ content.wrappedJSObject.MPShowMessage(JSON.stringify(message))
+ );
const { callCount } = aboutMessagePreviewActor.showMessage;
Assert.greaterOrEqual(callCount, 1, "showMessage was called");
- await ContentTaskUtils.waitForCondition(
+ await BrowserTestUtils.waitForCondition(
() => selectorIsVisible("#fxms-bmb-button"),
"Bookmarks toolbar button should be visible"
);
// Remove the button, so repeated tests don't fail
await CustomizableUI.destroyWidget("fxms-bmb-button");
+ messageSandbox.restore();
await cleanup();
});
diff --git a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_cfr.js b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_cfr.js
index 592cbeede0d..708a81d10e8 100644
--- a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_cfr.js
+++ b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_cfr.js
@@ -4,6 +4,8 @@ const { AboutMessagePreviewParent } = ChromeUtils.importESModule(
"resource:///actors/AboutWelcomeParent.sys.mjs"
);
+let messageSandbox;
+
const TEST_CFR_MESSAGE = {
content: {
text: {
@@ -57,19 +59,21 @@ const TEST_CFR_MESSAGE = {
id: "CFR_FULL_VIDEO_SUPPORT_EN",
};
+add_setup(async function () {
+ messageSandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ messageSandbox.restore();
+ });
+});
+
add_task(async function test_show_cfr_message() {
- const messageSandbox = sinon.createSandbox();
let { cleanup, browser } = await openMessagePreviewTab();
let aboutMessagePreviewActor = await getAboutMessagePreviewParent(browser);
messageSandbox.spy(aboutMessagePreviewActor, "showMessage");
- registerCleanupFunction(() => {
- messageSandbox.restore();
- });
- await aboutMessagePreviewActor.receiveMessage({
- name: "MessagePreview:SHOW_MESSAGE",
- data: JSON.stringify(TEST_CFR_MESSAGE),
- });
+ await SpecialPowers.spawn(browser, [TEST_CFR_MESSAGE], message =>
+ content.wrappedJSObject.MPShowMessage(JSON.stringify(message))
+ );
const { callCount } = aboutMessagePreviewActor.showMessage;
Assert.greaterOrEqual(callCount, 1, "showMessage was called");
@@ -85,5 +89,6 @@ add_task(async function test_show_cfr_message() {
);
await clearNotifications();
+ messageSandbox.restore();
await cleanup();
});
diff --git a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_featurecallout.js b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_featurecallout.js
index ec4a9afe700..69ce2e3a128 100644
--- a/browser/components/messagepreview/tests/browser/browser_messagepreview_show_featurecallout.js
+++ b/browser/components/messagepreview/tests/browser/browser_messagepreview_show_featurecallout.js
@@ -4,6 +4,8 @@ const { AboutMessagePreviewParent } = ChromeUtils.importESModule(
"resource:///actors/AboutWelcomeParent.sys.mjs"
);
+let messageSandbox;
+
// A feature callout that needs no modification
const TEST_HAPPY_FEATURE_CALLOUT_MESSAGE = {
id: "TEST_HAPPY_FEATURE_CALLOUT",
@@ -276,32 +278,28 @@ const TEST_VERY_BAD_FEATURE_CALLOUT = {
provider: "panel_local_testing",
};
+add_setup(async function () {
+ messageSandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ messageSandbox.restore();
+ });
+});
+
/**
* Test each version of the feature callout
*/
add_task(async function test_show_happy_feature_callout_message() {
- const messageSandbox = sinon.createSandbox();
// FeatureCallout needs a new window
const win = await BrowserTestUtils.openNewBrowserWindow();
- let tab = await BrowserTestUtils.openNewForegroundTab(
- win.gBrowser,
- "about:messagepreview",
- true
- );
-
- let aboutMessagePreviewActor = await getAboutMessagePreviewParent(
- tab.linkedBrowser
- );
+ let { browser } = await openMessagePreviewTab(win.gBrowser);
+ let aboutMessagePreviewActor = await getAboutMessagePreviewParent(browser);
messageSandbox.spy(aboutMessagePreviewActor, "showMessage");
- registerCleanupFunction(() => {
- messageSandbox.restore();
- });
- await aboutMessagePreviewActor.receiveMessage({
- name: "MessagePreview:SHOW_MESSAGE",
- data: JSON.stringify(TEST_HAPPY_FEATURE_CALLOUT_MESSAGE),
- validationEnabled: false,
- });
+ await SpecialPowers.spawn(
+ browser,
+ [TEST_HAPPY_FEATURE_CALLOUT_MESSAGE],
+ message => content.wrappedJSObject.MPShowMessage(JSON.stringify(message))
+ );
const { callCount } = aboutMessagePreviewActor.showMessage;
Assert.greaterOrEqual(callCount, 1, "showMessage was called");
@@ -320,32 +318,23 @@ add_task(async function test_show_happy_feature_callout_message() {
await waitForClick("button.dismiss-button", win);
await dialogClosed(win);
+ messageSandbox.restore();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_show_feature_callout_without_trigger() {
- const messageSandbox = sinon.createSandbox();
// FeatureCallout needs a new window
const win = await BrowserTestUtils.openNewBrowserWindow();
- let tab = await BrowserTestUtils.openNewForegroundTab(
- win.gBrowser,
- "about:messagepreview",
- true
- );
-
- let aboutMessagePreviewActor = await getAboutMessagePreviewParent(
- tab.linkedBrowser
- );
+ let { browser } = await openMessagePreviewTab(win.gBrowser);
+ let aboutMessagePreviewActor = await getAboutMessagePreviewParent(browser);
messageSandbox.spy(aboutMessagePreviewActor, "showMessage");
- registerCleanupFunction(() => {
- messageSandbox.restore();
- });
- await aboutMessagePreviewActor.receiveMessage({
- name: "MessagePreview:SHOW_MESSAGE",
- data: JSON.stringify(TEST_FEATURE_CALLOUT_NO_TRIGGER),
- validationEnabled: false,
- });
+ await SpecialPowers.spawn(
+ browser,
+ [TEST_FEATURE_CALLOUT_NO_TRIGGER],
... (truncated)
Loading diff…
References
On This Page