High CVSS 8.1 firefox Memory Corruption 🔧 Commit mapped

Overview

High
Severity
8.1
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionMemory safety bugs present in Firefox 136, Thunderbird 136, Firefox ESR 128.8, and Thunderbird 128.8. Some of these bugs showed evidence of memory corruption and we presume that with enough effort some of these could have been exploited to run arbitrary code.
ComponentDOM
Bug ClassMemory Corruption
Tracker1850615
Fix commita3f9af6c4974 (firefox) +158/-98
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedSylvestre Ledru, Paul Bone and the Mozilla Fuzzing Team
Disclosed2025-04-01

Changed Functions

FunctionChangeNotes
if
dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
modified
VAAPIDisplayHolder
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
modified
if
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
modified
if
dom/media/platforms/ffmpeg/VALibWrapper.cpp
modified
MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS
dom/media/platforms/ffmpeg/VALibWrapper.h
modified

Files Changed

  • dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
  • dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
  • dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
  • dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
  • dom/media/platforms/ffmpeg/VALibWrapper.cpp
  • dom/media/platforms/ffmpeg/VALibWrapper.h
  • dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
  • dom/media/platforms/ffmpeg/moz.build
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
index c99b114e279..ab23ca645ff 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -14,6 +14,7 @@
 #ifdef MOZ_WIDGET_GTK
 #  include "mozilla/gfx/gfxVars.h"
 #  include "mozilla/widget/DMABufLibWrapper.h"
+#  include "VALibWrapper.h"
 #endif
 
 #define AV_LOG_INFO 32
