Medium firefox Integer Overflow 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionIncorrect boundary conditions, integer overflow in the Audio/Video component
ComponentDOM
Bug ClassInteger Overflow
Tracker2030747
Fix commiteb549a3e8dbd (firefox) +50/-14
CISA KEVNot listed
CreditedAmeen Basha M K
Disclosed2026-05-19

Changed Functions

FunctionChangeNotes
if
dom/media/AudioConverter.cpp
modified
if
dom/media/AudioConverter.h
modified

Files Changed

  • dom/media/AudioConverter.cpp
  • dom/media/AudioConverter.h
diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp
index fbd9b5243f4..bc2c4dbe3b0 100644
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -9,6 +9,8 @@
 
 #include <cmath>
 
+#include "mozilla/CheckedInt.h"
+
 /*
  *  Parts derived from MythTV AudioConvert Class
  *  Created by Jean-Yves Avenard.
@@ -347,8 +349,15 @@ size_t AudioConverter::ResampleAudio(void* aOut, const void* aIn,
   if (!mResampler) {
     return 0;
   }
-  uint32_t outframes = ResampleRecipientFrames(aFrames);
-  uint32_t inframes = aFrames;
+  uint32_t outframes;
+  if (!ResampleRecipientFrames(aFrames, &outframes)) {
+    return 0;
+  }
+  CheckedUint32 inframesChecked(aFrames);
+  if (!inframesChecked.isValid()) {
+    return 0;
+  }
+  uint32_t inframes = inframesChecked.value();
 
   int error;
   if (mOut.Format() == AudioConfig::FORMAT_FLT) {
@@ -371,7 +380,8 @@ size_t AudioConverter::ResampleAudio(void* aOut, const void* aIn,
     mResampler = nullptr;
     return 0;
   }
-  MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
+  MOZ_ASSERT(static_cast<size_t>(inframes) == aFrames,
+             "Some frames will be dropped");
   return outframes;
 }
 
@@ -460,15 +470,27 @@ size_t AudioConverter::UpmixAudio(void* aOut, const void* aIn,
   return aFrames;
 }
 
-size_t AudioConverter::ResampleRecipientFrames(size_t aFrames) const {
+bool AudioConverter::ResampleRecipientFrames(size_t aFrames,
+                                             uint32_t* aOutFrames) const {
   if (!aFrames && mIn.Rate() != mOut.Rate()) {
     if (!mResampler) {
-      return 0;
+      *aOutFrames = 0;
+      return true;
     }
     // We drain by pushing in get_input_latency() samples of 0
     aFrames = speex_resampler_get_input_latency(mResampler);
   }
-  return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
+  CheckedInt<uint64_t> numerator = CheckedInt<uint64_t>(aFrames) * mOut.Rate();
+  if (!numerator.isValid()) {
+    return false;
+  }
+  CheckedUint32 outFrames(numerator.value() / mIn.Rate());
+  outFrames += 1u;
+  if (!outFrames.isValid()) {
+    return false;
+  }
+  *aOutFrames = outFrames.value();
+  return true;
 }
 
 size_t AudioConverter::FramesOutToSamples(size_t aFrames) const {
diff --git a/dom/media/AudioConverter.h b/dom/media/AudioConverter.h
index 8244ee250e9..3be9f457898 100644
--- a/dom/media/AudioConverter.h
+++ b/dom/media/AudioConverter.h
@@ -6,6 +6,7 @@
 #define AudioConverter_h
 
 #include "MediaInfo.h"
+#include "mozilla/CheckedInt.h"
 
 // Forward declaration
 typedef struct SpeexResamplerState_ SpeexResamplerState;
@@ -161,10 +162,15 @@ class AudioConverter {
     AlignedBuffer<Value>* outputBuffer = &temp1;
     AlignedBuffer<Value> temp2;
     if (!frames || mOut.Rate() > mIn.Rate()) {
+      uint32_t resampledFrames;
       // We are upsampling or about to drain, we can't work in place.
       // Allocate another temporary buffer where the upsampling will occur.
-      if (!temp2.SetLength(
-              FramesOutToSamples(ResampleRecipientFrames(frames)))) {
+      if (!ResampleRecipientFrames(frames, &resampledFrames)) {
+        return AudioDataBuffer<Format, Value>(std::move(temp2));
+      }
+      CheckedInt<size_t> outputSamples =
+          CheckedInt<size_t>(resampledFrames) * mOut.Channels();
+      if (!outputSamples.isValid() || !temp2.SetLength(outputSamples.value())) {
         return AudioDataBuffer<Format, Value>(std::move(temp2));
       }
       outputBuffer = &temp2;
@@ -210,11 +216,19 @@ class AudioConverter {
       return frames;
     }
     // Prepare output in cases of drain or up-sampling
-    if ((!frames || mOut.Rate() > mIn.Rate()) &&
-        !aOutBuffer.SetLength(
-            FramesOutToSamples(ResampleRecipientFrames(frames)))) {
-      MOZ_ALWAYS_TRUE(aOutBuffer.SetLength(0));
-      return 0;
+    if (!frames || mOut.Rate() > mIn.Rate()) {
+      uint32_t resampledFrames;
+      if (!ResampleRecipientFrames(frames, &resampledFrames)) {
+        MOZ_ALWAYS_TRUE(aOutBuffer.SetLength(0));
+        return 0;
+      }
+      CheckedInt<size_t> outputSamples =
+          CheckedInt<size_t>(resampledFrames) * mOut.Channels();
+      if (!outputSamples.isValid() ||
+          !aOutBuffer.SetLength(outputSamples.value())) {
+        MOZ_ALWAYS_TRUE(aOutBuffer.SetLength(0));
+        return 0;
+      }
     }
     if (!frames) {
       frames = DrainResampler(aOutBuffer.Data());
@@ -264,7 +278,7 @@ class AudioConverter {
   // Resampler context.
   SpeexResamplerState* mResampler;
   size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
-  size_t ResampleRecipientFrames(size_t aFrames) const;
+  bool ResampleRecipientFrames(size_t aFrames, uint32_t* aOutFrames) const;
   void RecreateResampler();
   size_t DrainResampler(void* aOut);
 };
Loading diff…