CVE-2021-37682: Use of Uninitialized Resource (CWE-908)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions all TFLite operations that use quantization can be made to use unitialized values. [For example](https://github.com/tensorflow/tensorflow/blob/460e000de3a83278fb00b61a16d161b1964f15f4/tensorflow/lite/kernels/depthwise_conv.cc#L198-L200). The issue stems from the fact that `quantization.params` is only valid if `quantization.type` is different that `kTfLiteNoQuantization`. However, these checks are missing in large parts of the code. We have patched the issue in GitHub commits 537bc7c723439b9194a358f64d871dd326c18887, 4a91f2069f7145aab6ba2d8cfe41be8a110c18a5 and 8933b8a21280696ab119b63263babdb54c298538. The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected and still in supported range.
CWE description: The product uses or accesses a resource that has not been initialized.
CVSS v3 base score: 7.1
Published: 2021-08-12T23:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/lite/kernels/unidirectional_sequence_lstm.cc
Commit date: 2021-07-16 10:03:12 -0700
Commit message: Fix a null pointer exception caused by branching on uninitialized data.

This is due to not checking that the params for the quantization exists. If there is no quantization, we should not access the `.params` field.

PiperOrigin-RevId: 385168337
Change-Id: I28661e4f12ba1c92cfeae23d22a3fb2df2a2c6a4

Diff: diff --git a/tensorflow/lite/kernels/unidirectional_sequence_lstm.cc b/tensorflow/lite/kernels/unidirectional_sequence_lstm.cc
index 56363f489c248..590a9e95a05a9 100644
--- a/tensorflow/lite/kernels/unidirectional_sequence_lstm.cc
+++ b/tensorflow/lite/kernels/unidirectional_sequence_lstm.cc
@@ -60,12 +60,16 @@ TfLiteStatus PopulateQuantizedLstmParams8x8_16(
   TfLiteTensor* output_tensor;
   TF_LITE_ENSURE_OK(
       context,
       GetOutputSafe(context, node, lstm::full::kOutputTensor, &output_tensor));
 
+  TF_LITE_ENSURE(context,
+                 cell_state->quantization.type != kTfLiteNoQuantization);
   auto* cell_state_params =
       static_cast<TfLiteAffineQuantization*>(cell_state->quantization.params);
+  TF_LITE_ENSURE(context,
+                 output_tensor->quantization.type != kTfLiteNoQuantization);
   auto* proj_params = static_cast<TfLiteAffineQuantization*>(
       output_tensor->quantization.params);
   if (cell_clip > 0.0) {
     integer_lstm_param->quantized_cell_clip = static_cast<int16_t>(std::min(
         std::max(cell_clip / cell_state_params->scale->data[0], -32768.0f),
@@ -158,10 +162,12 @@ TfLiteStatus PopulateQuantizedLstmParams8x8_16(
   for (int i = 0; i < 4; ++i) {
     if (use_layer_norm) {
       TfLiteTensor* intermediate;
       TF_LITE_ENSURE_OK(context,
                         GetIntermediatesSafe(context, node, i, &intermediate));
+      TF_LITE_ENSURE(context,
+                     intermediate->quantization.type != kTfLiteNoQuantization);
       auto* params = static_cast<TfLiteAffineQuantization*>(
           intermediate->quantization.params);
       intermediate_scale.push_back(params->scale->data[0]);
       intermediate_zp.push_back(params->zero_point->data[0]);
     } else {
@@ -172,10 +178,11 @@ TfLiteStatus PopulateQuantizedLstmParams8x8_16(
   }
   // In the absence of projection, hidden becomes otuput and this intermediate
   // is ignored.
   TfLiteTensor* hidden;
   TF_LITE_ENSURE_OK(context, GetIntermediatesSafe(context, node, 4, &hidden));
+  TF_LITE_ENSURE(context, hidden->quantization.type != kTfLiteNoQuantization);
   auto* hidden_params =
       static_cast<TfLiteAffineQuantization*>(hidden->quantization.params);
   intermediate_scale.push_back(hidden_params->scale->data[0]);
   intermediate_zp.push_back(hidden_params->zero_point->data[0]);
 
@@ -758,10 +765,12 @@ TfLiteStatus PopulatePrecomputedZPTimesWeightsWithBias(TfLiteContext* context,
   lstm_eval::IntegerLstmParameter* integer_lstm_params =
       &op_data->integer_lstm_param;
 
   const TfLiteTensor* intermediate =
       &context->tensors[node->intermediates->data[4]];
+  TF_LITE_ENSURE(context,
+                 intermediate->quantization.type != kTfLiteNoQuantization);
   const auto* params =
       static_cast<TfLiteAffineQuantization*>(intermediate->quantization.params);
   const int32_t hidden_zp = params->zero_point->data[0];
 
   // Get bias and perform zero point calculation.

Fixed code:   TF_LITE_ENSURE(context,
                 cell_state->quantization.type != kTfLiteNoQuantization);
  TF_LITE_ENSURE(context,
                 output_tensor->quantization.type != kTfLiteNoQuantization);
      TF_LITE_ENSURE(context,
                     intermediate->quantization.type != kTfLiteNoQuantization);
  TF_LITE_ENSURE(context, hidden->quantization.type != kTfLiteNoQuantization);
  TF_LITE_ENSURE(context,
                 intermediate->quantization.type != kTfLiteNoQuantization);