CVE-2022-36016: Reachable Assertion (CWE-617)
value: TensorFlow is an open source platform for machine learning. When `tensorflow::full_type::SubstituteFromAttrs` receives a `FullTypeDef& t` that is not exactly three args, it triggers a `CHECK`-fail instead of returning a status. We have patched the issue in GitHub commit 6104f0d4091c260ce9352f9155f7e9b725eab012. 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: C++
Files changed: tensorflow/core/framework/full_type_util.cc, tensorflow/core/framework/full_type_util_test.cc
Commit date: 2022-06-07 08:06:37 -0700
Commit message: Strengthen input verification for SpecializeType by replacing DCHECK with explicit test/status return.

PiperOrigin-RevId: 453436708

Diff: diff --git a/tensorflow/core/framework/full_type_util.cc b/tensorflow/core/framework/full_type_util.cc
index 97e9381df13da..a8636420f11fa 100644
--- a/tensorflow/core/framework/full_type_util.cc
+++ b/tensorflow/core/framework/full_type_util.cc
@@ -173,11 +173,15 @@ Status SubstituteVar(AttrMap& attrs, FullTypeDef& t) {
   t.clear_s();
   return OkStatus();
 }
 
 Status SubstituteForEach(AttrMap& attrs, FullTypeDef& t) {
-  DCHECK_EQ(t.args_size(), 3);
+  if (t.args_size() != 3) {
+    return Status(error::INVALID_ARGUMENT,
+                  absl::StrCat("illegal FOR_EACH type, expected 3 args, got ",
+                               t.args_size()));
+  }
 
   const auto& cont = t.args(0);
   const auto& tmpl = t.args(1);
   const auto& t_var = t.args(2);
 
diff --git a/tensorflow/core/framework/full_type_util_test.cc b/tensorflow/core/framework/full_type_util_test.cc
index 0324e64f96b0f..6037879d069ff 100644
--- a/tensorflow/core/framework/full_type_util_test.cc
+++ b/tensorflow/core/framework/full_type_util_test.cc
@@ -508,10 +508,23 @@ TEST(SpecializeType, ForEachOverridesTargetOfNestedForEach) {
   EXPECT_EQ(t_actual.args(1).args(0).args_size(), 1);
   EXPECT_EQ(t_actual.args(1).args(0).args(0).type_id(), TFT_DOUBLE);
   EXPECT_EQ(t_actual.args(1).args(0).args(0).args_size(), 0);
 }
 
+TEST(SpecializeType, ForEachRejectsMalformedInput) {
+  OpDef op;
+  FullTypeDef* t = op.add_output_arg()->mutable_experimental_full_type();
+  t->set_type_id(TFT_FOR_EACH);
+  t->add_args()->set_type_id(TFT_PRODUCT);
+
+  NodeDef ndef;
+  AttrSlice attrs(ndef);
+
+  FullTypeDef ft;
+  EXPECT_FALSE(SpecializeType(attrs, op, ft).ok());
+}
+
 TEST(SpecializeType, RemovesLegacyVariant) {
   OpDef op;
   FullTypeDef* t = op.add_output_arg()->mutable_experimental_full_type();
   t->set_type_id(TFT_ARRAY);
   t->add_args()->set_type_id(TFT_TENSOR);

Vulnerable code:   DCHECK_EQ(t.args_size(), 3);
Fixed code:   if (t.args_size() != 3) {
    return Status(error::INVALID_ARGUMENT,
                  absl::StrCat("illegal FOR_EACH type, expected 3 args, got ",
                               t.args_size()));
  }
TEST(SpecializeType, ForEachRejectsMalformedInput) {
  OpDef op;
  FullTypeDef* t = op.add_output_arg()->mutable_experimental_full_type();
  t->set_type_id(TFT_FOR_EACH);
  t->add_args()->set_type_id(TFT_PRODUCT);

  NodeDef ndef;
  AttrSlice attrs(ndef);

  FullTypeDef ft;
  EXPECT_FALSE(SpecializeType(attrs, op, ft).ok());
}