Vulnerability: Stack overflow in TensorFlow ### Impact
The `GraphDef` format in TensorFlow does not allow self recursive functions. The runtime assumes that this invariant is satisfied. However, a `GraphDef` containing a fragment such as the following can be consumed when loading a `SavedModel`:

```
  library {
    function {
      signature {
        name: "SomeOp"
        description: "Self recursive op"
      }
      node_def {
        name: "1"
        op: "SomeOp"
      }
      node_def {
        name: "2"
        op: "SomeOp"
      }
    }
  } 
```

This would result in a stack overflow during execution as resolving each `NodeDef` means resolving the function itself and its nodes.

### Patches
We have patched the issue in GitHub commit [448a16182065bd08a202d9057dd8ca541e67996c](https://github.com/tensorflow/tensorflow/commit/448a16182065bd08a202d9057dd8ca541e67996c).

The fix will be included in TensorFlow 2.8.0. We will also cherrypick this commit on TensorFlow 2.7.1, TensorFlow 2.6.3, and TensorFlow 2.5.3, as these are also affected and still in supported range.

### For more information
Please consult [our security guide](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md) for more information regarding the security model and how to contact us with issues and questions.
Vulnerability ID: GHSA-247x-2f9f-5wp7
CWE: CWE-400
Severity score: 7.5
Project: https://github.com/tensorflow/tensorflow
Published: 2022-02-09
File: tensorflow/cc/saved_model/loader.cc
Commit message: Prevent stack overflow when FunctionLib in GraphDef has a self-recursive function.

It is likely that no recursivity is supported, but we should handle this separately.

PiperOrigin-RevId: 414860329
Change-Id: I02a2270e86282b37362ddd485eeef16fb986a9e0
Commit author: Mihai Maruseac

Vulnerable version (before fix):
 limitations under the License. #include "tensorflow/core/framework/attr_value.pb.h" #include "tensorflow/core/framework/function.pb.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/tensor.pb.h" #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/monitoring/counter.h" static Status ValidateNode(const NodeDef& node) {   return Status::OK(); }  static Status ValidateSavedTensors(const GraphDef& graph_def) {   for (const auto& node : graph_def.node()) {     TF_RETURN_IF_ERROR(ValidateNode(node)); static Status ValidateSavedTensors(const GraphDef& graph_def) {       for (const auto& node : function.node_def()) {         TF_RETURN_IF_ERROR(ValidateNode(node));       }     }   } 

Fixed version (after fix):
 limitations under the License. #include "tensorflow/core/framework/attr_value.pb.h" #include "tensorflow/core/framework/function.pb.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/op_def.pb.h" #include "tensorflow/core/framework/tensor.pb.h" #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/monitoring/counter.h" static Status ValidateNode(const NodeDef& node) {   return Status::OK(); }  static Status ValidateFunctionNotRecursive(const FunctionDef& function) {   const auto& function_name = function.signature().name();   for (const auto& node : function.node_def()) {     if (node.op() == function_name) {       return errors::FailedPrecondition(           "Function ", function_name,           " is self recursive and TensorFlow does not support this scenario.");     }   }    return Status::OK(); }  static Status ValidateSavedTensors(const GraphDef& graph_def) {   for (const auto& node : graph_def.node()) {     TF_RETURN_IF_ERROR(ValidateNode(node)); static Status ValidateSavedTensors(const GraphDef& graph_def) {       for (const auto& node : function.node_def()) {         TF_RETURN_IF_ERROR(ValidateNode(node));       }        // Also check that there is no recursivity in the library       // TODO(mihaimaruseac): Do more than self-recursivity       TF_RETURN_IF_ERROR(ValidateFunctionNotRecursive(function));     }   } 

Patch:
patch: @@ -25,6 +25,7 @@ limitations under the License.
 #include "tensorflow/core/framework/attr_value.pb.h"
 #include "tensorflow/core/framework/function.pb.h"
 #include "tensorflow/core/framework/node_def.pb.h"
+#include "tensorflow/core/framework/op_def.pb.h"
 #include "tensorflow/core/framework/tensor.pb.h"
 #include "tensorflow/core/lib/io/path.h"
 #include "tensorflow/core/lib/monitoring/counter.h"
@@ -99,6 +100,19 @@ static Status ValidateNode(const NodeDef& node) {
   return Status::OK();
 }
 
+static Status ValidateFunctionNotRecursive(const FunctionDef& function) {
+  const auto& function_name = function.signature().name();
+  for (const auto& node : function.node_def()) {
+    if (node.op() == function_name) {
+      return errors::FailedPrecondition(
+          "Function ", function_name,
+          " is self recursive and TensorFlow does not support this scenario.");
+    }
+  }
+
+  return Status::OK();
+}
+
 static Status ValidateSavedTensors(const GraphDef& graph_def) {
   for (const auto& node : graph_def.node()) {
     TF_RETURN_IF_ERROR(ValidateNode(node));
@@ -110,6 +124,10 @@ static Status ValidateSavedTensors(const GraphDef& graph_def) {
       for (const auto& node : function.node_def()) {
         TF_RETURN_IF_ERROR(ValidateNode(node));
       }
+
+      // Also check that there is no recursivity in the library
+      // TODO(mihaimaruseac): Do more than self-recursivity
+      TF_RETURN_IF_ERROR(ValidateFunctionNotRecursive(function));
     }
   }
path: tensorflow/cc/saved_model/loader.cc