CVE-2021-29527: Divide By Zero (CWE-369)
value: TensorFlow is an end-to-end open source platform for machine learning. An attacker can trigger a division by 0 in `tf.raw_ops.QuantizedConv2D`. This is because the implementation(https://github.com/tensorflow/tensorflow/blob/00e9a4d67d76703fa1aee33dac582acf317e0e81/tensorflow/core/kernels/quantized_conv_ops.cc#L257-L259) does a division by a quantity that is controlled by the caller. 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/quantized_conv_ops.cc
Commit date: 2021-04-19 19:10:26 -0700
Commit message: Fix one FPE and remove two CHECK-fails.

PiperOrigin-RevId: 369349640
Change-Id: I1fedbfc2b5bab635c5cb51f103d7c9176f79831a

Diff: diff --git a/tensorflow/core/kernels/quantized_conv_ops.cc b/tensorflow/core/kernels/quantized_conv_ops.cc
index a4d36cca3e40..a339de8cfc8f 100644
--- a/tensorflow/core/kernels/quantized_conv_ops.cc
+++ b/tensorflow/core/kernels/quantized_conv_ops.cc
@@ -16,10 +16,12 @@ limitations under the License.
 // Implements quantized eight-bit versions of the convolution operations.
 
 #include <algorithm>
 #include <vector>
 
+#include "tensorflow/core/platform/errors.h"
+
 #define EIGEN_USE_THREADS
 
 #define GEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK
 #include "public/gemmlowp.h"
 #include "tensorflow/core/framework/kernel_shape_util.h"
@@ -225,12 +227,16 @@ class Im2ColConvFunctor {
                    stride, padding, output_data, output_height, output_width,
                    output_shift, output_offset, output_mult);
       return;
     }
 
-    CHECK_GT(output_width, 0);
-    CHECK_GT(output_height, 0);
+    OP_REQUIRES(
+        context, output_width > 0,
+        errors::InvalidArgument("output_width must be strictly positive"));
+    OP_REQUIRES(
+        context, output_height > 0,
+        errors::InvalidArgument("output_height must be strictly positive"));
     int filter_left_offset;
     int filter_top_offset;
     if (padding == VALID) {
       filter_left_offset =
           ((output_width - 1) * stride + filter_width - input_width + 1) / 2;
@@ -253,10 +259,13 @@ class Im2ColConvFunctor {
     // Each patch row contains a filter_width x filter_height patch of the
     // input, with the depth channel as the most contiguous in memory, followed
     // by the width, then the height. This is the standard memory order in the
     // image world if it helps to visualize it.
     const int filter_value_count = filter_width * filter_height * input_depth;
+    OP_REQUIRES(context, filter_value_count > 0,
+                errors::InvalidArgument(
+                    "filter patch must contain at least one element"));
     const int64 patches_per_chunk =
         kMaxChunkSize / (filter_value_count * sizeof(T1));
     const int64 chunk_value_count =
         (kMaxChunkSize + (sizeof(T1) - 1)) / sizeof(T1);
     // TODO(petewarden) - Memory allocation can be very slow on Android. Can we

Vulnerable code:     CHECK_GT(output_width, 0);
    CHECK_GT(output_height, 0);
Fixed code: #include "tensorflow/core/platform/errors.h"

    OP_REQUIRES(
        context, output_width > 0,
        errors::InvalidArgument("output_width must be strictly positive"));
    OP_REQUIRES(
        context, output_height > 0,
        errors::InvalidArgument("output_height must be strictly positive"));
    OP_REQUIRES(context, filter_value_count > 0,
                errors::InvalidArgument(
                    "filter patch must contain at least one element"));