Low CVSS 7.5 firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
7.5
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionA website configured to initiate a specially crafted WebTransport session could crash the Firefox process leading to a denial of service condition.
ComponentNetworking
Bug ClassLogic Error
Tracker1907726
Fix commitb9cc99cebaa4 (firefox) +9/-9
CWECWE-404
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CISA KEVNot listed
CreditedMarten Richter
Disclosed2024-10-01

Background

WebTransport
a network protocol, exposed to web content, that lets a site open a session for bidirectional streams and unreliable datagram messages over HTTP/3.
`WebTransportSessionProxy`
the networking-layer object that proxies WebTransport events (such as received datagrams) between the socket thread and the main-thread listener that consumes them.
`mPendingEvents`
a queue of deferred callback closures on WebTransportSessionProxy that holds events until the session is fully ready to deliver them.
`mStopRequestCalled`
a boolean flag on WebTransportSessionProxy indicating that request startup has completed and it is safe to dispatch events directly rather than queue them.

Root Cause Analysis

Incoming datagrams enter through WebTransportSessionProxy::OnDatagramReceivedInternal, which is responsible for marshaling the data onto the correct thread before WebTransportSessionProxy::NotifyDatagramReceived finally delivers it to mListener. In the vulnerable code, the “not yet ready” guard that checks !mStopRequestCalled and defers work onto mPendingEvents lived inside NotifyDatagramReceived, which runs only after the thread-dispatch and state validation performed by OnDatagramReceivedInternal. This violated the invariant that datagram processing must not touch session state, mTarget, or mListener before startup has completed, so a datagram arriving during the early, not-yet-active window was routed through the dispatch and state logic prematurely and could crash the process.

The fix moves the !mStopRequestCalled deferral check to the very top of OnDatagramReceivedInternal, so an early datagram is captured into mPendingEvents and replayed later, and it deletes the now-redundant guard from NotifyDatagramReceived. Because the deferral now happens before any thread dispatch or state inspection, the unsafe early code path is never reached.

Key insight
The single core mistake was placing the mStopRequestCalled readiness guard too late in the pipeline — inside NotifyDatagramReceived rather than at the entry point OnDatagramReceivedInternal — so early datagrams bypassed deferral; the fix relocates that guard to the entry point so premature events are queued before any state-dependent processing runs.

Attack Path

  1. Establish a session A malicious website configures and initiates a WebTransport session against the victim browser, causing a WebTransportSessionProxy to be created.
  2. Race the readiness window The site crafts the session so that datagrams arrive during the interval before mStopRequestCalled is set, i.e. before the proxy is fully active.
  3. Enter the unguarded path The early datagram is handed to OnDatagramReceivedInternal, which (in the vulnerable code) performs thread dispatch and reaches state logic without first checking readiness.
  4. Trigger the fault Processing the datagram against a not-yet-active mState, mTarget, or mListener leads to an invalid operation that crashes the networking process, producing a denial of service.

Impact Assessment

An attacker who controls a website gains the ability to crash the Firefox process, resulting in a denial of service, but obtains no memory disclosure or code execution. The crash occurs in the networking code that handles WebTransport datagrams, and the only precondition is that the victim visits a page which opens a specially crafted WebTransport session that delivers a datagram during the narrow pre-activation window.

Changed Functions

FunctionChangeNotes
if
netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
modified

Files Changed

  • netwerk/protocol/webtransport/WebTransportSessionProxy.cpp

Audit Directions

  • Guard placement in event pipelines
    Verify that readiness or lifecycle guards sit at the true entry point of each event, not after thread dispatch or state validation that assumes the object is already active.
  • Deferral consistency across entry points
    Audit other WebTransportSessionProxy and networking proxy methods that enqueue onto mPendingEvents to ensure every path capable of arriving before mStopRequestCalled defers work uniformly.
  • Pre-activation race windows
    Look for handlers that touch mState, mTarget, or mListener where remote-controlled input can arrive before initialization completes, since such windows invite denial-of-service crashes.
diff --git a/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp b/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
index dd01cc6ff8d..e0a80c25ba1 100644
--- a/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
+++ b/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
@@ -1078,15 +1078,6 @@ void WebTransportSessionProxy::NotifyDatagramReceived(
     MutexAutoLock lock(mMutex);
     MOZ_ASSERT(mTarget->IsOnCurrentThread());
 
-    if (!mStopRequestCalled) {
-      CopyableTArray<uint8_t> copied(aData);
-      mPendingEvents.AppendElement(
-          [self = RefPtr{this}, data = std::move(copied)]() mutable {
-            self->NotifyDatagramReceived(std::move(data));
-          });
-      return;
-    }
-
     if (mState != WebTransportSessionProxyState::ACTIVE || !mListener) {
       return;
     }
@@ -1102,6 +1093,15 @@ NS_IMETHODIMP WebTransportSessionProxy::OnDatagramReceivedInternal(
 
   {
     MutexAutoLock lock(mMutex);
+    if (!mStopRequestCalled) {
+      CopyableTArray<uint8_t> copied(aData);
+      mPendingEvents.AppendElement(
+          [self = RefPtr{this}, data = std::move(copied)]() mutable {
+            self->OnDatagramReceivedInternal(std::move(data));
+          });
+      return NS_OK;
+    }
+
     if (!mTarget->IsOnCurrentThread()) {
       return mTarget->Dispatch(NS_NewRunnableFunction(
           "WebTransportSessionProxy::OnDatagramReceived",
Loading diff…