CVE-2022-35937 (C++, published 2022-09-16T20:15Z)
Description: value: TensorFlow is an open source platform for machine learning. The `GatherNd` function takes arguments that determine the sizes of inputs and outputs. If the inputs given are greater than or equal to the sizes of the outputs, an out-of-bounds memory read is triggered. This issue has been patched in GitHub commit 595a65a3e224a0362d7e68c2213acfc2b499a196. 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.
Severity: nan (CVSS v3 base score: 9.1)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/tensorflow/tensorflow
Files changed:
tensorflow/lite/kernels/gather_nd.cc
tensorflow/lite/kernels/gather_nd_test.cc
tensorflow/lite/kernels/internal/reference/reference_ops.h
Commit message: Return a TFLite error if gather_nd will result in reading invalid memory

PiperOrigin-RevId: 463054033


Vulnerable code:
TfLiteStatus GatherNd(const TfLiteTensor* params, const TfLiteTensor* indices,
                      TfLiteTensor* output) {
  reference_ops::GatherNd(
  return kTfLiteOk;
      return GatherNd<float, IndicesT>(params, indices, output);
      return GatherNd<uint8_t, IndicesT>(params, indices, output);
      return GatherNd<int8_t, IndicesT>(params, indices, output);
      return GatherNd<int16_t, IndicesT>(params, indices, output);
      return GatherNd<int32_t, IndicesT>(params, indices, output);
      return GatherNd<int64_t, IndicesT>(params, indices, output);
inline void GatherNd(const RuntimeShape& params_shape,
                     const ParamsT* params_data,
                     const RuntimeShape& indices_shape,
                     const IndicesT* indices_data,
                     const RuntimeShape& output_shape, ParamsT* output_data) {
    int from_pos = 0;

Fixed code:
#include "tensorflow/lite/c/c_api_types.h"
TfLiteStatus GatherNd(TfLiteContext* context, const TfLiteTensor* params,
                      const TfLiteTensor* indices, TfLiteTensor* output) {
  const TfLiteStatus status = reference_ops::GatherNd(
  if (status != kTfLiteOk) {
    TF_LITE_KERNEL_LOG(context, "gather_nd index out of bounds");
  }
  return status;
      return GatherNd<float, IndicesT>(context, params, indices, output);
      return GatherNd<uint8_t, IndicesT>(context, params, indices, output);
      return GatherNd<int8_t, IndicesT>(context, params, indices, output);
      return GatherNd<int16_t, IndicesT>(context, params, indices, output);
      return GatherNd<int32_t, IndicesT>(context, params, indices, output);
      return GatherNd<int64_t, IndicesT>(context, params, indices, output);
TEST(GatherNdOpTest, ErrorOnOutOfBoundsTooLarge) {
  GatherNdOpModel m({TensorType_FLOAT32, {2, 2}}, {TensorType_INT32, {2, 2}});
  m.SetInput<float>({1.1, 1.2, 2.1, 2.2});
  m.SetPositions<int32_t>({0, 0, 2, 0});
  EXPECT_EQ(m.Invoke(), kTfLiteError);
  m.SetPositions<int32_t>({0, 0, 1, 2});
  EXPECT_EQ(m.Invoke(), kTfLiteError);
}

TEST(GatherNdOpTest, ErrorOnOutOfBoundsNegative) {
  GatherNdOpModel m({TensorType_FLOAT32, {2, 2}}, {TensorType_INT32, {2, 2}});
  m.SetInput<float>({1.1, 1.2, 2.1, 2.2});
  m.SetPositions<int32_t>({1, -1, 1, 1});
  EXPECT_EQ(m.Invoke(), kTfLiteError);
}

#include "tensorflow/lite/c/c_api_types.h"
// Implements GatherNd.
// Returns an error if any of the indices_data would cause an out of bounds
// memory read.
inline TfLiteStatus GatherNd(const RuntimeShape& params_shape,
                             const ParamsT* params_data,
                             const RuntimeShape& indices_shape,
                             const IndicesT* indices_data,
                             const RuntimeShape& output_shape,
                             ParamsT* output_data) {
    int64_t from_pos = 0;
    if (from_pos < 0 || from_pos + res.slice_size > params_shape.FlatSize()) {
      return kTfLiteError;
    }
  return kTfLiteOk;