CVE-2022-35998: Reachable Assertion (CWE-617)
value: TensorFlow is an open source platform for machine learning. If `EmptyTensorList` receives an input `element_shape` with more than one dimension, it gives a `CHECK` fail that can be used to trigger a denial of service attack. We have patched the issue in GitHub commit c8ba76d48567aed347508e0552a257641931024d. 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-16T23: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-07-19 09:52:26 -0700
Commit message: Fix tf.raw_ops.EmptyTensorList vulnerability with invalid `element_shape`.

Check that given `element_shape` is valid.
Add graph/eager unit tests. Graph mode was already ok but eager mode was not.

PiperOrigin-RevId: 461906461

Diff: diff --git a/tensorflow/core/kernels/list_kernels.cc b/tensorflow/core/kernels/list_kernels.cc
index 7b4465963bd63..a87b95087806b 100644
--- a/tensorflow/core/kernels/list_kernels.cc
+++ b/tensorflow/core/kernels/list_kernels.cc
@@ -19,23 +19,23 @@ limitations under the License.
 #define EIGEN_USE_GPU
 #endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
 
 #include "tensorflow/core/kernels/list_kernels.h"
 
+#include <algorithm>
+#include <iterator>
 #include <limits>
+#include <memory>
+#include <utility>
 
 #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_types.h"
 #include "tensorflow/core/framework/variant.h"
 #include "tensorflow/core/framework/variant_op_registry.h"
-#include "tensorflow/core/kernels/concat_lib.h"
-#include "tensorflow/core/lib/core/coding.h"
-#include "tensorflow/core/lib/core/errors.h"
-#include "tensorflow/core/util/util.h"
 
 namespace tensorflow {
 
 typedef Eigen::ThreadPoolDevice CPUDevice;
 
@@ -47,10 +47,13 @@ Status TensorShapeFromTensor(const Tensor& t, PartialTensorShape* out) {
       return OkStatus();
     }
     return errors::InvalidArgument(
         "The only valid scalar shape tensor is the fully unknown shape "
         "specified as -1.");
+  } else if (t.shape().dims() != 1) {
+    return errors::InvalidArgument("Shape must be at most rank 1 but is rank ",
+                                   t.shape().dims());
   }
   if (t.dtype() == DT_INT32) {
     return PartialTensorShape::MakePartialShape(t.vec<int32>().data(),
                                                 t.NumElements(), out);
   } else if (t.dtype() == DT_INT64) {
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 bc3e2f3c79083..796786aa3061a 100644
--- a/tensorflow/python/kernel_tests/data_structures/list_ops_test.py
+++ b/tensorflow/python/kernel_tests/data_structures/list_ops_test.py
@@ -1456,10 +1456,19 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase):
         r"List contains uninitialized tensor at index 0"
         r" but leading_dims has only 0 elements."):
       t = list_ops.tensor_list_concat(l, element_dtype=dtypes.float32)
       self.evaluate(t)
 
+  def testEmptyTensorListInvalidShape(self):
+    with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
+                                r"Shape must be at most rank 1 but is rank 2"):
+      t = gen_list_ops.EmptyTensorList(
+          element_shape=array_ops.ones(dtype=dtypes.int32, shape=[1, 0]),
+          max_num_elements=constant_op.constant(1),
+          element_dtype=dtypes.int32)
+      self.evaluate(t)
+
   def testEvenSplit(self):
 
     def RunTest(input_tensor, lengths, expected_stacked_output):
       l = list_ops.tensor_list_split(
           input_tensor, element_shape=None, lengths=lengths)

Vulnerable code: #include "tensorflow/core/kernels/concat_lib.h"
#include "tensorflow/core/lib/core/coding.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/util/util.h"
Fixed code: #include <algorithm>
#include <iterator>
#include <memory>
#include <utility>
  } else if (t.shape().dims() != 1) {
    return errors::InvalidArgument("Shape must be at most rank 1 but is rank ",
                                   t.shape().dims());
  def testEmptyTensorListInvalidShape(self):
    with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
                                r"Shape must be at most rank 1 but is rank 2"):
      t = gen_list_ops.EmptyTensorList(
          element_shape=array_ops.ones(dtype=dtypes.int32, shape=[1, 0]),
          max_num_elements=constant_op.constant(1),
          element_dtype=dtypes.int32)
      self.evaluate(t)