VYPR
Moderate severityNVD Advisory· Published Sep 25, 2020· Updated Aug 4, 2024

Denial of Service in Tensorflow

CVE-2020-15194

Description

In Tensorflow before versions 1.15.4, 2.0.3, 2.1.2, 2.2.1 and 2.3.1, the SparseFillEmptyRowsGrad implementation has incomplete validation of the shapes of its arguments. Although reverse_index_map_t and grad_values_t are accessed in a similar pattern, only reverse_index_map_t is validated to be of proper shape. Hence, malicious users can pass a bad grad_values_t to trigger an assertion failure in vec, causing denial of service in serving installations. The issue is patched in commit 390611e0d45c5793c7066110af37c8514e6a6c54, and is released in TensorFlow versions 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1."

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
tensorflowPyPI
< 1.15.41.15.4
tensorflowPyPI
>= 2.0.0, < 2.0.32.0.3
tensorflowPyPI
>= 2.1.0, < 2.1.22.1.2
tensorflowPyPI
>= 2.2.0, < 2.2.12.2.1
tensorflowPyPI
>= 2.3.0, < 2.3.12.3.1
tensorflow-cpuPyPI
< 1.15.41.15.4
tensorflow-cpuPyPI
>= 2.0.0, < 2.0.32.0.3
tensorflow-cpuPyPI
>= 2.1.0, < 2.1.22.1.2
tensorflow-cpuPyPI
>= 2.2.0, < 2.2.12.2.1
tensorflow-cpuPyPI
>= 2.3.0, < 2.3.12.3.1
tensorflow-gpuPyPI
< 1.15.41.15.4
tensorflow-gpuPyPI
>= 2.0.0, < 2.0.32.0.3
tensorflow-gpuPyPI
>= 2.1.0, < 2.1.22.1.2
tensorflow-gpuPyPI
>= 2.2.0, < 2.2.12.2.1
tensorflow-gpuPyPI
>= 2.3.0, < 2.3.12.3.1

Affected products

1

Patches

1
390611e0d45c

Fix heap buffer overflow in `tf.raw_ops.SparseFillEmptyRowsGrad`.

https://github.com/tensorflow/tensorflowMihai MaruseacSep 19, 2020via ghsa
2 files changed · +64 2
  • tensorflow/core/kernels/sparse_fill_empty_rows_op.cc+10 2 modified
    @@ -236,6 +236,9 @@ class SparseFillEmptyRowsGradOp : public OpKernel {
             context, TensorShapeUtils::IsVector(reverse_index_map_t->shape()),
             errors::InvalidArgument("reverse_index_map must be a vector, saw: ",
                                     reverse_index_map_t->shape().DebugString()));
    +    OP_REQUIRES(context, TensorShapeUtils::IsVector(grad_values_t->shape()),
    +                errors::InvalidArgument("grad_values must be a vector, saw: ",
    +                                        grad_values_t->shape().DebugString()));
     
         const auto reverse_index_map = reverse_index_map_t->vec<int64>();
         const auto grad_values = grad_values_t->vec<T>();
    @@ -264,8 +267,13 @@ class SparseFillEmptyRowsGradOp : public OpKernel {
           // Locate the index of the output of the forward prop associated
           // with this location in the input of the forward prop.  Copy
           // the gradient into it.  Mark it as visited.
    -      d_values(i) = grad_values(reverse_index_map(i));
    -      visited(reverse_index_map(i)) = true;
    +      int64 reverse_index = reverse_index_map(i);
    +      OP_REQUIRES(
    +          context, 0 <= reverse_index && reverse_index < N_full,
    +          errors::InvalidArgument("Elements in reverse index must be in [0, ",
    +                                  N_full, ") but got ", reverse_index));
    +      d_values(i) = grad_values(reverse_index);
    +      visited(reverse_index) = true;
         }
         for (int j = 0; j < N_full; ++j) {
           // The default value gradient gets the accumulated remainder of
    
  • tensorflow/python/ops/sparse_ops_test.py+54 0 modified
    @@ -21,6 +21,7 @@
     from absl.testing import parameterized
     import numpy as np
     
    +from tensorflow.python.eager import context
     from tensorflow.python.framework import constant_op
     from tensorflow.python.framework import dtypes
     from tensorflow.python.framework import errors
    @@ -30,6 +31,7 @@
     # Need array_grad to register gradient for Identity.
     from tensorflow.python.ops import array_grad  # pylint: disable=unused-import
     from tensorflow.python.ops import array_ops
    +from tensorflow.python.ops import gen_sparse_ops
     from tensorflow.python.ops import gradient_checker_v2 as gradient_checker
     from tensorflow.python.ops import math_ops
     # Need sparse_grad to register gradient for SparseToDense.
    @@ -234,5 +236,57 @@ def testConstantStringToSparse(self):
         self.assertAllEqual([5], result.dense_shape)
     
     
    +@test_util.run_all_in_graph_and_eager_modes
    +class RawOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase):
    +
    +  def testSparseFillEmptyRowsGrad(self):
    +    reverse_index_map = [2, 1]
    +    grad_values = [0, 1, 2, 3]
    +    d_values, d_default_value = self.evaluate(
    +        gen_sparse_ops.SparseFillEmptyRowsGrad(
    +            reverse_index_map=reverse_index_map, grad_values=grad_values))
    +    self.assertAllEqual([2, 1], d_values)
    +    self.assertEqual(3, d_default_value)
    +
    +  def testSparseFillEmptyRowsGradNegativeIndexMapValue(self):
    +    reverse_index_map = [2, -1]
    +    grad_values = [0, 1, 2, 3]
    +    with self.assertRaisesRegex(
    +        errors.InvalidArgumentError,
    +        r'Elements in reverse index must be in \[0, 4\)'):
    +      self.evaluate(
    +          gen_sparse_ops.SparseFillEmptyRowsGrad(
    +              reverse_index_map=reverse_index_map, grad_values=grad_values))
    +
    +  def testSparseFillEmptyRowsGradLargeIndexMapValue(self):
    +    reverse_index_map = [2, 10]
    +    grad_values = [0, 1, 2, 3]
    +    with self.assertRaisesRegex(
    +        errors.InvalidArgumentError,
    +        r'Elements in reverse index must be in \[0, 4\)'):
    +      self.evaluate(
    +          gen_sparse_ops.SparseFillEmptyRowsGrad(
    +              reverse_index_map=reverse_index_map, grad_values=grad_values))
    +
    +  def testSparseFillEmptyRowsGradMatrix(self):
    +    reverse_index_map = [0, 1]
    +    grad_values = [[0, 1], [2, 3]]
    +    # Note: Eager mode and graph mode throw different errors here. Graph mode
    +    # will fail with a ValueError from the shape checking logic, while Eager
    +    # will fail with an InvalidArgumentError from the kernel itself.
    +    if context.executing_eagerly():
    +      with self.assertRaisesRegex(errors.InvalidArgumentError,
    +                                  r'grad_values must be a vector'):
    +        self.evaluate(
    +            gen_sparse_ops.SparseFillEmptyRowsGrad(
    +                reverse_index_map=reverse_index_map, grad_values=grad_values))
    +    else:
    +      with self.assertRaisesRegex(ValueError,
    +                                  r'Shape must be rank 1 but is rank 2'):
    +        self.evaluate(
    +            gen_sparse_ops.SparseFillEmptyRowsGrad(
    +                reverse_index_map=reverse_index_map, grad_values=grad_values))
    +
    +
     if __name__ == '__main__':
       googletest.main()
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.