@@ -294,33 +295,6 @@ FFmpegLibWrapper::LinkResult FFmpegLibWrapper::Link() {
 #undef AV_FUNC
 #undef AV_FUNC_OPTION
 
-#ifdef MOZ_WIDGET_GTK
-#  define VA_FUNC_OPTION_SILENT(func)                               \
-    if (!((func) = (decltype(func))PR_FindSymbol(mVALib, #func))) { \
-      (func) = (decltype(func))nullptr;                             \
-    }
-
-  // mVALib is optional and may not be present.
-  if (mVALib) {
-    VA_FUNC_OPTION_SILENT(vaExportSurfaceHandle)
-    VA_FUNC_OPTION_SILENT(vaSyncSurface)
-    VA_FUNC_OPTION_SILENT(vaInitialize)
-    VA_FUNC_OPTION_SILENT(vaTerminate)
-  }
-#  undef VA_FUNC_OPTION_SILENT
-
-#  define VAD_FUNC_OPTION_SILENT(func)                                 \
-    if (!((func) = (decltype(func))PR_FindSymbol(mVALibDrm, #func))) { \
-      FFMPEGP_LOG("Couldn't load function " #func);                    \
-    }
-
-  // mVALibDrm is optional and may not be present.
-  if (mVALibDrm) {
-    VAD_FUNC_OPTION_SILENT(vaGetDisplayDRM)
-  }
-#  undef VAD_FUNC_OPTION_SILENT
-#endif
-
   if (avcodec_register_all) {
     avcodec_register_all();
   }
@@ -356,48 +330,10 @@ void FFmpegLibWrapper::Unlink() {
   if (mAVCodecLib) {
     PR_UnloadLibrary(mAVCodecLib);
   }
-#endif
-#ifdef MOZ_WIDGET_GTK
-  if (mVALib) {
-    PR_UnloadLibrary(mVALib);
-  }
-  if (mVALibDrm) {
-    PR_UnloadLibrary(mVALibDrm);
-  }
 #endif
   PodZero(this);
 }
 
-#ifdef MOZ_WIDGET_GTK
-void FFmpegLibWrapper::LinkVAAPILibs() {
-  if (!gfx::gfxVars::CanUseHardwareVideoDecoding() || !XRE_IsRDDProcess()) {
-    return;
-  }
-
-  PRLibSpec lspec;
-  lspec.type = PR_LibSpec_Pathname;
-  const char* libDrm = "libva-drm.so.2";
-  lspec.value.pathname = libDrm;
-  mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-  if (!mVALibDrm) {
-    FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", libDrm);
-    return;
-  }
-
-  const char* lib = "libva.so.2";
-  lspec.value.pathname = lib;
-  mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-  // Don't use libva when it's missing vaExportSurfaceHandle.
-  if (mVALib && !PR_FindSymbol(mVALib, "vaExportSurfaceHandle")) {
-    PR_UnloadLibrary(mVALib);
-    mVALib = nullptr;
-  }
-  if (!mVALib) {
-    FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", lib);
-  }
-}
-#endif
-
 #ifdef MOZ_WIDGET_GTK
 bool FFmpegLibWrapper::IsVAAPIAvailable() {
 #  define VA_FUNC_LOADED(func) ((func) != nullptr)
@@ -413,9 +349,7 @@ bool FFmpegLibWrapper::IsVAAPIAvailable() {
          VA_FUNC_LOADED(av_hwframe_ctx_alloc) && VA_FUNC_LOADED(av_dict_set) &&
          VA_FUNC_LOADED(av_dict_free) && VA_FUNC_LOADED(avcodec_get_name) &&
          VA_FUNC_LOADED(av_get_pix_fmt_string) &&
-         VA_FUNC_LOADED(vaExportSurfaceHandle) &&
-         VA_FUNC_LOADED(vaSyncSurface) && VA_FUNC_LOADED(vaInitialize) &&
-         VA_FUNC_LOADED(vaTerminate) && VA_FUNC_LOADED(vaGetDisplayDRM);
+         VALibWrapper::IsVAAPIAvailable();
 }
 #endif
 
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
index 8571dbe143b..8fbe244f958 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
@@ -43,7 +43,7 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper {
                    UnknownFutureFFMpegVersion, UnknownOlderFFMpegVersion,
                    MissingFFMpegFunction, MissingLibAVFunction));
 
-  // Examine mAVCodecLib, mAVUtilLib and mVALib, and attempt to resolve
+  // Examine mAVCodecLib and mAVUtilLib, and attempt to resolve
   // all symbols.
   // Upon failure, the entire object will be reset and any attached libraries
   // will be unlinked.
@@ -53,9 +53,8 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper {
   void Unlink();
 
 #ifdef MOZ_WIDGET_GTK
-  // Check if mVALib are available and we can use HW decode.
+  // Check if libva and libva-drm are available and we can use HW decode.
   bool IsVAAPIAvailable();
-  void LinkVAAPILibs();
 #endif
 
   // indicate the version of libavcodec linked to.
@@ -179,12 +178,6 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper {
                                         AVBufferRef* src_ctx, int flags);
   const char* (*avcodec_get_name)(int id);
   char* (*av_get_pix_fmt_string)(char* buf, int buf_size, int pix_fmt);
-
-  int (*vaExportSurfaceHandle)(void*, unsigned int, uint32_t, uint32_t, void*);
-  int (*vaSyncSurface)(void*, unsigned int);
-  int (*vaInitialize)(void* dpy, int* major_version, int* minor_version);
-  int (*vaTerminate)(void* dpy);
-  void* (*vaGetDisplayDRM)(int fd);
 #endif
 
   // Only ever used with ffvpx
@@ -193,10 +186,6 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper {
 
   PRLibrary* mAVCodecLib;
   PRLibrary* mAVUtilLib;
-#ifdef MOZ_WIDGET_GTK
-  PRLibrary* mVALib;
-  PRLibrary* mVALibDrm;
-#endif
 };
 
 }  // namespace mozilla
diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
index 189b063cdb8..042218af04f 100644
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
@@ -69,10 +69,6 @@ bool FFmpegRuntimeLinker::Init() {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
-#ifdef MOZ_WIDGET_GTK
-  sLibAV.LinkVAAPILibs();
-#endif
-
   // While going through all possible libs, this status will be updated with a
   // more precise error if possible.
   sLinkStatus = LinkStatus_NOT_FOUND;
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
index ad328580284..cbb4bb43167 100644
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -11,6 +11,7 @@
 #include "ImageContainer.h"
 #include "MP4Decoder.h"
 #include "MediaInfo.h"
+#include "VALibWrapper.h"
 #include "VideoUtils.h"
 #include "VPXDecoder.h"
 #include "mozilla/layers/KnowsCompositor.h"
@@ -250,15 +251,14 @@ class VAAPIDisplayHolder<LIBAV_VER>;
 template <>
 class VAAPIDisplayHolder<LIBAV_VER> {
  public:
-  VAAPIDisplayHolder(FFmpegLibWrapper* aLib, VADisplay aDisplay, int aDRMFd)
-      : mLib(aLib), mDisplay(aDisplay), mDRMFd(aDRMFd) {};
+  VAAPIDisplayHolder(VADisplay aDisplay, int aDRMFd)
+      : mDisplay(aDisplay), mDRMFd(aDRMFd) {};
   ~VAAPIDisplayHolder() {
-    mLib->vaTerminate(mDisplay);
+    VALibWrapper::sFuncs.vaTerminate(mDisplay);
     close(mDRMFd);
   }
 
  private:
-  FFmpegLibWrapper* mLib;
   VADisplay mDisplay;
   int mDRMFd;
 };
@@ -283,17 +283,17 @@ bool FFmpegVideoDecoder<LIBAV_VER>::CreateVAAPIDeviceContext() {
   AVVAAPIDeviceContext* vactx = (AVVAAPIDeviceContext*)hwctx->hwctx;
 
   int drmFd = widget::GetDMABufDevice()->OpenDRMFd();
-  mDisplay = mLib->vaGetDisplayDRM(drmFd);
+  mDisplay = VALibWrapper::sFuncs.vaGetDisplayDRM(drmFd);
   if (!mDisplay) {
     FFMPEG_LOG("  Can't get DRM VA-API display.");
     return false;
   }
 
-  hwctx->user_opaque = new VAAPIDisplayHolder<LIBAV_VER>(mLib, mDisplay, drmFd);
+  hwctx->user_opaque = new VAAPIDisplayHolder<LIBAV_VER>(mDisplay, drmFd);
   hwctx->free = VAAPIDisplayReleaseCallback;
 
   int major, minor;
-  int status = mLib->vaInitialize(mDisplay, &major, &minor);
+  int status = VALibWrapper::sFuncs.vaInitialize(mDisplay, &major, &minor);
   if (status != VA_STATUS_SUCCESS) {
     FFMPEG_LOG("  vaInitialize failed.");
     return false;
@@ -1607,13 +1607,13 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImage(
 bool FFmpegVideoDecoder<LIBAV_VER>::GetVAAPISurfaceDescriptor(
     VADRMPRIMESurfaceDescriptor* aVaDesc) {
   VASurfaceID surface_id = (VASurfaceID)(uintptr_t)mFrame->data[3];
-  VAStatus vas = mLib->vaExportSurfaceHandle(
+  VAStatus vas = VALibWrapper::sFuncs.vaExportSurfaceHandle(
       mDisplay, surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
       VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, aVaDesc);
   if (vas != VA_STATUS_SUCCESS) {
     return false;
   }
-  vas = mLib->vaSyncSurface(mDisplay, surface_id);
+  vas = VALibWrapper::sFuncs.vaSyncSurface(mDisplay, surface_id);
   if (vas != VA_STATUS_SUCCESS) {
     NS_WARNING("vaSyncSurface() failed.");
   }
diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.cpp b/dom/media/platforms/ffmpeg/VALibWrapper.cpp
new file mode 100644
index 00000000000..b3870f2d81a
--- /dev/null
+++ b/dom/media/platforms/ffmpeg/VALibWrapper.cpp
@@ -0,0 +1,90 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VALibWrapper.h"
+
+#include "FFmpegLog.h"
+#include "PlatformDecoderModule.h"
+#include "prlink.h"
+#include "mozilla/gfx/gfxVars.h"
+
+namespace mozilla {
+
+VALibWrapper VALibWrapper::sFuncs;
+
+void VALibWrapper::Link() {
+#define VA_FUNC_OPTION_SILENT(func)                               \
+  if (!((func) = (decltype(func))PR_FindSymbol(mVALib, #func))) { \
+    (func) = (decltype(func))nullptr;                             \
+  }
+
+  // mVALib is optional and may not be present.
+  if (mVALib) {
+    VA_FUNC_OPTION_SILENT(vaExportSurfaceHandle)
+    VA_FUNC_OPTION_SILENT(vaSyncSurface)
+    VA_FUNC_OPTION_SILENT(vaInitialize)
+    VA_FUNC_OPTION_SILENT(vaTerminate)
+  }
+#undef VA_FUNC_OPTION_SILENT
+
+#define VAD_FUNC_OPTION_SILENT(func)                                 \
+  if (!((func) = (decltype(func))PR_FindSymbol(mVALibDrm, #func))) { \
+    FFMPEGP_LOG("Couldn't load function " #func);                    \
+  }
+
+  // mVALibDrm is optional and may not be present.
+  if (mVALibDrm) {
+    VAD_FUNC_OPTION_SILENT(vaGetDisplayDRM)
+  }
+#undef VAD_FUNC_OPTION_SILENT
+}
+
+bool VALibWrapper::LinkVAAPILibs() {
+  if (!gfx::gfxVars::CanUseHardwareVideoDecoding() || !XRE_IsRDDProcess()) {
+    return false;
+  }
+
+  PRLibSpec lspec;
+  lspec.type = PR_LibSpec_Pathname;
+  const char* libDrm = "libva-drm.so.2";
+  lspec.value.pathname = libDrm;
+  mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+  if (!mVALibDrm) {
+    FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", libDrm);
+    return false;
+  }
+
+  const char* lib = "libva.so.2";
+  lspec.value.pathname = lib;
+  mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+  // Don't use libva when it's missing vaExportSurfaceHandle.
+  if (mVALib && !PR_FindSymbol(mVALib, "vaExportSurfaceHandle")) {
+    PR_UnloadLibrary(mVALib);
+    mVALib = nullptr;
+  }
+  if (!mVALib) {
+    FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", lib);
+    return false;
+  }
+
+  Link();
+  return true;
+}
+
+bool VALibWrapper::AreVAAPIFuncsAvailable() {
+#define VA_FUNC_LOADED(func) ((func) != nullptr)
+  return VA_FUNC_LOADED(vaExportSurfaceHandle) &&
+         VA_FUNC_LOADED(vaSyncSurface) && VA_FUNC_LOADED(vaInitialize) &&
+         VA_FUNC_LOADED(vaTerminate) && VA_FUNC_LOADED(vaGetDisplayDRM);
+}
+
+/* static */
+bool VALibWrapper::IsVAAPIAvailable() {
+  static bool once = sFuncs.LinkVAAPILibs();
+  (void)once;
+
+  return sFuncs.AreVAAPIFuncsAvailable();
+}
+
+}  // namespace mozilla
diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.h b/dom/media/platforms/ffmpeg/VALibWrapper.h
new file mode 100644
index 00000000000..20f1c9d74c4
--- /dev/null
+++ b/dom/media/platforms/ffmpeg/VALibWrapper.h
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_
+#define DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Types.h"
+
+struct PRLibrary;
+
+#ifdef MOZ_WIDGET_GTK
+namespace mozilla {
+
+class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS VALibWrapper {
+ public:
+  // The class is used only in static storage and so is zero initialized.
+  VALibWrapper() = default;
+  // The libraries are not unloaded in the destructor, because doing so would
+  // require a static constructor to register the static destructor.  As the
+  // class is in static storage, the destructor would only run on shutdown
+  // anyway.
+  ~VALibWrapper() = default;
+
+  // Check if sVALib and sVALibDrm are available with necessary symbols and
+  // initialize sFuncs;
+  static bool IsVAAPIAvailable();
+  static VALibWrapper sFuncs;
+
+ private:
+  void Link();
+  bool AreVAAPIFuncsAvailable();
+  // Attempt to load libva-drm and libva and resolve necessary symbols.
+  // Upon failure, the entire object will be reset and any attached libraries
+  // will be unlinked.  Do not invoke more than once.
+  bool LinkVAAPILibs();
+
+ public:
+  int (*vaExportSurfaceHandle)(void*, unsigned int, uint32_t, uint32_t, void*);
+  int (*vaSyncSurface)(void*, unsigned int);
+  int (*vaInitialize)(void* dpy, int* major_version, int* minor_version);
+  int (*vaTerminate)(void* dpy);
+  void* (*vaGetDisplayDRM)(int fd);
+
+ private:
+  PRLibrary* mVALib;
+  PRLibrary* mVALibDrm;
+};
+
+}  // namespace mozilla
+#endif  // MOZ_WIDGET_GTK
+
+#endif  // DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_
diff --git a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
index 02bd401596c..a167e641328 100644
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
@@ -78,10 +78,6 @@ bool FFVPXRuntimeLinker::Init() {
 
   sLinkStatus = LinkStatus_FAILED;
... (file diff truncated)
Loading diff…