High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the WebRTC component
ComponentDOM
Bug ClassUAF
Tracker2021769
Fix commit66beba63ca35 (firefox) +36/-122
CISA KEVNot listed
CreditedNan Wang
Disclosed2026-04-21

Changed Functions

FunctionChangeNotes
mOwner
dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp
modified

Files Changed

  • dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp
  • dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h
  • dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
  • dom/media/webrtc/jsapi/RTCEncodedFrameBase.h
  • dom/media/webrtc/jsapi/RTCEncodedVideoFrame.cpp
  • dom/media/webrtc/jsapi/RTCEncodedVideoFrame.h
diff --git a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp
index 5dd474ce6db..d65ef46375e 100644
--- a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp
+++ b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp
@@ -14,7 +14,6 @@
 #include "js/RootingAPI.h"
 #include "jsapi/RTCEncodedFrameBase.h"
 #include "jsapi/RTCRtpScriptTransform.h"
-#include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/RTCEncodedAudioFrameBinding.h"
 #include "mozilla/dom/RTCRtpScriptTransformer.h"
@@ -22,42 +21,20 @@
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/fallible.h"
 #include "nsContentUtils.h"
-#include "nsCycleCollectionParticipant.h"
 #include "nsIGlobalObject.h"
 #include "nsISupports.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla::dom {
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(RTCEncodedAudioFrame)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(RTCEncodedAudioFrame,
-                                                RTCEncodedFrameBase)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(RTCEncodedAudioFrame,
-                                                  RTCEncodedFrameBase)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(RTCEncodedAudioFrame,
-                                               RTCEncodedFrameBase)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-NS_IMPL_ADDREF_INHERITED(RTCEncodedAudioFrame, RTCEncodedFrameBase)
-NS_IMPL_RELEASE_INHERITED(RTCEncodedAudioFrame, RTCEncodedFrameBase)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCEncodedAudioFrame)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-NS_INTERFACE_MAP_END_INHERITING(RTCEncodedFrameBase)
-
 RTCEncodedAudioFrame::RTCEncodedAudioFrame(
     nsIGlobalObject* aGlobal,
     std::unique_ptr<webrtc::TransformableFrameInterface> aFrame,
     uint64_t aCounter, RTCRtpScriptTransformer* aOwner)
     : RTCEncodedAudioFrameData{RTCEncodedFrameState{std::move(aFrame), aCounter,
                                                     /*timestamp*/ 0}},
