High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the WebRTC: Audio/Video component
ComponentDOM
Bug ClassUAF
Tracker2043188
Fix commit766bdbb6fba0 (firefox) +8/-13
CISA KEVNot listed
Creditedcrixer
Disclosed2026-07-21

Changed Functions

FunctionChangeNotes
if
dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
modified

Files Changed

  • dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
diff --git a/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp b/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
index cd8b8f64713..930d2b2788f 100644
--- a/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
+++ b/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
@@ -19,8 +19,6 @@ namespace mozilla::dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(RTCEncodedFrameBase)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RTCEncodedFrameBase)
-  using ::ImplCycleCollectionUnlink;
-  tmp->DetachData();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner, mGlobal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -53,11 +51,13 @@ RTCEncodedFrameBase::RTCEncodedFrameBase(nsIGlobalObject* aGlobal,
 
   mozilla::HoldJSObjects(this);
 
-  if (mState.mFrame->GetData().data()) {
-    // Avoid a copy
-    mData = JS::NewArrayBufferWithUserOwnedContents(
-        jsapi.cx(), mState.mFrame->GetData().size(),
-        (void*)(mState.mFrame->GetData().data()));
+  const auto& frame = mState.mFrame->GetData();
+  if (frame.data()) {
+    UniquePtr<void, JS::FreePolicy> data(js_pod_arena_malloc<uint8_t>(
+        js::ArrayBufferContentsArena, frame.size()));
+    memcpy(data.get(), frame.data(), frame.size());
+    mData = JS::NewArrayBufferWithContents(jsapi.cx(), frame.size(),
+                                           std::move(data));
   } else {
     mData = JS::NewArrayBuffer(jsapi.cx(), 0);
   }
@@ -70,7 +70,6 @@ RTCEncodedFrameState::RTCEncodedFrameState(
 
 RTCEncodedFrameBase::~RTCEncodedFrameBase() {
   DetachData();
-  mData = nullptr;
   mozilla::DropJSObjects(this);
 }
 
@@ -98,7 +97,6 @@ unsigned long RTCEncodedFrameBase::Timestamp() const {
 }
 
 void RTCEncodedFrameBase::SetData(const ArrayBuffer& aData) {
-  DetachData();
   mData.set(aData.Obj());
   if (mState.mFrame) {
     aData.ProcessData([&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
@@ -122,10 +120,7 @@ RTCEncodedFrameBase::TakeFrame() {
 }
 
 size_t RTCEncodedFrameBase::Size() const {
-  if (!mState.mFrame) {
-    return 0;
-  }
-  return mState.mFrame->GetData().size();
+  return GetArrayBufferByteLength(mData);
 }
 
 RTCEncodedFrameState::~RTCEncodedFrameState() = default;
Loading diff…