CVE-2022-41909: NULL Pointer Dereference (CWE-476)
value: TensorFlow is an open source platform for machine learning. An input `encoded` that is not a valid `CompositeTensorVariant` tensor will trigger a segfault in `tf.raw_ops.CompositeTensorVariantToComponents`. We have patched the issue in GitHub commits bf594d08d377dc6a3354d9fdb494b32d45f91971 and 660ce5a89eb6766834bdc303d2ab3902aef99d3d. The fix will be included in TensorFlow 2.11. We will also cherrypick this commit on TensorFlow 2.10.1, 2.9.3, and TensorFlow 2.8.4, as these are also affected and still in supported range.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 7.5
Published: 2022-11-18T22:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: Python
Files changed: tensorflow/core/kernels/composite_tensor_ops.cc, tensorflow/python/kernel_tests/composite_tensor_ops_test.py
Commit date: 2022-09-14 14:59:17 -0700
Commit message: [Security] Add a check for empty variant tensor input to CompositeTensorVariantToComponents.

So an exception will be raised instead of segfault.

PiperOrigin-RevId: 474397914

Diff: diff --git a/tensorflow/core/kernels/composite_tensor_ops.cc b/tensorflow/core/kernels/composite_tensor_ops.cc
index f41b02991bba4..bc4f96e6bb2fe 100644
--- a/tensorflow/core/kernels/composite_tensor_ops.cc
+++ b/tensorflow/core/kernels/composite_tensor_ops.cc
@@ -13,10 +13,11 @@ See the License for the specific language governing permissions and
 limitations under the License.
 ==============================================================================*/
 
 #include "tensorflow/core/framework/op.h"
 #include "tensorflow/core/framework/op_kernel.h"
+#include "tensorflow/core/framework/op_requires.h"
 #include "tensorflow/core/framework/variant.h"
 #include "tensorflow/core/framework/variant_encode_decode.h"
 #include "tensorflow/core/kernels/composite_tensor_variant.h"
 #include "tensorflow/core/platform/errors.h"
 #include "tensorflow/core/protobuf/composite_tensor_variant.pb.h"
@@ -64,10 +65,15 @@ class CompositeTensorVariantToComponents : public OpKernel {
                    context->GetAttr("Tcomponents", &component_dtypes_));
   }
 
   void Compute(OpKernelContext* context) override {
     Tensor encoded_t = context->input(0);
+    OP_REQUIRES(
+        context, encoded_t.flat<Variant>().size() > 0,
+        errors::InvalidArgument("Input `encoded` must not be an empty variant "
+                                "tensor, but got ",
+                                encoded_t.DebugString()));
     auto* encoded = encoded_t.flat<Variant>()(0).get<CompositeTensorVariant>();
 
     // Check that the encoded TypeSpec is compatible with the expected TypeSpec.
     // For now, we just check that the class matches.
     //
diff --git a/tensorflow/python/kernel_tests/composite_tensor_ops_test.py b/tensorflow/python/kernel_tests/composite_tensor_ops_test.py
index e5e9d1ef9bf6d..7a10cae3ebc10 100644
--- a/tensorflow/python/kernel_tests/composite_tensor_ops_test.py
+++ b/tensorflow/python/kernel_tests/composite_tensor_ops_test.py
@@ -16,15 +16,17 @@
 
 from absl.testing import parameterized
 
 from tensorflow.python.eager import backprop
 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
 from tensorflow.python.framework import sparse_tensor
 from tensorflow.python.framework import test_util
 from tensorflow.python.ops import composite_tensor_ops
+from tensorflow.python.ops import gen_composite_tensor_ops
 from tensorflow.python.ops import gradients_impl
 from tensorflow.python.ops import math_ops
 from tensorflow.python.ops import parsing_ops
 from tensorflow.python.ops import sparse_ops
 from tensorflow.python.ops.ragged import ragged_factory_ops
@@ -81,10 +83,22 @@ class ExtensionTypeTest(test_util.TensorFlowTestCase, parameterized.TestCase):
   ])
   def testEncodingErrors(self, value, spec, message):
     with self.assertRaisesRegex(ValueError, message):
       composite_tensor_ops.composite_tensor_to_variants(value(), spec)
 
+  def testDecodingEmptyNonScalarTensorError(self):
+    if not context.executing_eagerly():
+      # Creating a variant tensor of an empty list is not allowed in eager mode.
+      return
+
+    with self.assertRaisesRegex(errors.InvalidArgumentError,
+                                'must not be an empty variant tensor'):
+      gen_composite_tensor_ops.CompositeTensorVariantToComponents(
+          encoded=constant_op.constant([], dtype=dtypes.variant),
+          metadata='',
+          Tcomponents=[dtypes.int32])
+
   def testRoundTripThroughTensorProto(self):
     value = ragged_factory_ops.constant([[1, 2], [3], [4, 5, 6]])
     encoded = composite_tensor_ops.composite_tensor_to_variants(value)
     proto = parsing_ops.SerializeTensor(tensor=encoded)
     parsed = parsing_ops.ParseTensor(serialized=proto, out_type=dtypes.variant)

Fixed code: #include "tensorflow/core/framework/op_requires.h"
    OP_REQUIRES(
        context, encoded_t.flat<Variant>().size() > 0,
        errors::InvalidArgument("Input `encoded` must not be an empty variant "
                                "tensor, but got ",
                                encoded_t.DebugString()));
from tensorflow.python.framework import constant_op
from tensorflow.python.ops import gen_composite_tensor_ops
  def testDecodingEmptyNonScalarTensorError(self):
    if not context.executing_eagerly():
      # Creating a variant tensor of an empty list is not allowed in eager mode.
      return

    with self.assertRaisesRegex(errors.InvalidArgumentError,
                                'must not be an empty variant tensor'):
      gen_composite_tensor_ops.CompositeTensorVariantToComponents(
          encoded=constant_op.constant([], dtype=dtypes.variant),
          metadata='',
          Tcomponents=[dtypes.int32])