VYPR
High severityNVD Advisory· Published Sep 16, 2022· Updated Apr 23, 2025

OOB read in `Gather_nd` op in TensorFlow Lite

CVE-2022-35937

Description

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.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
tensorflowPyPI
< 2.7.22.7.2
tensorflowPyPI
>= 2.8.0, < 2.8.12.8.1
tensorflowPyPI
>= 2.9.0, < 2.9.12.9.1
tensorflow-cpuPyPI
< 2.7.22.7.2
tensorflow-cpuPyPI
>= 2.8.0, < 2.8.12.8.1
tensorflow-cpuPyPI
>= 2.9.0, < 2.9.12.9.1
tensorflow-gpuPyPI
< 2.7.22.7.2
tensorflow-gpuPyPI
>= 2.8.0, < 2.8.12.8.1
tensorflow-gpuPyPI
>= 2.9.0, < 2.9.12.9.1

Affected products

1

Patches

1
595a65a3e224

Return a TFLite error if gather_nd will result in reading invalid memory

https://github.com/tensorflow/tensorflowA. Unique TensorFlowerJul 25, 2022via ghsa
3 files changed · +45 16
  • tensorflow/lite/kernels/gather_nd.cc+14 10 modified
    @@ -14,6 +14,7 @@ limitations under the License.
     ==============================================================================*/
     #include <stdint.h>
     
    +#include "tensorflow/lite/c/c_api_types.h"
     #include "tensorflow/lite/c/common.h"
     #include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h"
     #include "tensorflow/lite/kernels/internal/reference/reference_ops.h"
    @@ -102,13 +103,16 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
     }
     
     template <typename ParamsT, typename IndicesT>
    -TfLiteStatus GatherNd(const TfLiteTensor* params, const TfLiteTensor* indices,
    -                      TfLiteTensor* output) {
    -  reference_ops::GatherNd(
    +TfLiteStatus GatherNd(TfLiteContext* context, const TfLiteTensor* params,
    +                      const TfLiteTensor* indices, TfLiteTensor* output) {
    +  const TfLiteStatus status = reference_ops::GatherNd(
           GetTensorShape(params), GetTensorData<ParamsT>(params),
           GetTensorShape(indices), GetTensorData<IndicesT>(indices),
           GetTensorShape(output), GetTensorData<ParamsT>(output));
    -  return kTfLiteOk;
    +  if (status != kTfLiteOk) {
    +    TF_LITE_KERNEL_LOG(context, "gather_nd index out of bounds");
    +  }
    +  return status;
     }
     
     template <typename IndicesT>
    @@ -136,17 +140,17 @@ TfLiteStatus EvalGatherNd(TfLiteContext* context, const TfLiteTensor* params,
     
       switch (params->type) {
         case kTfLiteFloat32:
    -      return GatherNd<float, IndicesT>(params, indices, output);
    +      return GatherNd<float, IndicesT>(context, params, indices, output);
         case kTfLiteUInt8:
    -      return GatherNd<uint8_t, IndicesT>(params, indices, output);
    +      return GatherNd<uint8_t, IndicesT>(context, params, indices, output);
         case kTfLiteInt8:
    -      return GatherNd<int8_t, IndicesT>(params, indices, output);
    +      return GatherNd<int8_t, IndicesT>(context, params, indices, output);
         case kTfLiteInt16:
    -      return GatherNd<int16_t, IndicesT>(params, indices, output);
    +      return GatherNd<int16_t, IndicesT>(context, params, indices, output);
         case kTfLiteInt32:
    -      return GatherNd<int32_t, IndicesT>(params, indices, output);
    +      return GatherNd<int32_t, IndicesT>(context, params, indices, output);
         case kTfLiteInt64:
    -      return GatherNd<int64_t, IndicesT>(params, indices, output);
    +      return GatherNd<int64_t, IndicesT>(context, params, indices, output);
         case kTfLiteString:
           return GatherNdString<IndicesT>(params, indices, output);
         default:
    
  • tensorflow/lite/kernels/gather_nd_test.cc+16 0 modified
    @@ -73,6 +73,22 @@ TEST(GatherNdOpTest, ElementIndexingIntoMatrix) {
       EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray({1.1, 2.2}));
     }
     
    +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);
    +}
    +
     TEST(GatherNdOpTest, SliceIndexingIntoMatrix) {
       GatherNdOpModel m({TensorType_FLOAT32, {2, 2}}, {TensorType_INT32, {2, 1}});
       m.SetInput<float>({1.1, 1.2, 2.1, 2.2});
    
  • tensorflow/lite/kernels/internal/reference/reference_ops.h+15 6 modified
    @@ -29,6 +29,7 @@ limitations under the License.
     #include "third_party/eigen3/Eigen/Core"
     #include "fixedpoint/fixedpoint.h"
     #include "ruy/profiler/instrumentation.h"  // from @ruy
    +#include "tensorflow/lite/c/c_api_types.h"
     #include "tensorflow/lite/c/common.h"
     #include "tensorflow/lite/kernels/internal/common.h"
     #include "tensorflow/lite/kernels/internal/quantization_util.h"
    @@ -595,23 +596,31 @@ inline GatherNdHelperResult GatherNdHelper(const RuntimeShape& params_shape,
       return ret;
     }
     
    +// Implements GatherNd.
    +// Returns an error if any of the indices_data would cause an out of bounds
    +// memory read.
     template <typename ParamsT, typename IndicesT = int32>
    -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) {
    +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) {
       ruy::profiler::ScopeLabel label("GatherNd");
     
       const GatherNdHelperResult res = GatherNdHelper(params_shape, indices_shape);
       for (int i = 0; i < res.n_slices; ++i) {
    -    int from_pos = 0;
    +    int64_t from_pos = 0;
         for (int j = 0; j < res.indices_nd; ++j) {
           from_pos += indices_data[i * res.indices_nd + j] * res.dims_to_count[j];
         }
    +    if (from_pos < 0 || from_pos + res.slice_size > params_shape.FlatSize()) {
    +      return kTfLiteError;
    +    }
         std::memcpy(output_data + i * res.slice_size, params_data + from_pos,
                     sizeof(ParamsT) * res.slice_size);
       }
    +  return kTfLiteOk;
     }
     
     #ifndef TF_LITE_STATIC_MEMORY
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.