CVE-2022-41896: Improper Validation of Specified Quantity in Input (CWE-1284)
value: TensorFlow is an open source platform for machine learning. If `ThreadUnsafeUnigramCandidateSampler` is given input `filterbank_channel_count` greater than the allowed max size, TensorFlow will crash. We have patched the issue in GitHub commit 39ec7eaf1428e90c37787e5b3fbd68ebd3c48860. The fix will be included in TensorFlow 2.11. We will also cherrypick this commit on TensorFlow 2.10.1, 2.9.3, and TensorFlow 2.8.4, as these are also affected and still in supported range.
CWE description: The product receives input that is expected to specify a quantity (such as size or length), but it does not validate or incorrectly validates that the quantity has the required properties.
CVSS v3 base score: 7.5
Published: 2022-11-18T22:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/mfcc.cc, tensorflow/core/kernels/mfcc_mel_filterbank.cc, tensorflow/core/kernels/mfcc_mel_filterbank_test.cc, tensorflow/core/kernels/mfcc_op.cc
Commit date: 2022-09-29 16:05:58 -0700
Commit message: Make MfccMelFilterbank fail initialization if num_channels is > max int value.

Also initialize MfccDct only if MfccMelFilterbank initialization was successful.

PiperOrigin-RevId: 477844246

