High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the Audio/Video component
ComponentDOM
Bug ClassUAF
Tracker2058911
Fix commite2f157dd07f1 (firefox) +40/-4
CISA KEVNot listed
CreditedUkyo Akai
Disclosed2026-09-01

Changed Functions

FunctionChangeNotes
if
dom/media/ipc/RemoteDecoderParent.cpp
modified
if
dom/media/ipc/RemoteMediaDataEncoderParent.cpp
modified
if
dom/media/platforms/apple/AppleVTDecoder.cpp
modified
if
dom/media/platforms/apple/AppleVTEncoder.cpp
modified

Files Changed

  • dom/media/ipc/RemoteDecoderParent.cpp
  • dom/media/ipc/RemoteDecoderParent.h
  • dom/media/ipc/RemoteMediaDataEncoderParent.cpp
  • dom/media/ipc/RemoteMediaDataEncoderParent.h
  • dom/media/platforms/apple/AppleVTDecoder.cpp
  • dom/media/platforms/apple/AppleVTEncoder.cpp
diff --git a/dom/media/ipc/RemoteDecoderParent.cpp b/dom/media/ipc/RemoteDecoderParent.cpp
index fffaa30bb9d..1532405c337 100644
--- a/dom/media/ipc/RemoteDecoderParent.cpp
+++ b/dom/media/ipc/RemoteDecoderParent.cpp
@@ -50,8 +50,12 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvInit(
     return IPC_OK();
   }
 
-  MOZ_DIAGNOSTIC_ASSERT(!mPendingInitResolver,
-                        "overlapping Init in RemoteDecoderParent");
+  if (mInitAttempted) {
+    aResolver(MediaResult(NS_ERROR_ALREADY_INITIALIZED, __func__));
+    return IPC_OK();
+  }
+  mInitAttempted = true;
+
   mPendingInitResolver.emplace(std::move(aResolver));
   RefPtr<RemoteDecoderParent> self = this;
   mInitRequest.DisconnectIfExists();
diff --git a/dom/media/ipc/RemoteDecoderParent.h b/dom/media/ipc/RemoteDecoderParent.h
index 99165bbcc34..30a4c65e0d8 100644
--- a/dom/media/ipc/RemoteDecoderParent.h
+++ b/dom/media/ipc/RemoteDecoderParent.h
@@ -67,6 +67,7 @@ class RemoteDecoderParent : public ShmemRecycleAllocator<RemoteDecoderParent>,
   // Only be used on Windows when the media engine playback is enabled.
   const Maybe<uint64_t> mMediaEngineId;
 
+  bool mInitAttempted = false;
   bool mShutdown = false;
 
   // Pending IPC resolvers and matching request holders for the in-flight
diff --git a/dom/media/ipc/RemoteMediaDataEncoderParent.cpp b/dom/media/ipc/RemoteMediaDataEncoderParent.cpp
index 269ba3b04c2..c4bb5c6df3f 100644
--- a/dom/media/ipc/RemoteMediaDataEncoderParent.cpp
+++ b/dom/media/ipc/RemoteMediaDataEncoderParent.cpp
@@ -81,6 +81,12 @@ IPCResult RemoteMediaDataEncoderParent::RecvInit(InitResolver&& aResolver) {
     return IPC_OK();
   }
 
+  if (mInitAttempted) {
+    aResolver(MediaResult(NS_ERROR_ALREADY_INITIALIZED, __func__));
+    return IPC_OK();
+  }
+  mInitAttempted = true;
+
   mEncoder->Init()->Then(
       GetCurrentSerialEventTarget(), __func__,
       [encoder = RefPtr{mEncoder}, resolver = std::move(aResolver)](
diff --git a/dom/media/ipc/RemoteMediaDataEncoderParent.h b/dom/media/ipc/RemoteMediaDataEncoderParent.h
index 7cad2bed294..49e7c094ef7 100644
--- a/dom/media/ipc/RemoteMediaDataEncoderParent.h
+++ b/dom/media/ipc/RemoteMediaDataEncoderParent.h
@@ -55,6 +55,7 @@ class RemoteMediaDataEncoderParent final
 
   std::map<uint32_t, RefPtr<ShmemRecycleTicket>> mTickets;
   uint32_t mTicketCounter = 0;
+  bool mInitAttempted = false;
   bool mShutdown = false;
 };
 
diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp
index 11906564c22..6ddb554a02c 100644
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -92,6 +92,24 @@ AppleVTDecoder::~AppleVTDecoder() { MOZ_COUNT_DTOR(AppleVTDecoder); }
 
 RefPtr<MediaDataDecoder::InitPromise> AppleVTDecoder::Init() {
   AUTO_PROFILER_LABEL("AppleVTDecoder::Init", MEDIA_PLAYBACK);
+  if (mSession) {
+    MOZ_ASSERT_UNREACHABLE(
+        "Cannot initialize decoder again without shutting down");
+    return InitPromise::CreateAndReject(
+        MediaResult(NS_ERROR_ALREADY_INITIALIZED,
+                    RESULT_DETAIL("Decoder initialization already attempted")),
+        __func__);
+  }
+
+  if (mFormat) {
+    MOZ_ASSERT_UNREACHABLE(
+        "Cannot initialize decoder again after previous initialization failed");
+    return InitPromise::CreateAndReject(
+        MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                    RESULT_DETAIL("Previous decoder initialization failed")),
+        __func__);
+  }
+
   MediaResult rv = InitializeSession();
 
   if (NS_SUCCEEDED(rv)) {
diff --git a/dom/media/platforms/apple/AppleVTEncoder.cpp b/dom/media/platforms/apple/AppleVTEncoder.cpp
index 3359cbaddcf..3cd823a6ecf 100644
--- a/dom/media/platforms/apple/AppleVTEncoder.cpp
+++ b/dom/media/platforms/apple/AppleVTEncoder.cpp
@@ -395,8 +395,14 @@ static Result<OSType, MediaResult> MapPixelFormat(
 }
 
 RefPtr<MediaDataEncoder::InitPromise> AppleVTEncoder::Init() {
-  MOZ_ASSERT(!mSession,
-             "Cannot initialize encoder again without shutting down");
+  if (mSession) {
+    MOZ_ASSERT_UNREACHABLE(
+        "Cannot initialize encoder again without shutting down");
+    return InitPromise::CreateAndReject(
+        MediaResult(NS_ERROR_ALREADY_INITIALIZED,
+                    RESULT_DETAIL("Encoder is already initialized")),
+        __func__);
+  }
 
   MediaResult r = InitSession();
   if (NS_FAILED(r.Code())) {
Loading diff…