Vulnerability: Division by zero in `Conv3D` ### Impact
A malicious user could trigger a division by 0 in `Conv3D` implementation:

```python
import tensorflow as tf

input_tensor = tf.constant([], shape=[0, 0, 0, 0, 0], dtype=tf.float32)
filter_tensor = tf.constant([], shape=[0, 0, 0, 0, 0], dtype=tf.float32)

tf.raw_ops.Conv3D(input=input_tensor, filter=filter_tensor, strides=[1, 56, 56, 56, 1], padding='VALID', data_format='NDHWC', dilations=[1, 1, 1, 23, 1])
```

The [implementation](https://github.com/tensorflow/tensorflow/blob/42033603003965bffac51ae171b51801565e002d/tensorflow/core/kernels/conv_ops_3d.cc#L143-L145) does a modulo operation based on user controlled input:

```cc
  const int64 out_depth = filter.dim_size(4);
  OP_REQUIRES(context, in_depth % filter_depth == 0, ...);
```

Thus, when `filter` has a 0 as the fifth element, this results in a division by 0.

Additionally, if the shape of the two tensors is not valid, an Eigen assertion can be triggered, resulting in a program crash:

```python
import tensorflow as tf

input_tensor = tf.constant([], shape=[2, 2, 2, 2, 0], dtype=tf.float32)
filter_tensor = tf.constant([], shape=[0, 0, 2, 6, 2], dtype=tf.float32)

tf.raw_ops.Conv3D(input=input_tensor, filter=filter_tensor, strides=[1, 56, 39, 34, 1], padding='VALID', data_format='NDHWC', dilations=[1, 1, 1, 1, 1])
```

The shape of the two tensors must follow the constraints specified in the [op description](https://www.tensorflow.org/api_docs/python/tf/raw_ops/Conv3D).

### Patches
We have patched the issue in GitHub commit [799f835a3dfa00a4d852defa29b15841eea9d64f](https://github.com/tensorflow/tensorflow/commit/799f835a3dfa00a4d852defa29b15841eea9d64f).

The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.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 and Ying Wang of Baidu X-Team.
Vulnerability ID: GHSA-772p-x54p-hjrv
CWE: CWE-369
Severity score: 2.5
Project: https://github.com/tensorflow/tensorflow
Published: 2021-05-21
File: tensorflow/core/kernels/conv_ops_3d.cc
Commit message: Fix 2 issues with `Conv3D`.

We have an issue where the dimensions are not matching and this causes Eigen to crash on an assert.

Then, we have an issue where we accidentally do a division by 0.

PiperOrigin-RevId: 369242785
Change-Id: Ie94067b2d41f58699af99ebb5af335ad9defd931
Commit author: Mihai Maruseac

Vulnerable version (before fix):
 struct LaunchConvOp<CPUDevice, T> {                 errors::InvalidArgument("CPU implementation of Conv3D "                                         "currently only supports dilated rates "                                         "of 1."));     functor::CuboidConvolution<CPUDevice, T>()(         context->eigen_device<CPUDevice>(), output->tensor<T, 5>(),         input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1], class Conv3DOp : public BinaryOp<T> {     const int64 filter_depth = filter.dim_size(3);     const int64 out_depth = filter.dim_size(4);      OP_REQUIRES(context, in_depth % filter_depth == 0,                 errors::InvalidArgument(                     "Input depth must be evenly divisible by filter depth: ",

Fixed version (after fix):
 struct LaunchConvOp<CPUDevice, T> {                 errors::InvalidArgument("CPU implementation of Conv3D "                                         "currently only supports dilated rates "                                         "of 1."));     OP_REQUIRES(context, filter.dim_size(3) == input.dim_size(input.dims() - 1),                 errors::InvalidArgument(                     "Number of channels in filter (", filter.dim_size(3),                     ") must match last dimension of input (",                     input.dim_size(input.dims() - 1), ")"));     functor::CuboidConvolution<CPUDevice, T>()(         context->eigen_device<CPUDevice>(), output->tensor<T, 5>(),         input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1], class Conv3DOp : public BinaryOp<T> {     const int64 filter_depth = filter.dim_size(3);     const int64 out_depth = filter.dim_size(4);      OP_REQUIRES(context, filter_depth != 0,                 errors::InvalidArgument("filter_depth must be non-zero"));     OP_REQUIRES(context, in_depth % filter_depth == 0,                 errors::InvalidArgument(                     "Input depth must be evenly divisible by filter depth: ",

Patch:
patch: @@ -69,6 +69,11 @@ struct LaunchConvOp<CPUDevice, T> {
                 errors::InvalidArgument("CPU implementation of Conv3D "
                                         "currently only supports dilated rates "
                                         "of 1."));
+    OP_REQUIRES(context, filter.dim_size(3) == input.dim_size(input.dims() - 1),
+                errors::InvalidArgument(
+                    "Number of channels in filter (", filter.dim_size(3),
+                    ") must match last dimension of input (",
+                    input.dim_size(input.dims() - 1), ")"));
     functor::CuboidConvolution<CPUDevice, T>()(
         context->eigen_device<CPUDevice>(), output->tensor<T, 5>(),
         input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1],
@@ -142,6 +147,8 @@ class Conv3DOp : public BinaryOp<T> {
     const int64 filter_depth = filter.dim_size(3);
     const int64 out_depth = filter.dim_size(4);
 
+    OP_REQUIRES(context, filter_depth != 0,
+                errors::InvalidArgument("filter_depth must be non-zero"));
     OP_REQUIRES(context, in_depth % filter_depth == 0,
                 errors::InvalidArgument(
                     "Input depth must be evenly divisible by filter depth: ",
path: tensorflow/core/kernels/conv_ops_3d.cc