CVE-2021-37683: Divide By Zero (CWE-369)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions the implementation of division in TFLite is [vulnerable to a division by 0 error](https://github.com/tensorflow/tensorflow/blob/460e000de3a83278fb00b61a16d161b1964f15f4/tensorflow/lite/kernels/div.cc). There is no check that the divisor tensor does not contain zero elements. We have patched the issue in GitHub commit 1e206baedf8bef0334cca3eb92bab134ef525a28. 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 divides a value by zero.
CVSS v3 base score: 5.5
Published: 2021-08-12T23:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/lite/kernels/div.cc
Commit date: 2021-07-16 14:28:13 -0700
Commit message: Prevent a division by 0 in division ops.

PiperOrigin-RevId: 385223169
Change-Id: Ia4228960b5d2aa44480385f74bdd70d21a3613c3

Diff: diff --git a/tensorflow/lite/kernels/div.cc b/tensorflow/lite/kernels/div.cc
index f744b4ba1b7f6..51623a969d1b1 100644
--- a/tensorflow/lite/kernels/div.cc
+++ b/tensorflow/lite/kernels/div.cc
@@ -214,23 +214,38 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
                     GetInputSafe(context, node, kInputTensor2, &input2));
   TfLiteTensor* output;
   TF_LITE_ENSURE_OK(context,
                     GetOutputSafe(context, node, kOutputTensor, &output));
 
-  if (output->type == kTfLiteFloat32 || output->type == kTfLiteInt32) {
+  // TODO(b/193904910): This can written with C++ templates
+#define TF_LITE_CHECK_DIV_NON_ZERO(data_type)                       \
+  const auto* input2_data = GetTensorData<data_type>(input2);       \
+  const size_t input2_elements = input2->bytes / sizeof(data_type); \
+  for (size_t i = 0; i < input2_elements; i++) {                    \
+    TF_LITE_ENSURE(context, input2_data[i] != 0);                   \
+  }
+
+  if (output->type == kTfLiteFloat32) {
+    // Div by zero seems ok in this case, just like in TF case infinities are
+    // returned. So we don't do a check at this point.
+    EvalDiv<kernel_type>(context, node, params, data, input1, input2, output);
+  } else if (output->type == kTfLiteInt32) {
+    TF_LITE_CHECK_DIV_NON_ZERO(int32_t);
     EvalDiv<kernel_type>(context, node, params, data, input1, input2, output);
   } else if (output->type == kTfLiteUInt8) {
+    TF_LITE_CHECK_DIV_NON_ZERO(uint8_t);
     TF_LITE_ENSURE_OK(
         context, EvalQuantized<kernel_type>(context, node, params, data, input1,
                                             input2, output));
   } else {
     context->ReportError(
         context,
         "Div only supports FLOAT32, INT32 and quantized UINT8 now, got %d.",
         output->type);
     return kTfLiteError;
   }
+#undef TF_LITE_CHECK_DIV_NON_ZERO
 
   return kTfLiteOk;
 }
 
 }  // namespace div

Vulnerable code:   if (output->type == kTfLiteFloat32 || output->type == kTfLiteInt32) {
Fixed code:   // TODO(b/193904910): This can written with C++ templates
#define TF_LITE_CHECK_DIV_NON_ZERO(data_type)                       \
  const auto* input2_data = GetTensorData<data_type>(input2);       \
  const size_t input2_elements = input2->bytes / sizeof(data_type); \
  for (size_t i = 0; i < input2_elements; i++) {                    \
    TF_LITE_ENSURE(context, input2_data[i] != 0);                   \
  }

  if (output->type == kTfLiteFloat32) {
    // Div by zero seems ok in this case, just like in TF case infinities are
    // returned. So we don't do a check at this point.
    EvalDiv<kernel_type>(context, node, params, data, input1, input2, output);
  } else if (output->type == kTfLiteInt32) {
    TF_LITE_CHECK_DIV_NON_ZERO(int32_t);
    TF_LITE_CHECK_DIV_NON_ZERO(uint8_t);
#undef TF_LITE_CHECK_DIV_NON_ZERO