CVE-2022-35996: Divide By Zero (CWE-369)
value: TensorFlow is an open source platform for machine learning. If `Conv2D` is given empty `input` and the `filter` and `padding` sizes are valid, the output is all-zeros. This causes division-by-zero floating point exceptions that can be used to trigger a denial of service attack. We have patched the issue in GitHub commit 611d80db29dd7b0cfb755772c69d60ae5bca05f9. The fix will be included in TensorFlow 2.10.0. We will also cherrypick this commit on TensorFlow 2.9.1, TensorFlow 2.8.1, and TensorFlow 2.7.2, as these are also affected and still in supported range. There are no known workarounds for this issue.
CWE description: The product divides a value by zero.
CVSS v3 base score: 7.5
Published: 2022-09-16T23:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: Python
Files changed: tensorflow/core/kernels/conv_ops.cc, tensorflow/python/kernel_tests/nn_ops/conv_ops_test.py
Commit date: 2022-07-25 14:38:58 -0700
Commit message: Fix conv2d crash when input size is empty.

If the input is empty (so convolution is only applied to padding), and if
the filter and padding sizes are still valid, then the output will be
all-zeros.  This previously caused a division-by-zero crash in multiple
kernels.

PiperOrigin-RevId: 463179650

Diff: diff --git a/tensorflow/core/kernels/conv_ops.cc b/tensorflow/core/kernels/conv_ops.cc
index 2c2b00d4d8def..64c6a154a6715 100644
--- a/tensorflow/core/kernels/conv_ops.cc
+++ b/tensorflow/core/kernels/conv_ops.cc
@@ -42,10 +42,11 @@ limitations under the License.
 #include "tensorflow/core/framework/tensor_shape.h"
 #include "tensorflow/core/framework/tensor_slice.h"
 #include "tensorflow/core/framework/types.h"
 #include "tensorflow/core/kernels/conv_2d.h"
 #include "tensorflow/core/kernels/deep_conv2d.h"
+#include "tensorflow/core/kernels/fill_functor.h"
 #include "tensorflow/core/kernels/ops_util.h"
 #include "tensorflow/core/lib/core/errors.h"
 #include "tensorflow/core/lib/gtl/array_slice.h"
 #include "tensorflow/core/lib/strings/numbers.h"
 #include "tensorflow/core/lib/strings/str_util.h"
@@ -699,10 +700,19 @@ class Conv2DOp : public BinaryOp<T> {
     // If there is nothing to compute, return.
     if (out_shape.num_elements() == 0) {
       return;
     }
 
+    // If the input is empty, result can only be due to padding.
+    if (input.NumElements() == 0) {
+      // Zero-out output and return.
+      functor::SetZeroFunctor<Device, T>()(context->eigen_device<Device>(),
+                                           output->template flat<T>());
+
+      return;
+    }
+
 #ifdef TENSORFLOW_USE_LIBXSMM_CONVOLUTIONS
     if (params_.padding != EXPLICIT &&
         LaunchXsmmConvOp<Device, T>::Run(
             context, input, filter, dimensions.batch, dimensions.input_rows,
             dimensions.input_cols, dimensions.in_depth, dimensions.filter_rows,
diff --git a/tensorflow/python/kernel_tests/nn_ops/conv_ops_test.py b/tensorflow/python/kernel_tests/nn_ops/conv_ops_test.py
index 907c3c93a2fd5..0527215618f26 100644
--- a/tensorflow/python/kernel_tests/nn_ops/conv_ops_test.py
+++ b/tensorflow/python/kernel_tests/nn_ops/conv_ops_test.py
@@ -757,10 +757,19 @@ class Conv2DTest(test.TestCase):
         filter_in_sizes=[3, 2, 2, 1],
         strides=[1, 1],
         padding=[[2, 1], [1, 2]],
         dilations=[2, 3])
 
+  @test_util.run_in_graph_and_eager_modes()
+  def testConv2dOnlyPaddingReturnsZeros(self):
+    self._VerifyValues(
+        tensor_in_sizes=[1, 0, 2, 1],
+        filter_in_sizes=[1, 1, 1, 1],
+        strides=[1, 1],
+        padding=[[1, 1], [1, 1]],
+        expected=[0, 0, 0, 0, 0, 0, 0, 0])
+
   def testConv2DExplicitPaddingWithLayoutOptimizer(self):
     # Test with Grappler's layout optimizer, to ensure the layout optimizer
     # handles explicit padding correctly.
     self._VerifyExplicitPaddings(
         tensor_in_sizes=[1, 3, 2, 1],

Fixed code: #include "tensorflow/core/kernels/fill_functor.h"
    // If the input is empty, result can only be due to padding.
    if (input.NumElements() == 0) {
      // Zero-out output and return.
      functor::SetZeroFunctor<Device, T>()(context->eigen_device<Device>(),
                                           output->template flat<T>());

      return;
    }

  @test_util.run_in_graph_and_eager_modes()
  def testConv2dOnlyPaddingReturnsZeros(self):
    self._VerifyValues(
        tensor_in_sizes=[1, 0, 2, 1],
        filter_in_sizes=[1, 1, 1, 1],
        strides=[1, 1],
        padding=[[1, 1], [1, 1]],
        expected=[0, 0, 0, 0, 0, 0, 0, 0])