Diff: diff --git a/tensorflow/core/kernels/mfcc.cc b/tensorflow/core/kernels/mfcc.cc
index 8c755e0df8754..cb4416f7bd309 100644
--- a/tensorflow/core/kernels/mfcc.cc
+++ b/tensorflow/core/kernels/mfcc.cc
@@ -36,12 +36,14 @@ Mfcc::Mfcc()
 
 bool Mfcc::Initialize(int input_length, double input_sample_rate) {
   bool initialized = mel_filterbank_.Initialize(
       input_length, input_sample_rate, filterbank_channel_count_,
       lower_frequency_limit_, upper_frequency_limit_);
-  initialized &=
-      dct_.Initialize(filterbank_channel_count_, dct_coefficient_count_);
+  if (initialized) {
+    initialized =
+        dct_.Initialize(filterbank_channel_count_, dct_coefficient_count_);
+  }
   initialized_ = initialized;
   return initialized;
 }
 
 void Mfcc::Compute(const std::vector<double>& spectrogram_frame,
diff --git a/tensorflow/core/kernels/mfcc_mel_filterbank.cc b/tensorflow/core/kernels/mfcc_mel_filterbank.cc
index 8eb2d9d8309f5..c5c2d29d37b99 100644
--- a/tensorflow/core/kernels/mfcc_mel_filterbank.cc
+++ b/tensorflow/core/kernels/mfcc_mel_filterbank.cc
@@ -30,10 +30,12 @@ limitations under the License.
 
 #include "tensorflow/core/kernels/mfcc_mel_filterbank.h"
 
 #include <math.h>
 
+#include <limits>
+
 #include "tensorflow/core/platform/logging.h"
 
 namespace tensorflow {
 
 MfccMelFilterbank::MfccMelFilterbank() : initialized_(false) {}
@@ -72,11 +74,21 @@ bool MfccMelFilterbank::Initialize(int input_length, double input_sample_rate,
     return false;
   }
 
   // An extra center frequency is computed at the top to get the upper
   // limit on the high side of the final triangular filter.
-  center_frequencies_.resize(num_channels_ + 1);
+  std::size_t center_frequencies_size = std::size_t(num_channels_) + 1;
+  if (center_frequencies_size >= std::numeric_limits<int>::max() ||
+      center_frequencies_size > center_frequencies_.max_size()) {
+    LOG(ERROR) << "Number of filterbank channels must be less than "
+               << std::numeric_limits<int>::max()
+               << " and less than or equal to "
+               << center_frequencies_.max_size();
+    return false;
+  }
+  center_frequencies_.resize(center_frequencies_size);
+
   const double mel_low = FreqToMel(lower_frequency_limit);
   const double mel_hi = FreqToMel(upper_frequency_limit);
   const double mel_span = mel_hi - mel_low;
   const double mel_spacing = mel_span / static_cast<double>(num_channels_ + 1);
   for (int i = 0; i < num_channels_ + 1; ++i) {
diff --git a/tensorflow/core/kernels/mfcc_mel_filterbank_test.cc b/tensorflow/core/kernels/mfcc_mel_filterbank_test.cc
index 54f31e1699ef1..26b5afed13505 100644
--- a/tensorflow/core/kernels/mfcc_mel_filterbank_test.cc
+++ b/tensorflow/core/kernels/mfcc_mel_filterbank_test.cc
@@ -13,10 +13,11 @@ See the License for the specific language governing permissions and
 limitations under the License.
 ==============================================================================*/
 
 #include "tensorflow/core/kernels/mfcc_mel_filterbank.h"
 
+#include <limits>
 #include <vector>
 
 #include "tensorflow/core/platform/test.h"
 #include "tensorflow/core/platform/types.h"
 
@@ -83,6 +84,39 @@ TEST(MfccMelFilterbankTest, IgnoresExistingContentOfOutputVector) {
   for (const double value : output) {
     EXPECT_EQ(0.0, value);
   }
 }
 
+TEST(MfccMelFilterbankTest, FailsWhenChannelsGreaterThanMaxIntValue) {
+  // Test for bug where vector throws a length_error when it suspects the size
+  // to be more than it's max_size. For now, we fail initialization when the
+  // number of requested channels is >= the maximum value int can take (since
+  // num_channels_ is an int).
+  MfccMelFilterbank filterbank;
+
+  const int kSampleCount = 513;
+  std::size_t num_channels = std::numeric_limits<int>::max();
+  bool initialized = filterbank.Initialize(
+      kSampleCount, 2 /* sample rate */, num_channels /* channels */,
+      1.0 /*  lower frequency limit */, 5.0 /* upper frequency limit */);
+
+  EXPECT_FALSE(initialized);
+}
+
+TEST(MfccMelFilterbankTest, FailsWhenChannelsGreaterThanMaxSize) {
+  // Test for bug where vector throws a length_error when it suspects the size
+  // to be more than it's max_size. For now, we fail initialization when the
+  // number of requested channels is > than std::vector<double>::max_size().
+  MfccMelFilterbank filterbank;
+
+  const int kSampleCount = 513;
+  // Set num_channels to exceed the max_size a double vector can
+  // theoretically take.
+  std::size_t num_channels = std::vector<double>().max_size() + 1;
+  bool initialized = filterbank.Initialize(
+      kSampleCount, 2 /* sample rate */, num_channels /* channels */,
+      1.0 /*  lower frequency limit */, 5.0 /* upper frequency limit */);
+
+  EXPECT_FALSE(initialized);
+}
+
 }  // namespace tensorflow
diff --git a/tensorflow/core/kernels/mfcc_op.cc b/tensorflow/core/kernels/mfcc_op.cc
index 358a420c1606a..2c5f9560aaa31 100644
--- a/tensorflow/core/kernels/mfcc_op.cc
+++ b/tensorflow/core/kernels/mfcc_op.cc
@@ -23,11 +23,11 @@ limitations under the License.
 #include "tensorflow/core/kernels/mfcc.h"
 #include "tensorflow/core/lib/core/status.h"
 
 namespace tensorflow {
 
-// Create a speech fingerpring from spectrogram data.
+// Create a speech fingerprint from spectrogram data.
 class MfccOp : public OpKernel {
  public:
   explicit MfccOp(OpKernelConstruction* context) : OpKernel(context) {
     OP_REQUIRES_OK(context, context->GetAttr("upper_frequency_limit",
                                              &upper_frequency_limit_));
@@ -58,14 +58,16 @@ class MfccOp : public OpKernel {
     Mfcc mfcc;
     mfcc.set_upper_frequency_limit(upper_frequency_limit_);
     mfcc.set_lower_frequency_limit(lower_frequency_limit_);
     mfcc.set_filterbank_channel_count(filterbank_channel_count_);
     mfcc.set_dct_coefficient_count(dct_coefficient_count_);
-    OP_REQUIRES(context, mfcc.Initialize(spectrogram_channels, sample_rate),
-                errors::InvalidArgument(
-                    "Mfcc initialization failed for channel count ",
-                    spectrogram_channels, " and sample rate ", sample_rate));
+    OP_REQUIRES(
+        context, mfcc.Initialize(spectrogram_channels, sample_rate),
+        errors::InvalidArgument("Mfcc initialization failed for channel count ",
+                                spectrogram_channels, ", sample rate ",
+                                sample_rate, " and filterbank_channel_count ",
+                                filterbank_channel_count_));
 
     Tensor* output_tensor = nullptr;
     OP_REQUIRES_OK(context,
                    context->allocate_output(
                        0,

Vulnerable code:   initialized &=
      dct_.Initialize(filterbank_channel_count_, dct_coefficient_count_);
  center_frequencies_.resize(num_channels_ + 1);
// Create a speech fingerpring from spectrogram data.
    OP_REQUIRES(context, mfcc.Initialize(spectrogram_channels, sample_rate),
                errors::InvalidArgument(
                    "Mfcc initialization failed for channel count ",
                    spectrogram_channels, " and sample rate ", sample_rate));
Fixed code:   if (initialized) {
    initialized =
        dct_.Initialize(filterbank_channel_count_, dct_coefficient_count_);
  }
#include <limits>

  std::size_t center_frequencies_size = std::size_t(num_channels_) + 1;
  if (center_frequencies_size >= std::numeric_limits<int>::max() ||
      center_frequencies_size > center_frequencies_.max_size()) {
    LOG(ERROR) << "Number of filterbank channels must be less than "
               << std::numeric_limits<int>::max()
               << " and less than or equal to "
               << center_frequencies_.max_size();
    return false;
  }
  center_frequencies_.resize(center_frequencies_size);

#include <limits>
TEST(MfccMelFilterbankTest, FailsWhenChannelsGreaterThanMaxIntValue) {
  // Test for bug where vector throws a length_error when it suspects the size
  // to be more than it's max_size. For now, we fail initialization when the
  // number of requested channels is >= the maximum value int can take (since
  // num_channels_ is an int).
  MfccMelFilterbank filterbank;

  const int kSampleCount = 513;
  std::size_t num_channels = std::numeric_limits<int>::max();
  bool initialized = filterbank.Initialize(
      kSampleCount, 2 /* sample rate */, num_channels /* channels */,
      1.0 /*  lower frequency limit */, 5.0 /* upper frequency limit */);

  EXPECT_FALSE(initialized);
}

TEST(MfccMelFilterbankTest, FailsWhenChannelsGreaterThanMaxSize) {
  // Test for bug where vector throws a length_error when it suspects the size
  // to be more than it's max_size. For now, we fail initialization when the
  // number of requested channels is > than std::vector<double>::max_size().
  MfccMelFilterbank filterbank;

  const int kSampleCount = 513;
  // Set num_channels to exceed the max_size a double vector can
  // theoretically take.
  std::size_t num_channels = std::vector<double>().max_size() + 1;
  bool initialized = filterbank.Initialize(
      kSampleCount, 2 /* sample rate */, num_channels /* channels */,
      1.0 /*  lower frequency limit */, 5.0 /* upper frequency limit */);

  EXPECT_FALSE(initialized);
}

// Create a speech fingerprint from spectrogram data.
    OP_REQUIRES(
        context, mfcc.Initialize(spectrogram_channels, sample_rate),
        errors::InvalidArgument("Mfcc initialization failed for channel count ",
                                spectrogram_channels, ", sample rate ",
                                sample_rate, " and filterbank_channel_count ",
                                filterbank_channel_count_));