High firefox Memory Corruption 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionMemory safety bugs present in Firefox 147 and Thunderbird 147. Some of these bugs showed evidence of memory corruption and we presume that with enough effort some of these could have been exploited to run arbitrary code.
ComponentCore
Bug ClassMemory Corruption
Tracker1756056
Fix commit3aa4f024fc89 (firefox) +187/-133
CISA KEVNot listed
CreditedAgi Sferro, Andrew McCreight, Randell Jesup, Tom Schuster
Disclosed2026-02-24

Changed Functions

FunctionChangeNotes
if
mobile/shared/actors/ContentDelegateChild.sys.mjs
modified
actorCreated
mobile/shared/actors/GeckoViewContentChild.sys.mjs
modified
switch
mobile/shared/actors/GeckoViewContentParent.sys.mjs
modified
restoreState
mobile/shared/actors/GeckoViewContentParent.sys.mjs
modified
if
mobile/shared/actors/GeckoViewContentParent.sys.mjs
modified
getMediaPermission
mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
modified
mediaRecordingStatusChanged
mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
modified

Files Changed

  • mobile/shared/actors/ContentDelegateChild.sys.mjs
  • mobile/shared/actors/ContentDelegateParent.sys.mjs
  • mobile/shared/actors/GeckoViewContentChild.sys.mjs
  • mobile/shared/actors/GeckoViewContentParent.sys.mjs
  • mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
  • mobile/shared/actors/GeckoViewPermissionParent.sys.mjs
  • mobile/shared/actors/GeckoViewPrompterChild.sys.mjs
  • mobile/shared/actors/GeckoViewPrompterParent.sys.mjs
  • mobile/shared/actors/LoadURIDelegateChild.sys.mjs
  • mobile/shared/actors/LoadURIDelegateParent.sys.mjs
  • mobile/shared/actors/MediaControlDelegateChild.sys.mjs
  • mobile/shared/actors/MediaControlDelegateParent.sys.mjs
  • mobile/shared/actors/ScrollDelegateChild.sys.mjs
  • mobile/shared/actors/ScrollDelegateParent.sys.mjs
  • mobile/shared/actors/SelectionActionDelegateChild.sys.mjs
  • mobile/shared/actors/SelectionActionDelegateParent.sys.mjs
  • mobile/shared/modules/geckoview/GeckoViewActorChild.sys.mjs
  • mobile/shared/modules/geckoview/GeckoViewActorParent.sys.mjs
  • mobile/shared/modules/geckoview/LoadURIDelegate.sys.mjs
  • mobile/shared/modules/geckoview/Messaging.sys.mjs
diff --git a/mobile/shared/actors/ContentDelegateChild.sys.mjs b/mobile/shared/actors/ContentDelegateChild.sys.mjs
index 5269fe3fd9b..f5a30687b2c 100644
--- a/mobile/shared/actors/ContentDelegateChild.sys.mjs
+++ b/mobile/shared/actors/ContentDelegateChild.sys.mjs
@@ -27,10 +27,7 @@ export class ContentDelegateChild extends GeckoViewActorChild {
           return;
         }
         this.lastViewportFit = viewportFit;
-        this.eventDispatcher.sendRequest({
-          type: "GeckoView:DOMMetaViewportFit",
-          viewportfit: viewportFit,
-        });
+        this.sendAsyncMessage("GeckoView:DOMMetaViewportFit", viewportFit);
       }
     );
   }
@@ -179,7 +176,6 @@ export class ContentDelegateChild extends GeckoViewActorChild {
 
         if (uri || isImage || isMedia) {
           const msg = {
-            type: "GeckoView:ContextMenu",
             // We don't have full zoom on Android, so using CSS coordinates
             // here is fine, since the CSS coordinate spaces match between the
             // child and parent processes.
@@ -200,13 +196,13 @@ export class ContentDelegateChild extends GeckoViewActorChild {
               null,
           };
 
-          this.eventDispatcher.sendRequest(msg);
+          this.sendAsyncMessage("GeckoView:ContextMenu", msg);
           aEvent.preventDefault();
         }
         break;
       }
       case "MozDOMFullscreen:Request": {
-        this.sendAsyncMessage("GeckoView:DOMFullscreenRequest", {});
+        this.sendAsyncMessage("GeckoView:DOMFullscreenRequest");
         break;
       }
       case "MozDOMFullscreen:Entered":
@@ -219,7 +215,7 @@ export class ContentDelegateChild extends GeckoViewActorChild {
         }
       // fall-through
       case "MozDOMFullscreen:Exit":
-        this.sendAsyncMessage("GeckoView:DOMFullscreenExit", {});
+        this.sendAsyncMessage("GeckoView:DOMFullscreenExit");
         break;
       case "DOMMetaViewportFitChanged":
         if (aEvent.originalTarget.ownerGlobal == this.contentWindow) {
@@ -241,24 +237,17 @@ export class ContentDelegateChild extends GeckoViewActorChild {
             this.contentWindow
           );
           if (manifest) {
-            this.eventDispatcher.sendRequest({
-              type: "GeckoView:WebAppManifest",
-              manifest,
-            });
+            this.sendAsyncMessage("GeckoView:WebAppManifest", manifest);
           }
         });
         break;
       }
       case "MozFirstContentfulPaint": {
-        this.eventDispatcher.sendRequest({
-          type: "GeckoView:FirstContentfulPaint",
-        });
+        this.sendAsyncMessage("GeckoView:FirstContentfulPaint");
         break;
       }
       case "MozPaintStatusReset": {
-        this.eventDispatcher.sendRequest({
-          type: "GeckoView:PaintStatusReset",
-        });
+        this.sendAsyncMessage("GeckoView:PaintStatusReset");
         break;
       }
     }
