High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the Crash Reporting component
ComponentToolkit
Bug ClassLogic Error
Tracker2068421
Fix commit0c426ca946b2 (firefox) +48/-22
CISA KEVNot listed
Creditedlocust1b
Disclosed2026-10-13

Files Changed

  • toolkit/crashreporter/crash_helper_common/src/ipc_queue.rs
  • toolkit/crashreporter/crash_helper_common/src/ipc_queue/windows.rs
  • toolkit/crashreporter/crash_helper_common/src/platform/windows.rs
diff --git a/toolkit/crashreporter/crash_helper_common/src/ipc_queue.rs b/toolkit/crashreporter/crash_helper_common/src/ipc_queue.rs
index f5794f0bbf3..884d305e1bf 100644
--- a/toolkit/crashreporter/crash_helper_common/src/ipc_queue.rs
+++ b/toolkit/crashreporter/crash_helper_common/src/ipc_queue.rs
@@ -24,6 +24,8 @@ pub enum IPCQueueError {
     IPCListenerError(#[from] IPCListenerError),
     #[error("Underlying message error: {0}")]
     MessageError(#[from] MessageError),
+    #[error("Unexpected event: {0}")]
+    UnexpectedEvent(&'static str),
 }
 
 /*****************************************************************************
diff --git a/toolkit/crashreporter/crash_helper_common/src/ipc_queue/windows.rs b/toolkit/crashreporter/crash_helper_common/src/ipc_queue/windows.rs
index 662b811dae2..c081e503a3d 100644
--- a/toolkit/crashreporter/crash_helper_common/src/ipc_queue/windows.rs
+++ b/toolkit/crashreporter/crash_helper_common/src/ipc_queue/windows.rs
@@ -185,25 +185,8 @@ impl IPCQueue {
                 )
             };
 
-            if number_of_bytes_transferred == 0 {
-                // This is an event on the listener
-                debug_assert!(
-                    self.listener.as_raw() as IPCConnectorKey == completion_key,
-                    "Completion event doesn't match the listener"
-                );
-                let operation = self.listen_operation.take();
-                if let Some(operation) = operation {
-                    operation.accept().map_err(IPCQueueError::WaitError)?;
-                }
-                let connector = Rc::new(self.listener.replace_pipe()?);
-                self.insert_connector(&connector);
-
-                // After the pipe is connected the listener handle will have been
-                // replaced with a new one, so associate the new handle with the
-                // completion queue.
-                self.add_handle(self.listener.as_raw())?;
-
-                events.push(IPCEvent::Connect(connector));
+            if self.is_listener(completion_key) {
+                events.push(self.handle_listener_event(number_of_bytes_transferred)?);
             } else {
                 let element = self
                     .connectors
@@ -213,7 +196,7 @@ impl IPCQueue {
                     .operation
                     .take()
                     .expect("No pending receive operation");
-                let buffer = operation.collect_recv();
+                let buffer = operation.collect_recv(number_of_bytes_transferred as usize);
                 let header = Header::decode(buffer)?;
                 let payload = element.connector.recv(header.size);
                 match payload {
@@ -237,6 +220,36 @@ impl IPCQueue {
 
         Ok(events)
     }
+
+    fn is_listener(&self, completion_key: IPCConnectorKey) -> bool {
+        self.listener.as_raw() as IPCConnectorKey == completion_key
+    }
+
+    fn handle_listener_event(
+        &mut self,
+        number_of_bytes_transferred: u32,
+    ) -> Result<IPCEvent, IPCQueueError> {
+        // A connection event will have 0 bytes transferred
+        if number_of_bytes_transferred != 0 {
+            return Err(IPCQueueError::UnexpectedEvent(
+                "Non-zero transfer received on the listener",
+            ));
+        }
+
+        let operation = self.listen_operation.take();
+        if let Some(operation) = operation {
+            operation.accept().map_err(IPCQueueError::WaitError)?;
+        }
+        let connector = Rc::new(self.listener.replace_pipe()?);
+        self.insert_connector(&connector);
+
+        // After the pipe is connected the listener handle will have been
+        // replaced with a new one, so associate the new handle with the
+        // completion queue.
+        self.add_handle(self.listener.as_raw())?;
+
+        Ok(IPCEvent::Connect(connector))
+    }
 }
 
 impl Drop for IPCQueue {
diff --git a/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs b/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs
index a25d3931326..d719008805f 100644
--- a/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs
+++ b/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs
@@ -421,8 +421,19 @@ impl OverlappedOperation {
         Self::sched_recv_internal(handle, None, expected_size)
     }
 
-    pub(crate) fn collect_recv(mut self) -> Vec<u8> {
-        self.buffer.take().expect("Missing receive buffer")
+    pub(crate) fn collect_recv(mut self, len: usize) -> Vec<u8> {
+        let mut buffer = self.buffer.take().expect("Missing receive buffer");
+
+        // We assert here because if this happens then we've hit a logic bug in
+        // our code. The size of the receive operation and buffer length are
+        // tied together so this should never happen.
+        assert!(
+            len <= buffer.len(),
+            "More bytes received than the buffer would allow"
+        );
+
+        buffer.truncate(len);
+        buffer
     }
 
     pub(crate) fn send(
Loading diff…