CVE-2021-37662: Access of Uninitialized Pointer (CWE-824)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions an attacker can generate undefined behavior via a reference binding to nullptr in `BoostedTreesCalculateBestGainsPerFeature` and similar attack can occur in `BoostedTreesCalculateBestFeatureSplitV2`. The [implementation](https://github.com/tensorflow/tensorflow/blob/84d053187cb80d975ef2b9684d4b61981bca0c41/tensorflow/core/kernels/boosted_trees/stats_ops.cc) does not validate the input values. We have patched the issue in GitHub commit 9c87c32c710d0b5b53dc6fd3bfde4046e1f7a5ad and in commit 429f009d2b2c09028647dd4bb7b3f6f414bbaad7. The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected and still in supported range.
CWE description: The product accesses or uses a pointer that has not been initialized.
CVSS v3 base score: 7.8
Published: 2021-08-12T21:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/boosted_trees/stats_ops.cc
Commit date: 2021-07-27 12:21:52 -0700
Commit message: Disallow empty node_id_range in tf.raw_ops.BoostedTreesCalculateBestFeatureSplitV2 and tf.raw_ops.BoostedTreesCalculateBestGainsPerFeature

PiperOrigin-RevId: 387165936
Change-Id: I2f70341af96236b2776c2a592c917d549c1fc1e2

Diff: diff --git a/tensorflow/core/kernels/boosted_trees/stats_ops.cc b/tensorflow/core/kernels/boosted_trees/stats_ops.cc
index f3449daef7838..014c2ec22c9cf 100644
--- a/tensorflow/core/kernels/boosted_trees/stats_ops.cc
+++ b/tensorflow/core/kernels/boosted_trees/stats_ops.cc
@@ -49,10 +49,20 @@ class BoostedTreesCalculateBestGainsPerFeatureOp : public OpKernel {
 
   void Compute(OpKernelContext* const context) override {
     // node_id_range
     const Tensor* node_id_range_t;
     OP_REQUIRES_OK(context, context->input("node_id_range", &node_id_range_t));
+    OP_REQUIRES(
+        context, node_id_range_t->dims() == 1,
+        errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
+                                "given node_id_range has dims of ",
+                                node_id_range_t->dims()));
+    OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
+                errors::InvalidArgument(
+                    "node_id_range must be a rank 1 tensor with shape=[2], but "
+                    "given node_id_range has shape ",
+                    node_id_range_t->dim_size(0), " on its first dim"));
     const auto node_id_range = node_id_range_t->vec<int32>();
     const int32_t node_id_first = node_id_range(0);  // inclusive
     const int32_t node_id_last = node_id_range(1);   // exclusive
     // stats_summary_list
     OpInputList stats_summary_list;
@@ -568,10 +578,20 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
   void Compute(OpKernelContext* const context) override {
     // node_id_range
     const Tensor* node_id_range_t;
     OP_REQUIRES_OK(context, context->input("node_id_range", &node_id_range_t));
     const auto node_id_range = node_id_range_t->vec<int32>();
+    OP_REQUIRES(
+        context, node_id_range_t->dims() == 1,
+        errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
+                                "given node_id_range has dims of ",
+                                node_id_range_t->dims()));
+    OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
+                errors::InvalidArgument(
+                    "node_id_range must be a rank 1 tensor with shape=[2], but "
+                    "given node_id_range has shape ",
+                    node_id_range_t->dim_size(0), " on its first dim"));
     const int32_t node_id_first = node_id_range(0);  // Inclusive.
     const int32_t node_id_last = node_id_range(1);   // Exclusive.
 
     // Get stats_summaries_list.
     OpInputList stats_summaries_list;

Fixed code:     OP_REQUIRES(
        context, node_id_range_t->dims() == 1,
        errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
                                "given node_id_range has dims of ",
                                node_id_range_t->dims()));
    OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
                errors::InvalidArgument(
                    "node_id_range must be a rank 1 tensor with shape=[2], but "
                    "given node_id_range has shape ",
                    node_id_range_t->dim_size(0), " on its first dim"));
    OP_REQUIRES(
        context, node_id_range_t->dims() == 1,
        errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
                                "given node_id_range has dims of ",
                                node_id_range_t->dims()));
    OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
                errors::InvalidArgument(
                    "node_id_range must be a rank 1 tensor with shape=[2], but "
                    "given node_id_range has shape ",
                    node_id_range_t->dim_size(0), " on its first dim"));