CVE-2021-37675: Divide By Zero (CWE-369)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions most implementations of convolution operators in TensorFlow are affected by a division by 0 vulnerability where an attacker can trigger a denial of service via a crash. The shape inference [implementation](https://github.com/tensorflow/tensorflow/blob/460e000de3a83278fb00b61a16d161b1964f15f4/tensorflow/core/framework/common_shape_fns.cc#L577) is missing several validations before doing divisions and modulo operations. We have patched the issue in GitHub commit 8a793b5d7f59e37ac7f3cd0954a750a2fe76bad4. 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-12T22:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/framework/common_shape_fns.cc
Commit date: 2021-07-29 18:33:51 -0700
Commit message: Prevent division by 0 in common shape functions.

PiperOrigin-RevId: 387712197
Change-Id: Id25c7460e35b68aeeeac23b9a88e455b443ee149

Diff: diff --git a/tensorflow/core/framework/common_shape_fns.cc b/tensorflow/core/framework/common_shape_fns.cc
index e578e2016b874..4806d70a1d337 100644
--- a/tensorflow/core/framework/common_shape_fns.cc
+++ b/tensorflow/core/framework/common_shape_fns.cc
@@ -670,19 +670,23 @@ Status Conv2DShapeImpl(shape_inference::InferenceContext* c,
   // Check that the input tensor and the filter tensor agree on the channel
   // count.
   if (c->ValueKnown(input_depth_dim) && c->ValueKnown(filter_input_depth_dim)) {
     int64_t input_depth_value = c->Value(input_depth_dim),
             filter_input_depth_value = c->Value(filter_input_depth_dim);
+    if (filter_input_depth_value == 0)
+      return errors::InvalidArgument("Depth of filter must not be 0");
     if (input_depth_value % filter_input_depth_value != 0)
       return errors::InvalidArgument(
           "Depth of input (", input_depth_value,
           ") is not a multiple of input depth of filter (",
           filter_input_depth_value, ")");
     if (input_depth_value != filter_input_depth_value) {
       int64_t num_groups = input_depth_value / filter_input_depth_value;
       if (c->ValueKnown(output_depth_dim)) {
         int64_t output_depth_value = c->Value(output_depth_dim);
+        if (num_groups == 0)
+          return errors::InvalidArgument("Number of groups must not be 0");
         if (output_depth_value % num_groups != 0)
           return errors::InvalidArgument(
               "Depth of output (", output_depth_value,
               ") is not a multiple of the number of groups (", num_groups, ")");
       }
@@ -814,19 +818,23 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
   // Check that the input tensor and the filter tensor agree on the channel
   // count.
   if (c->ValueKnown(input_depth_dim) && c->ValueKnown(filter_input_depth_dim)) {
     int64_t input_depth_value = c->Value(input_depth_dim),
             filter_input_depth_value = c->Value(filter_input_depth_dim);
+    if (filter_input_depth_value == 0)
+      return errors::InvalidArgument("Depth of filter must not be 0");
     if (input_depth_value % filter_input_depth_value != 0)
       return errors::InvalidArgument(
           "Depth of input (", input_depth_value,
           ") is not a multiple of input depth of filter (",
           filter_input_depth_value, ")");
     if (input_depth_value != filter_input_depth_value) {
       int64_t num_groups = input_depth_value / filter_input_depth_value;
       if (c->ValueKnown(output_depth_dim)) {
         int64_t output_depth_value = c->Value(output_depth_dim);
+        if (num_groups == 0)
+          return errors::InvalidArgument("Number of groups must not be 0");
         if (output_depth_value % num_groups != 0)
           return errors::InvalidArgument(
               "Depth of output (", output_depth_value,
               ") is not a multiple of the number of groups (", num_groups, ")");
       }
@@ -2454,10 +2462,13 @@ Status SparseReduceShapeFn(InferenceContext* c) {
     auto shape_vec = shape_tensor->flat<int64>();
     auto axes_vec = axes_tensor->flat<int32>();
 
     int64_t ndims = shape_vec.size();
     absl::flat_hash_set<int64> axes;
+    if (ndims == 0)
+      return errors::InvalidArgument(
+          "Number of dims in shape tensor must not be 0");
     for (int i = 0; i < axes_vec.size(); i++) {
       axes.insert((axes_vec(i) + ndims) % ndims);
     }
 
     std::vector<DimensionHandle> dims;

Fixed code:     if (filter_input_depth_value == 0)
      return errors::InvalidArgument("Depth of filter must not be 0");
        if (num_groups == 0)
          return errors::InvalidArgument("Number of groups must not be 0");
    if (filter_input_depth_value == 0)
      return errors::InvalidArgument("Depth of filter must not be 0");
        if (num_groups == 0)
          return errors::InvalidArgument("Number of groups must not be 0");
    if (ndims == 0)
      return errors::InvalidArgument(
          "Number of dims in shape tensor must not be 0");