Vulnerability: Division by 0 in most convolution operators ### Impact
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:

```python
import tensorflow as tf

tf.compat.v1.disable_v2_behavior()
tf.raw_ops.Conv2D(
  input = tf.constant([], shape=[0, 0, 0, 0], dtype=tf.float32),
  filter = tf.constant([], shape=[0, 0, 0, 0], dtype=tf.float32),
  strides = [1, 1, 1, 1],
  padding = "SAME")
```

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.

### Patches
We have patched the issue in GitHub commit [8a793b5d7f59e37ac7f3cd0954a750a2fe76bad4](https://github.com/tensorflow/tensorflow/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.

### For more information
Please consult [our security guide](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md) for more information regarding the security model and how to contact us with issues and questions.

### Attribution
This vulnerability has been reported by Yakun Zhang of Baidu Security.
Vulnerability ID: GHSA-9c8h-2mv3-49ww
CWE: CWE-369
Severity score: 5.5
Project: https://github.com/tensorflow/tensorflow
Published: 2021-08-25
File: tensorflow/core/framework/common_shape_fns.cc
Commit message: Prevent division by 0 in common shape functions.

PiperOrigin-RevId: 387712197
Change-Id: Id25c7460e35b68aeeeac23b9a88e455b443ee149
Commit author: Mihai Maruseac

Vulnerable version (before fix):
 Status Conv2DShapeImpl(shape_inference::InferenceContext* c,   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 (input_depth_value % filter_input_depth_value != 0)       return errors::InvalidArgument(           "Depth of input (", input_depth_value, Status Conv2DShapeImpl(shape_inference::InferenceContext* c,       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 (output_depth_value % num_groups != 0)           return errors::InvalidArgument(               "Depth of output (", output_depth_value, Status Conv3DShape(shape_inference::InferenceContext* c) {   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 (input_depth_value % filter_input_depth_value != 0)       return errors::InvalidArgument(           "Depth of input (", input_depth_value, Status Conv3DShape(shape_inference::InferenceContext* c) {       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 (output_depth_value % num_groups != 0)           return errors::InvalidArgument(               "Depth of output (", output_depth_value, Status SparseReduceShapeFn(InferenceContext* c) {      int64_t ndims = shape_vec.size();     absl::flat_hash_set<int64> axes;     for (int i = 0; i < axes_vec.size(); i++) {       axes.insert((axes_vec(i) + ndims) % ndims);     }

Fixed version (after fix):
 Status Conv2DShapeImpl(shape_inference::InferenceContext* c,   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, Status Conv2DShapeImpl(shape_inference::InferenceContext* c,       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, Status Conv3DShape(shape_inference::InferenceContext* c) {   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, Status Conv3DShape(shape_inference::InferenceContext* c) {       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, Status SparseReduceShapeFn(InferenceContext* c) {      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);     }

Patch:
patch: @@ -672,6 +672,8 @@ Status Conv2DShapeImpl(shape_inference::InferenceContext* c,
   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,
@@ -681,6 +683,8 @@ Status Conv2DShapeImpl(shape_inference::InferenceContext* c,
       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,
@@ -816,6 +820,8 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
   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,
@@ -825,6 +831,8 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
       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,
@@ -2456,6 +2464,9 @@ Status SparseReduceShapeFn(InferenceContext* c) {
 
     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);
     }
path: tensorflow/core/framework/common_shape_fns.cc