VYPR
Moderate severityNVD Advisory· Published Aug 12, 2021· Updated Aug 4, 2024

Heap OOB in TensorFlow Lite's `Gather*` implementations

CVE-2021-37687

Description

TensorFlow is an end-to-end open source platform for machine learning. In affected versions TFLite's `GatherNd` implementation does not support negative indices but there are no checks for this situation. Hence, an attacker can read arbitrary data from the heap by carefully crafting a model with negative values in indices. Similar issue exists in `Gather` implementation. We have patched the issue in GitHub commits bb6a0383ed553c286f87ca88c207f6774d5c4a8f and eb921122119a6b6e470ee98b89e65d721663179d. 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.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
tensorflowPyPI
< 2.3.42.3.4
tensorflowPyPI
>= 2.4.0, < 2.4.32.4.3
tensorflowPyPI
>= 2.5.0, < 2.5.12.5.1
tensorflow-cpuPyPI
< 2.3.42.3.4
tensorflow-cpuPyPI
>= 2.4.0, < 2.4.32.4.3
tensorflow-cpuPyPI
>= 2.5.0, < 2.5.12.5.1
tensorflow-gpuPyPI
< 2.3.42.3.4
tensorflow-gpuPyPI
>= 2.4.0, < 2.4.32.4.3
tensorflow-gpuPyPI
>= 2.5.0, < 2.5.12.5.1

Affected products

1

Patches

2
eb921122119a

Prevent heap OOB read in TFLite's `gather.cc`.

https://github.com/tensorflow/tensorflowMihai MaruseacJul 28, 2021via ghsa
1 file changed · +53 16
  • tensorflow/lite/kernels/gather.cc+53 16 modified
    @@ -117,8 +117,20 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
     }
     
     template <typename InputT, typename PositionsT>
    -TfLiteStatus Gather(const TfLiteGatherParams& params, const TfLiteTensor* input,
    -                    const TfLiteTensor* positions, TfLiteTensor* output) {
    +TfLiteStatus Gather(TfLiteContext* context, const TfLiteGatherParams& params,
    +                    const TfLiteTensor* input, const TfLiteTensor* positions,
    +                    TfLiteTensor* output) {
    +  const PositionsT* indexes = GetTensorData<PositionsT>(positions);
    +  bool indices_has_only_positive_elements = true;
    +  const size_t num_indices = positions->bytes / sizeof(PositionsT);
    +  for (size_t i = 0; i < num_indices; i++) {
    +    if (indexes[i] < 0) {
    +      indices_has_only_positive_elements = false;
    +      break;
    +    }
    +  }
    +  TF_LITE_ENSURE(context, indices_has_only_positive_elements);
    +
       tflite::GatherParams op_params;
       op_params.axis = params.axis;
       op_params.batch_dims = params.batch_dims;
    @@ -134,7 +146,18 @@ TfLiteStatus GatherStrings(TfLiteContext* context, const TfLiteTensor* input,
                                const TfLiteTensor* positions,
                                TfLiteTensor* output) {
       DynamicBuffer buffer;
    +
       const PositionT* indexes = GetTensorData<PositionT>(positions);
    +  bool indices_has_only_positive_elements = true;
    +  const size_t num_indices = positions->bytes / sizeof(PositionT);
    +  for (size_t i = 0; i < num_indices; i++) {
    +    if (indexes[i] < 0) {
    +      indices_has_only_positive_elements = false;
    +      break;
    +    }
    +  }
    +  TF_LITE_ENSURE(context, indices_has_only_positive_elements);
    +
       const PositionT num_strings = GetStringCount(input);
       const int num_indexes = NumElements(positions);
     
    @@ -163,19 +186,26 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
       if (positions->type == kTfLiteInt32) {
         switch (input->type) {
           case kTfLiteFloat32:
    -        return Gather<float, int32_t>(*params, input, positions, output);
    +        return Gather<float, int32_t>(context, *params, input, positions,
    +                                      output);
           case kTfLiteUInt8:
    -        return Gather<uint8_t, int32_t>(*params, input, positions, output);
    +        return Gather<uint8_t, int32_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt8:
    -        return Gather<int8_t, int32_t>(*params, input, positions, output);
    +        return Gather<int8_t, int32_t>(context, *params, input, positions,
    +                                       output);
           case kTfLiteInt16:
    -        return Gather<int16_t, int32_t>(*params, input, positions, output);
    +        return Gather<int16_t, int32_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt32:
    -        return Gather<int32_t, int32_t>(*params, input, positions, output);
    +        return Gather<int32_t, int32_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt64:
    -        return Gather<int64_t, int32_t>(*params, input, positions, output);
    +        return Gather<int64_t, int32_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteBool:
    -        return Gather<bool, int32_t>(*params, input, positions, output);
    +        return Gather<bool, int32_t>(context, *params, input, positions,
    +                                     output);
           case kTfLiteString:
             return GatherStrings<int32_t>(context, input, positions, output);
           default:
    @@ -187,19 +217,26 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
       if (positions->type == kTfLiteInt64) {
         switch (input->type) {
           case kTfLiteFloat32:
    -        return Gather<float, int64_t>(*params, input, positions, output);
    +        return Gather<float, int64_t>(context, *params, input, positions,
    +                                      output);
           case kTfLiteUInt8:
    -        return Gather<uint8_t, int64_t>(*params, input, positions, output);
    +        return Gather<uint8_t, int64_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt8:
    -        return Gather<int8_t, int64_t>(*params, input, positions, output);
    +        return Gather<int8_t, int64_t>(context, *params, input, positions,
    +                                       output);
           case kTfLiteInt16:
    -        return Gather<int16_t, int64_t>(*params, input, positions, output);
    +        return Gather<int16_t, int64_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt32:
    -        return Gather<int32_t, int64_t>(*params, input, positions, output);
    +        return Gather<int32_t, int64_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteInt64:
    -        return Gather<int64_t, int64_t>(*params, input, positions, output);
    +        return Gather<int64_t, int64_t>(context, *params, input, positions,
    +                                        output);
           case kTfLiteBool:
    -        return Gather<bool, int64_t>(*params, input, positions, output);
    +        return Gather<bool, int64_t>(context, *params, input, positions,
    +                                     output);
           case kTfLiteString:
             return GatherStrings<int64_t>(context, input, positions, output);
           default:
    
bb6a0383ed55

Prevent heap OOB read in TFLite's `gather_nd.cc`.

https://github.com/tensorflow/tensorflowMihai MaruseacJul 27, 2021via ghsa
1 file changed · +11 0
  • tensorflow/lite/kernels/gather_nd.cc+11 0 modified
    @@ -123,6 +123,17 @@ TfLiteStatus GatherNdString(const TfLiteTensor* params,
     template <typename IndicesT>
     TfLiteStatus EvalGatherNd(TfLiteContext* context, const TfLiteTensor* params,
                               const TfLiteTensor* indices, TfLiteTensor* output) {
    +  bool indices_has_only_positive_elements = true;
    +  const auto* indices_values = GetTensorData<IndicesT>(indices);
    +  const size_t num_indices = indices->bytes / sizeof(IndicesT);
    +  for (size_t i = 0; i < num_indices; i++) {
    +    if (indices_values[i] < 0) {
    +      indices_has_only_positive_elements = false;
    +      break;
    +    }
    +  }
    +  TF_LITE_ENSURE(context, indices_has_only_positive_elements);
    +
       switch (params->type) {
         case kTfLiteFloat32:
           return GatherNd<float, IndicesT>(params, indices, output);
    

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

10

News mentions

0

No linked articles in our index yet.