diff --git a/mobile/shared/actors/ContentDelegateParent.sys.mjs b/mobile/shared/actors/ContentDelegateParent.sys.mjs
index d621c801047..f11fde38f52 100644
--- a/mobile/shared/actors/ContentDelegateParent.sys.mjs
+++ b/mobile/shared/actors/ContentDelegateParent.sys.mjs
@@ -29,6 +29,39 @@ export class ContentDelegateParent extends GeckoViewActorParent {
         this.window.windowUtils.remoteFrameFullscreenChanged(this.browser);
         return null;
       }
+
+      case "GeckoView:DOMMetaViewportFit": {
+        return this.eventDispatcher.sendRequest({
+          viewportfit: aMsg.data,
+          type: "GeckoView:DOMMetaViewportFit",
+        });
+      }
+
+      case "GeckoView:ContextMenu": {
+        return this.eventDispatcher.sendRequest({
+          ...aMsg.data,
+          type: "GeckoView:ContextMenu",
+        });
+      }
+
+      case "GeckoView:WebAppManifest": {
+        return this.eventDispatcher.sendRequest({
+          manifest: aMsg.data,
+          type: "GeckoView:WebAppManifest",
+        });
+      }
+
+      case "GeckoView:FirstContentfulPaint": {
+        return this.eventDispatcher.sendRequest({
+          type: "GeckoView:FirstContentfulPaint",
+        });
+      }
+
+      case "GeckoView:PaintStatusReset": {
+        return this.eventDispatcher.sendRequest({
+          type: "GeckoView:PaintStatusReset",
+        });
+      }
     }
 
     return super.receiveMessage(aMsg);
diff --git a/mobile/shared/actors/GeckoViewContentChild.sys.mjs b/mobile/shared/actors/GeckoViewContentChild.sys.mjs
index 23cfc73de50..cef3910b568 100644
--- a/mobile/shared/actors/GeckoViewContentChild.sys.mjs
+++ b/mobile/shared/actors/GeckoViewContentChild.sys.mjs
@@ -32,8 +32,6 @@ export class GeckoViewContentChild extends GeckoViewActorChild {
   }
 
   actorCreated() {
-    super.actorCreated();
-
     this.pageShow = new Promise(resolve => {
       this.receivedPageShow = resolve;
     });
@@ -335,8 +333,7 @@ export class GeckoViewContentChild extends GeckoViewActorChild {
           aEvent.reason === "presscaret" ||
           aEvent.reason === "releasecaret"
         ) {
-          this.eventDispatcher.sendRequest({
-            type: "GeckoView:PinOnScreen",
+          this.sendAsyncMessage("GeckoView:PinOnScreen", {
             pinned: aEvent.reason === "presscaret",
           });
         }
diff --git a/mobile/shared/actors/GeckoViewContentParent.sys.mjs b/mobile/shared/actors/GeckoViewContentParent.sys.mjs
index 069894ba967..8f61cfaf64c 100644
--- a/mobile/shared/actors/GeckoViewContentParent.sys.mjs
+++ b/mobile/shared/actors/GeckoViewContentParent.sys.mjs
@@ -28,6 +28,20 @@ export class GeckoViewContentParent extends GeckoViewActorParent {
     return this.sendQuery("ContainsFormData");
   }
 
+  async receiveMessage(aMsg) {
+    switch (aMsg.name) {
+      case "GeckoView:PinOnScreen": {
+        return this.eventDispatcher.sendRequest({
+          ...aMsg.data,
+          type: "GeckoView:PinOnScreen",
+        });
+      }
+      default: {
+        return super.receiveMessage(aMsg);
+      }
+    }
+  }
+
   restoreState({ history, switchId, formdata, scrolldata }) {
     if (Services.appinfo.sessionHistoryInParent) {
       const { browsingContext } = this.browser;
diff --git a/mobile/shared/actors/GeckoViewPermissionChild.sys.mjs b/mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
index bbe9457cc5e..d454250bb56 100644
--- a/mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
+++ b/mobile/shared/actors/GeckoViewPermissionChild.sys.mjs
@@ -20,8 +20,7 @@ const MAPPED_TO_EXTENSION_PERMISSIONS = [
 
 export class GeckoViewPermissionChild extends GeckoViewActorChild {
   getMediaPermission(aPermission) {
-    return this.eventDispatcher.sendRequestForResult({
-      type: "GeckoView:MediaPermission",
+    return this.sendQuery("GeckoView:MediaPermission", {
       ...aPermission,
     });
   }
@@ -35,8 +34,7 @@ export class GeckoViewPermissionChild extends GeckoViewActorChild {
   }
 
   mediaRecordingStatusChanged(aDevices) {
-    return this.eventDispatcher.sendRequest({
-      type: "GeckoView:MediaRecordingStatusChanged",
+    return this.sendAsyncMessage("GeckoView:MediaRecordingStatusChanged", {
       devices: aDevices,
     });
   }
@@ -132,8 +130,7 @@ export class GeckoViewPermissionChild extends GeckoViewActorChild {
 
     let allowOrDeny;
     try {
-      allowOrDeny = await this.eventDispatcher.sendRequestForResult({
-        type: "GeckoView:ContentPermission",
+      allowOrDeny = await this.sendQuery("GeckoView:ContentPermission", {
Loading diff…