CVE-2022-35960: Reachable Assertion (CWE-617)
value: TensorFlow is an open source platform for machine learning. In `core/kernels/list_kernels.cc's TensorListReserve`, `num_elements` is assumed to be a tensor of size 1. When a `num_elements` of more than 1 element is provided, then `tf.raw_ops.TensorListReserve` fails the `CHECK_EQ` in `CheckIsAlignedAndSingleElement`. We have patched the issue in GitHub commit b5f6fbfba76576202b72119897561e3bd4f179c7. 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 contains an assert() or similar statement that can be triggered by an attacker, which leads to an application exit or other behavior that is more severe than necessary.
CVSS v3 base score: 7.5
Published: 2022-09-16T20:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: Python
Files changed: tensorflow/core/kernels/list_kernels.cc, tensorflow/python/kernel_tests/data_structures/list_ops_test.py
Commit date: 2022-08-09 14:07:09 -0700
Commit message: Re-enable testTensorListReserveWithNonScalarNumElements to work with mlir as well.

PiperOrigin-RevId: 466460987

Diff: diff --git a/tensorflow/core/kernels/list_kernels.cc b/tensorflow/core/kernels/list_kernels.cc
index 9648a43c919ea..72443a594c860 100644
--- a/tensorflow/core/kernels/list_kernels.cc
+++ b/tensorflow/core/kernels/list_kernels.cc
@@ -29,13 +29,15 @@ limitations under the License.
 
 #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
 #include "tensorflow/core/framework/allocator.h"
 #include "tensorflow/core/framework/op_kernel.h"
 #include "tensorflow/core/framework/register_types.h"
+#include "tensorflow/core/framework/tensor_shape.h"
 #include "tensorflow/core/framework/tensor_types.h"
 #include "tensorflow/core/framework/variant.h"
 #include "tensorflow/core/framework/variant_op_registry.h"
+#include "tensorflow/core/platform/errors.h"
 
 namespace tensorflow {
 
 typedef Eigen::ThreadPoolDevice CPUDevice;
 
@@ -320,10 +322,15 @@ class TensorListReserve : public OpKernel {
   }
 
   void Compute(OpKernelContext* c) override {
     PartialTensorShape element_shape;
     OP_REQUIRES_OK(c, TensorShapeFromTensor(c->input(0), &element_shape));
+    OP_REQUIRES(
+        c, TensorShapeUtils::IsScalar(c->input(1).shape()),
+        errors::InvalidArgument(
+            "The num_elements to reserve must be a tensor size 1, but got ",
+            c->input(1).shape()));
     int32_t num_elements = c->input(1).scalar<int32>()();
     OP_REQUIRES(c, num_elements >= 0,
                 errors::InvalidArgument("The num_elements to reserve must be a "
                                         "non negative number, but got ",
                                         num_elements));
diff --git a/tensorflow/python/kernel_tests/data_structures/list_ops_test.py b/tensorflow/python/kernel_tests/data_structures/list_ops_test.py
index 801372dce266c..b4e21c1b1f7e8 100644
--- a/tensorflow/python/kernel_tests/data_structures/list_ops_test.py
+++ b/tensorflow/python/kernel_tests/data_structures/list_ops_test.py
@@ -92,10 +92,20 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase):
     with self.assertRaisesRegex(errors.InvalidArgumentError,
                                 "Trying to pop from an empty list"):
       l = list_ops.tensor_list_pop_back(l, element_dtype=dtypes.float32)
       self.evaluate(l)
 
+  def testTensorListReserveWithNonScalarNumElements(self):
+    # list_kernels.cc in tf/core/kernels raises InvalidArgumentError, and
+    # tf_ops_n_z.cc in tf/compiler/mlir/tf/ir raises UnknownError.
+    with self.assertRaises((errors.InvalidArgumentError, errors.UnknownError)):
+      l = list_ops.tensor_list_reserve(
+          element_dtype=dtypes.float32,
+          element_shape=[2, 3],
+          num_elements=constant_op.constant([1, 1]))
+      self.evaluate(l)
+
   def testPopUninitializedTensorUseListElementShape(self):
     l = list_ops.tensor_list_reserve(
         element_dtype=dtypes.float32, element_shape=[2, 3], num_elements=3)
     _, e = list_ops.tensor_list_pop_back(l, element_dtype=dtypes.float32)
     l = list_ops.tensor_list_stack(l, element_dtype=dtypes.float32)

Fixed code: #include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/platform/errors.h"
    OP_REQUIRES(
        c, TensorShapeUtils::IsScalar(c->input(1).shape()),
        errors::InvalidArgument(
            "The num_elements to reserve must be a tensor size 1, but got ",
            c->input(1).shape()));
  def testTensorListReserveWithNonScalarNumElements(self):
    # list_kernels.cc in tf/core/kernels raises InvalidArgumentError, and
    # tf_ops_n_z.cc in tf/compiler/mlir/tf/ir raises UnknownError.
    with self.assertRaises((errors.InvalidArgumentError, errors.UnknownError)):
      l = list_ops.tensor_list_reserve(
          element_dtype=dtypes.float32,
          element_shape=[2, 3],
          num_elements=constant_op.constant([1, 1]))
      self.evaluate(l)