Firefox · DOM
CVE-2026-117868
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/webtransport/parent/WebTransportParent.cpp |
modified | |
ifnetwerk/protocol/webtransport/WebTransportSessionProxy.cpp |
modified | |
OnDrainingnetwerk/protocol/webtransport/WebTransportSessionProxy.cpp |
modified |
Files Changed
dom/webtransport/parent/WebTransportParent.cppnetwerk/protocol/webtransport/WebTransportSessionProxy.cppnetwerk/protocol/webtransport/WebTransportSessionProxy.h
Patch
diff --git a/dom/webtransport/parent/WebTransportParent.cpp b/dom/webtransport/parent/WebTransportParent.cpp
index e5aaf4961a1..015d50e4edd 100644
--- a/dom/webtransport/parent/WebTransportParent.cpp
+++ b/dom/webtransport/parent/WebTransportParent.cpp
@@ -981,7 +981,9 @@ WebTransportParent::OnOutgoingDatagramOutCome(
}
// This assumes the stack is calling us back synchronously!
- MOZ_ASSERT(mOutgoingDatagramResolver);
+ if (!mOutgoingDatagramResolver) {
+ return NS_OK;
+ }
mOutgoingDatagramResolver(result);
mOutgoingDatagramResolver = nullptr;
@@ -991,7 +993,9 @@ WebTransportParent::OnOutgoingDatagramOutCome(
NS_IMETHODIMP WebTransportParent::OnMaxDatagramSize(uint64_t aSize) {
LOG(("Max datagram size is %" PRIu64, aSize));
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
- MOZ_ASSERT(mMaxDatagramSizeResolver);
+ if (!mMaxDatagramSizeResolver) {
+ return NS_OK;
+ }
mMaxDatagramSizeResolver(aSize);
mMaxDatagramSizeResolver = nullptr;
return NS_OK;
diff --git a/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp b/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
index c356f01ca2f..f73d5167861 100644
--- a/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
+++ b/netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
@@ -1280,26 +1280,41 @@ WebTransportSessionProxy::OnSessionClosed(bool aCleanly, uint32_t aStatus,
return NS_OK;
}
+void WebTransportSessionProxy::OnDrainingInternal() {
+ nsCOMPtr<WebTransportSessionEventListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ if (!mTarget->IsOnCurrentThread()) {
+ // mTarget changed (RetargetTo) after this runnable was queued; forward to
+ // the current target so the listener is only ever invoked on one thread.
+ mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::OnDrainingInternal",
+ [self = RefPtr{this}] { self->OnDrainingInternal(); }));
+ return;
+ }
+ listener = mListener;
+ }
+
+ if (listener) {
+ listener->OnDraining();
+ }
+}
+
NS_IMETHODIMP
WebTransportSessionProxy::OnDraining() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
- MutexAutoLock lock(mMutex);
LOG(("WebTransportSessionProxy::OnDraining %p", this));
- if (!mTarget->IsOnCurrentThread()) {
- nsCOMPtr<WebTransportSessionEventListener> listener = mListener;
- mTarget->Dispatch(NS_NewRunnableFunction(
- "WebTransportSessionProxy::OnDraining", [listener]() {
- if (listener) {
- listener->OnDraining();
- }
- }));
- return NS_OK;
+ {
+ MutexAutoLock lock(mMutex);
+ if (!mTarget->IsOnCurrentThread()) {
+ return mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::OnDraining",
+ [self = RefPtr{this}] { self->OnDrainingInternal(); }));
+ }
}
- if (mListener) {
- mListener->OnDraining();
- }
+ OnDrainingInternal();
return NS_OK;
}
@@ -1314,7 +1329,16 @@ void WebTransportSessionProxy::OnStatsAvailableInternal(
nsCOMPtr<WebTransportSessionEventListener> listener;
{
MutexAutoLock lock(mMutex);
- MOZ_ASSERT(mTarget->IsOnCurrentThread());
+ if (!mTarget->IsOnCurrentThread()) {
+ // mTarget changed (RetargetTo) after this runnable was queued; forward to
+ // the current target so the listener is only ever invoked on one thread.
+ mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::OnStatsAvailableInternal",
+ [self = RefPtr{this}, stats = aStats] {
+ self->OnStatsAvailableInternal(stats);
+ }));
+ return;
+ }
listener = mListener;
}
if (!listener) {
@@ -1352,10 +1376,6 @@ WebTransportSessionProxy::OnStatsAvailable(
{
MutexAutoLock lock(mMutex);
- // RetargetTo() runs synchronously before content can ever reach this
- // point (its promise chain depends on it), so mTarget should already be
- // the socket thread here.
- MOZ_ASSERT(mTarget->IsOnCurrentThread());
// Cache stats for use after connection is closed (spec requirement).
if (rawStats) {
mHasCachedStats = true;
@@ -1499,7 +1519,16 @@ void WebTransportSessionProxy::NotifyDatagramReceived(
nsCOMPtr<WebTransportSessionEventListener> listener;
{
MutexAutoLock lock(mMutex);
- MOZ_ASSERT(mTarget->IsOnCurrentThread());
+ if (!mTarget->IsOnCurrentThread()) {
+ // mTarget changed (RetargetTo) after this runnable was queued; forward to
+ // the current target so the listener is only ever invoked on one thread.
+ mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::NotifyDatagramReceived",
+ [self = RefPtr{this}, data{std::move(aData)}]() mutable {
+ self->NotifyDatagramReceived(std::move(data));
+ }));
+ return;
+ }
if (mState != WebTransportSessionProxyState::ACTIVE || !mListener) {
return;
@@ -1547,8 +1576,6 @@ void WebTransportSessionProxy::OnMaxDatagramSizeInternal(uint64_t aSize) {
nsCOMPtr<WebTransportSessionEventListener> listener;
{
MutexAutoLock lock(mMutex);
- MOZ_ASSERT(mTarget->IsOnCurrentThread());
-
if (!mStopRequestCalled) {
mPendingEvents.AppendElement([self = RefPtr{this}, size(aSize)]() {
self->OnMaxDatagramSizeInternal(size);
@@ -1556,6 +1583,17 @@ void WebTransportSessionProxy::OnMaxDatagramSizeInternal(uint64_t aSize) {
return;
}
+ if (!mTarget->IsOnCurrentThread()) {
+ // mTarget changed (RetargetTo) after this runnable was queued; forward to
+ // the current target so the listener is only ever invoked on one thread.
+ mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::OnMaxDatagramSizeInternal",
+ [self = RefPtr{this}, size(aSize)] {
+ self->OnMaxDatagramSizeInternal(size);
+ }));
+ return;
+ }
+
if (mState != WebTransportSessionProxyState::ACTIVE || !mListener) {
return;
}
@@ -1588,7 +1626,16 @@ void WebTransportSessionProxy::OnOutgoingDatagramOutComeInternal(
nsCOMPtr<WebTransportSessionEventListener> listener;
{
MutexAutoLock lock(mMutex);
- MOZ_ASSERT(mTarget->IsOnCurrentThread());
+ if (!mTarget->IsOnCurrentThread()) {
+ // mTarget changed (RetargetTo) after this runnable was queued; forward to
+ // the current target so the listener is only ever invoked on one thread.
+ mTarget->Dispatch(NS_NewRunnableFunction(
+ "WebTransportSessionProxy::OnOutgoingDatagramOutComeInternal",
+ [self = RefPtr{this}, id(aId), outcome(aOutCome)] {
+ self->OnOutgoingDatagramOutComeInternal(id, outcome);
+ }));
+ return;
+ }
if (mState != WebTransportSessionProxyState::ACTIVE || !mListener) {
return;
}
diff --git a/netwerk/protocol/webtransport/WebTransportSessionProxy.h b/netwerk/protocol/webtransport/WebTransportSessionProxy.h
index 4ca97f8e9c4..852ac0180dc 100644
--- a/netwerk/protocol/webtransport/WebTransportSessionProxy.h
+++ b/netwerk/protocol/webtransport/WebTransportSessionProxy.h
@@ -181,6 +181,7 @@ class WebTransportSessionProxy final
void GetMaxDatagramSizeInternal(
const RefPtr<WebTransportSessionBase>& aSession);
void OnMaxDatagramSizeInternal(uint64_t aSize);
+ void OnDrainingInternal();
void GetStatsInternal(const RefPtr<WebTransportSessionBase>& aSession);
void OnStatsAvailableInternal(
const Maybe<mozilla::dom::WebTransportStatsData>& aStats);
Loading diff…
References
On This Page