-      RTCEncodedFrameBase(aGlobal, static_cast<RTCEncodedFrameState&>(*this)),
-      mOwner(aOwner) {
+      RTCEncodedFrameBase(aGlobal, static_cast<RTCEncodedFrameState&>(*this),
+                          aOwner) {
   mMetadata.mSynchronizationSource.Construct(mFrame->GetSsrc());
   mMetadata.mPayloadType.Construct(mFrame->GetPayloadType());
   const auto& audioFrame(
@@ -69,10 +46,6 @@ RTCEncodedAudioFrame::RTCEncodedAudioFrame(
   if (const auto optionalSeqNum = audioFrame.SequenceNumber()) {
     mMetadata.mSequenceNumber.Construct(*optionalSeqNum);
   }
-
-  // Base class needs this, but can't do it itself because of an assertion in
-  // the cycle-collector.
-  mozilla::HoldJSObjects(this);
 }
 
 RTCEncodedAudioFrame::RTCEncodedAudioFrame(nsIGlobalObject* aGlobal,
@@ -81,21 +54,8 @@ RTCEncodedAudioFrame::RTCEncodedAudioFrame(nsIGlobalObject* aGlobal,
                                                     aData.mCounter,
                                                     aData.mTimestamp},
                                std::move(aData.mMetadata)},
-      RTCEncodedFrameBase(aGlobal, static_cast<RTCEncodedFrameState&>(*this)),
-      mOwner(nullptr) {
-  // Base class needs this, but can't do it itself because of an assertion in
-  // the cycle-collector.
-  mozilla::HoldJSObjects(this);
-}
-
-RTCEncodedAudioFrame::~RTCEncodedAudioFrame() {
-  // Clear JS::Heap<> members before unregistering as a script holder,
-  // so their destructors don't barrier against a finalized JS object.
-  mData = nullptr;  // from RTCEncodedFrameBase (protected)
-  // Base class needs this, but can't do it itself because of an assertion in
-  // the cycle-collector.
-  mozilla::DropJSObjects(this);
-}
+      RTCEncodedFrameBase(aGlobal, static_cast<RTCEncodedFrameState&>(*this),
+                          nullptr) {}
 
 JSObject* RTCEncodedAudioFrame::WrapObject(JSContext* aCx,
                                            JS::Handle<JSObject*> aGivenProto) {
@@ -137,10 +97,6 @@ RTCEncodedAudioFrameData RTCEncodedAudioFrameData::Clone() const {
       RTCEncodedAudioFrameMetadata(mMetadata)};
 }
 
-nsIGlobalObject* RTCEncodedAudioFrame::GetParentObject() const {
-  return mGlobal;
-}
-
 void RTCEncodedAudioFrame::GetMetadata(
     RTCEncodedAudioFrameMetadata& aMetadata) const {
   aMetadata = mMetadata;
diff --git a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h
index 4c1f794ccef..001ce00a7d8 100644
--- a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h
+++ b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h
@@ -5,7 +5,6 @@
 #ifndef MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCENCODEDAUDIOFRAME_H_
 #define MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCENCODEDAUDIOFRAME_H_
 
-#include "mozilla/RefPtr.h"
 #include "mozilla/dom/RTCEncodedAudioFrameBinding.h"
 #include "mozilla/dom/RTCEncodedFrameBase.h"
 #include "nsIGlobalObject.h"
@@ -36,11 +35,6 @@ class RTCEncodedAudioFrame final : public RTCEncodedAudioFrameData,
   explicit RTCEncodedAudioFrame(nsIGlobalObject* aGlobal,
                                 RTCEncodedAudioFrameData&& aData);
 
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(RTCEncodedAudioFrame,
-                                                         RTCEncodedFrameBase)
-
   // webidl (timestamp and data accessors live in base class)
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
@@ -49,8 +43,6 @@ class RTCEncodedAudioFrame final : public RTCEncodedAudioFrameData,
       const GlobalObject& aGlobal, const RTCEncodedAudioFrame& aOriginalFrame,
       const RTCEncodedAudioFrameOptions& aOptions, ErrorResult& aRv);
 
-  nsIGlobalObject* GetParentObject() const;
-
   void GetMetadata(RTCEncodedAudioFrameMetadata& aMetadata) const;
 
   bool CheckOwner(RTCRtpScriptTransformer* aOwner) const override;
@@ -64,7 +56,7 @@ class RTCEncodedAudioFrame final : public RTCEncodedAudioFrameData,
                             StructuredCloneHolder* aHolder) const;
 
  private:
-  virtual ~RTCEncodedAudioFrame();
+  virtual ~RTCEncodedAudioFrame() = default;
 
   // forbid copy/move to keep mState member in base valid
   RTCEncodedAudioFrame(const RTCEncodedAudioFrame&) = delete;
@@ -76,8 +68,6 @@ class RTCEncodedAudioFrame final : public RTCEncodedAudioFrameData,
   void AssertIsOnOwningThread() const {
     NS_ASSERT_OWNINGTHREAD(RTCEncodedAudioFrame);
   }
-
-  RefPtr<RTCRtpScriptTransformer> mOwner;
 };
 
 }  // namespace mozilla::dom
diff --git a/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp b/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
index 6c1e0dd0bc5..455c26e3be1 100644
--- a/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
+++ b/dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp
@@ -7,6 +7,7 @@
 #include "api/frame_transformer_interface.h"
 #include "js/ArrayBuffer.h"
 #include "js/GCAPI.h"
+#include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsIGlobalObject.h"
 
@@ -16,32 +17,38 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(RTCEncodedFrameBase)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RTCEncodedFrameBase)
   using ::ImplCycleCollectionUnlink;
   tmp->DetachData();
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner, mGlobal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RTCEncodedFrameBase)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner, mGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(RTCEncodedFrameBase)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBERS(mData)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(RTCEncodedFrameBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(RTCEncodedFrameBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCEncodedFrameBase)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 RTCEncodedFrameBase::RTCEncodedFrameBase(nsIGlobalObject* aGlobal,
-                                         RTCEncodedFrameState& aState)
-    : mGlobal(aGlobal), mState(aState), mData(nullptr) {
+                                         RTCEncodedFrameState& aState,
+                                         RTCRtpScriptTransformer* aOwner)
+    : mGlobal(aGlobal), mOwner(aOwner), mState(aState), mData(nullptr) {
   mState.mTimestamp = mState.mFrame->GetTimestamp();
   AutoJSAPI jsapi;
Loading diff…