CVE-2021-29517: Divide By Zero (CWE-369)
value: TensorFlow is an end-to-end open source platform for machine learning. A malicious user could trigger a division by 0 in `Conv3D` implementation. 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. 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. 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.
CWE description: The product divides a value by zero.
CVSS v3 base score: 5.5
Published: 2021-05-14T20:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/conv_ops_3d.cc
Commit date: 2021-04-19 10:01:00 -0700
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

Diff: diff --git a/tensorflow/core/kernels/conv_ops_3d.cc b/tensorflow/core/kernels/conv_ops_3d.cc
index 56b58b58daa1..505c55c7e6fe 100644
--- a/tensorflow/core/kernels/conv_ops_3d.cc
+++ b/tensorflow/core/kernels/conv_ops_3d.cc
@@ -67,10 +67,15 @@ struct LaunchConvOp<CPUDevice, T> {
     OP_REQUIRES(context,
                 dilations[0] == 1 && dilations[1] == 1 && dilations[2] == 1,
                 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],
         strides[0], BrainPadding2EigenPadding(padding));
   }
@@ -140,10 +145,12 @@ class Conv3DOp : public BinaryOp<T> {
     const int64 in_batch = GetTensorDim(input, data_format_, 'N');
 
     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: ",
                     in_depth, " vs ", filter_depth));
 

Fixed code:     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), ")"));
    OP_REQUIRES(context, filter_depth != 0,
                errors::InvalidArgument("filter_depth must be non-zero"));