CVE-2021-37686 (C, published 2021-08-12T22:15Z)
Description: value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions the strided slice implementation in TFLite has a logic bug which can allow an attacker to trigger an infinite loop. This arises from newly introduced support for [ellipsis in axis definition](https://github.com/tensorflow/tensorflow/blob/149562d49faa709ea80df1d99fc41d005b81082a/tensorflow/lite/kernels/strided_slice.cc#L103-L122). An attacker can craft a model such that `ellipsis_end_idx` is smaller than `i` (e.g., always negative). In this case, the inner loop does not increase `i` and the `continue` statement causes execution to skip over the preincrement at the end of the outer loop. We have patched the issue in GitHub commit dfa22b348b70bb89d6d6ec0ff53973bacb4f4695. TensorFlow 2.6.0 is the only affected version.
Severity: LOW (CVSS v3 base score: 5.5)
Weakness: CWE-835 \u2014 Loop with Unreachable Exit Condition ('Infinite Loop')
The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
Repository: https://github.com/tensorflow/tensorflow
Files changed:
tensorflow/lite/kernels/internal/averagepool_quantized_test.cc
tensorflow/lite/kernels/internal/optimized/integer_ops/pooling.h
tensorflow/lite/kernels/internal/optimized/legacy_optimized_ops.h
tensorflow/lite/kernels/internal/optimized/optimized_ops.h
tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h
tensorflow/lite/kernels/internal/reference/legacy_reference_ops.h
tensorflow/lite/kernels/internal/reference/pooling.h
tensorflow/lite/kernels/pooling.cc
Commit message: Prevent a division by 0 in average ops.

PiperOrigin-RevId: 385184660
Change-Id: I7affd4554f9b336fca29ac68f633232c094d0bd3


Vulnerable code:
  reference_integer_ops::AveragePool(params, input_shape, input_data,
                                     output_shape,
                                     reference_averagePool_output.data());
  optimized_integer_ops::AveragePool(params, input_shape, input_data,
                                     output_shape,
                                     optimized_averagePool_output.data());
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const float* input_data, const Dims<4>& input_dims,
  AveragePool(params, DimsToShape(input_dims), input_data,
              DimsToShape(output_dims), output_data);
void AveragePool(const float* input_data, const Dims<4>& input_dims,
  AveragePool(input_data, input_dims, stride_width, stride_height, pad_width,
              pad_height, kwidth, kheight, output_activation_min,
              output_activation_max, output_data, output_dims);
void AveragePool(const float* input_data, const Dims<4>& input_dims, int stride,
  AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width, pad_height,
                  filter_width, filter_height, output_data, output_dims);
inline void AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  AveragePool(params, DimsToShape(input_dims), input_data,
              DimsToShape(output_dims), output_data);
void AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  AveragePool(input_data, input_dims, stride_width, stride_height, pad_width,
              pad_height, filter_width, filter_height, output_activation_min,
              output_activation_max, output_data, output_dims);
void AveragePool(const uint8* input_data, const Dims<4>& input_dims, int stride,
  AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width, pad_height,
                  filter_width, filter_height, output_activation_min,
                  output_activation_max, output_data, output_dims);
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const float* input_data, const Dims<4>& input_dims,
  AveragePool(params, DimsToShape(input_dims), input_data,
              DimsToShape(output_dims), output_data);
void AveragePool(const float* input_data, const Dims<4>& input_dims,
  AveragePool(input_data, input_dims, stride_width, stride_height, pad_width,
              pad_height, kwidth, kheight, output_activation_min,
              output_activation_max, output_data, output_dims);
void AveragePool(const float* input_data, const Dims<4>& input_dims, int stride,
  AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width, pad_height,
                  filter_width, filter_height, output_data, output_dims);
inline void AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  AveragePool(params, DimsToShape(input_dims), input_data,
              DimsToShape(output_dims), output_data);
void AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  AveragePool(input_data, input_dims, stride_width, stride_height, pad_width,
              pad_height, filter_width, filter_height, output_activation_min,
              output_activation_max, output_data, output_dims);
void AveragePool(const uint8* input_data, const Dims<4>& input_dims, int stride,
  AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width, pad_height,
                  filter_width, filter_height, output_activation_min,
                  output_activation_max, output_data, output_dims);
inline void AveragePool(const PoolParams& params,
inline void AveragePool(const PoolParams& params,
void AverageEvalFloat(TfLiteContext* context, TfLiteNode* node,
                      TfLitePoolParams* params, OpData* data,
                      const TfLiteTensor* input, TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                       \
  tflite::PoolParams op_params;                                          \
  op_params.stride_height = params->stride_height;                       \
  op_params.stride_width = params->stride_width;                         \
  op_params.filter_height = params->filter_height;                       \
  op_params.filter_width = params->filter_width;                         \
  op_params.padding_values.height = data->padding.height;                \
  op_params.padding_values.width = data->padding.width;                  \
  op_params.float_activation_min = activation_min;                       \
  op_params.float_activation_max = activation_max;                       \
  type::AveragePool(op_params, GetTensorShape(input),                    \
                    GetTensorData<float>(input), GetTensorShape(output), \
                    GetTensorData<float>(output))
void AverageEvalQuantizedUint8(TfLiteContext* context, TfLiteNode* node,
                               TfLitePoolParams* params, OpData* data,
                               const TfLiteTensor* input,
                               TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                         \
  tflite::PoolParams op_params;                                            \
  op_params.stride_height = params->stride_height;                         \
  op_params.stride_width = params->stride_width;                           \
  op_params.filter_height = params->filter_height;                         \
  op_params.filter_width = params->filter_width;                           \
  op_params.padding_values.height = data->padding.height;                  \
  op_params.padding_values.width = data->padding.width;                    \
  op_params.quantized_activation_min = activation_min;                     \
  op_params.quantized_activation_max = activation_max;                     \
  type::AveragePool(op_params, GetTensorShape(input),                      \
                    GetTensorData<uint8_t>(input), GetTensorShape(output), \
                    GetTensorData<uint8_t>(output))
void AverageEvalQuantizedInt8(TfLiteContext* context, TfLiteNode* node,
                              TfLitePoolParams* params, OpData* data,
                              const TfLiteTensor* input, TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                        \
  tflite::PoolParams op_params;                                           \
  op_params.stride_height = params->stride_height;                        \
  op_params.stride_width = params->stride_width;                          \
  op_params.filter_height = params->filter_height;                        \
  op_params.filter_width = params->filter_width;                          \
  op_params.padding_values.height = data->padding.height;                 \
  op_params.padding_values.width = data->padding.width;                   \
  op_params.quantized_activation_min = activation_min;                    \
  op_params.quantized_activation_max = activation_max;                    \
  type::AveragePool(op_params, GetTensorShape(input),                     \
                    GetTensorData<int8_t>(input), GetTensorShape(output), \
                    GetTensorData<int8_t>(output))
void AverageEvalQuantizedInt16(TfLiteContext* context, TfLiteNode* node,
                               TfLitePoolParams* params, OpData* data,
                               const TfLiteTensor* input,
                               TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                         \
  tflite::PoolParams op_params;                                            \
  op_params.stride_height = params->stride_height;                         \
  op_params.stride_width = params->stride_width;                           \
  op_params.filter_height = params->filter_height;                         \
  op_params.filter_width = params->filter_width;                           \
  op_params.padding_values.height = data->padding.height;                  \
  op_params.padding_values.width = data->padding.width;                    \
  op_params.quantized_activation_min = activation_min;                     \
  op_params.quantized_activation_max = activation_max;                     \
  type::AveragePool(op_params, GetTensorShape(input),                      \
                    GetTensorData<int16_t>(input), GetTensorShape(output), \
                    GetTensorData<int16_t>(output))
      AverageEvalFloat<kernel_type>(context, node, params, data, input, output);
      break;
      AverageEvalQuantizedUint8<kernel_type>(context, node, params, data, input,
                                             output);
      break;
      AverageEvalQuantizedInt8<kernel_type>(context, node, params, data, input,
                                            output);
      break;
      AverageEvalQuantizedInt16<kernel_type>(context, node, params, data, input,
                                             output);
      break;

Fixed code:
  bool reference_success = reference_integer_ops::AveragePool(
      params, input_shape, input_data, output_shape,
      reference_averagePool_output.data());
  bool optimized_success = optimized_integer_ops::AveragePool(
      params, input_shape, input_data, output_shape,
      optimized_averagePool_output.data());
  EXPECT_TRUE(reference_success);
  EXPECT_TRUE(optimized_success);
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
inline bool AveragePool(const float* input_data, const Dims<4>& input_dims,
  return AveragePool(params, DimsToShape(input_dims), input_data,
                     DimsToShape(output_dims), output_data);
bool AveragePool(const float* input_data, const Dims<4>& input_dims,
  return AveragePool(input_data, input_dims, stride_width, stride_height,
                     pad_width, pad_height, kwidth, kheight,
                     output_activation_min, output_activation_max, output_data,
                     output_dims);
bool AveragePool(const float* input_data, const Dims<4>& input_dims, int stride,
  return AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width,
                         pad_height, filter_width, filter_height, output_data,
                         output_dims);
inline bool AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  return AveragePool(params, DimsToShape(input_dims), input_data,
                     DimsToShape(output_dims), output_data);
bool AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  return AveragePool(input_data, input_dims, stride_width, stride_height,
                     pad_width, pad_height, filter_width, filter_height,
                     output_activation_min, output_activation_max, output_data,
                     output_dims);
bool AveragePool(const uint8* input_data, const Dims<4>& input_dims, int stride,
  return AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width,
                         pad_height, filter_width, filter_height,
                         output_activation_min, output_activation_max,
                         output_data, output_dims);
inline bool AveragePool(const PoolParams& params,
  if (stride_height == 0) return false;
  if (stride_width == 0) return false;


  return true;
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
inline bool AveragePool(const float* input_data, const Dims<4>& input_dims,
  return AveragePool(params, DimsToShape(input_dims), input_data,
                     DimsToShape(output_dims), output_data);
bool AveragePool(const float* input_data, const Dims<4>& input_dims,
  return AveragePool(input_data, input_dims, stride_width, stride_height,
                     pad_width, pad_height, kwidth, kheight,
                     output_activation_min, output_activation_max, output_data,
                     output_dims);
bool AveragePool(const float* input_data, const Dims<4>& input_dims, int stride,
  return AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width,
                         pad_height, filter_width, filter_height, output_data,
                         output_dims);
inline bool AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  return AveragePool(params, DimsToShape(input_dims), input_data,
                     DimsToShape(output_dims), output_data);
bool AveragePool(const uint8* input_data, const Dims<4>& input_dims,
  return AveragePool(input_data, input_dims, stride_width, stride_height,
                     pad_width, pad_height, filter_width, filter_height,
                     output_activation_min, output_activation_max, output_data,
                     output_dims);
bool AveragePool(const uint8* input_data, const Dims<4>& input_dims, int stride,
  return AveragePool<Ac>(input_data, input_dims, stride, stride, pad_width,
                         pad_height, filter_width, filter_height,
                         output_activation_min, output_activation_max,
                         output_data, output_dims);
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
inline bool AveragePool(const PoolParams& params,
          if (filter_count == 0) return false;
  return true;
TfLiteStatus AverageEvalFloat(TfLiteContext* context, TfLiteNode* node,
                              TfLitePoolParams* params, OpData* data,
                              const TfLiteTensor* input, TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                            \
  tflite::PoolParams op_params;                                               \
  op_params.stride_height = params->stride_height;                            \
  op_params.stride_width = params->stride_width;                              \
  op_params.filter_height = params->filter_height;                            \
  op_params.filter_width = params->filter_width;                              \
  op_params.padding_values.height = data->padding.height;                     \
  op_params.padding_values.width = data->padding.width;                       \
  op_params.float_activation_min = activation_min;                            \
  op_params.float_activation_max = activation_max;                            \
  TF_LITE_ENSURE(context, type::AveragePool(op_params, GetTensorShape(input), \
                                            GetTensorData<float>(input),      \
                                            GetTensorShape(output),           \
                                            GetTensorData<float>(output)))
  return kTfLiteOk;
TfLiteStatus AverageEvalQuantizedUint8(TfLiteContext* context, TfLiteNode* node,
                                       TfLitePoolParams* params, OpData* data,
                                       const TfLiteTensor* input,
                                       TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                            \
  tflite::PoolParams op_params;                                               \
  op_params.stride_height = params->stride_height;                            \
  op_params.stride_width = params->stride_width;                              \
  op_params.filter_height = params->filter_height;                            \
  op_params.filter_width = params->filter_width;                              \
  op_params.padding_values.height = data->padding.height;                     \
  op_params.padding_values.width = data->padding.width;                       \
  op_params.quantized_activation_min = activation_min;                        \
  op_params.quantized_activation_max = activation_max;                        \
  TF_LITE_ENSURE(context, type::AveragePool(op_params, GetTensorShape(input), \
                                            GetTensorData<uint8_t>(input),    \
                                            GetTensorShape(output),           \
                                            GetTensorData<uint8_t>(output)))
  return kTfLiteOk;
TfLiteStatus AverageEvalQuantizedInt8(TfLiteContext* context, TfLiteNode* node,
                                      TfLitePoolParams* params, OpData* data,
                                      const TfLiteTensor* input,
                                      TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                            \
  tflite::PoolParams op_params;                                               \
  op_params.stride_height = params->stride_height;                            \
  op_params.stride_width = params->stride_width;                              \
  op_params.filter_height = params->filter_height;                            \
  op_params.filter_width = params->filter_width;                              \
  op_params.padding_values.height = data->padding.height;                     \
  op_params.padding_values.width = data->padding.width;                       \
  op_params.quantized_activation_min = activation_min;                        \
  op_params.quantized_activation_max = activation_max;                        \
  TF_LITE_ENSURE(context, type::AveragePool(op_params, GetTensorShape(input), \
                                            GetTensorData<int8_t>(input),     \
                                            GetTensorShape(output),           \
                                            GetTensorData<int8_t>(output)))
  return kTfLiteOk;
TfLiteStatus AverageEvalQuantizedInt16(TfLiteContext* context, TfLiteNode* node,
                                       TfLitePoolParams* params, OpData* data,
                                       const TfLiteTensor* input,
                                       TfLiteTensor* output) {
#define TF_LITE_AVERAGE_POOL(type)                                            \
  tflite::PoolParams op_params;                                               \
  op_params.stride_height = params->stride_height;                            \
  op_params.stride_width = params->stride_width;                              \
  op_params.filter_height = params->filter_height;                            \
  op_params.filter_width = params->filter_width;                              \
  op_params.padding_values.height = data->padding.height;                     \
  op_params.padding_values.width = data->padding.width;                       \
  op_params.quantized_activation_min = activation_min;                        \
  op_params.quantized_activation_max = activation_max;                        \
  TF_LITE_ENSURE(context, type::AveragePool(op_params, GetTensorShape(input), \
                                            GetTensorData<int16_t>(input),    \
                                            GetTensorShape(output),           \
                                            GetTensorData<int16_t>(output)))
  return kTfLiteOk;
      return AverageEvalFloat<kernel_type>(context, node, params, data, input,
                                           output);
      return AverageEvalQuantizedUint8<kernel_type>(context, node, params, data,
                                                    input, output);
      return AverageEvalQuantizedInt8<kernel_type>(context, node, params, data,
                                                   input, output);
      return AverageEvalQuantizedInt16<kernel_type>(context, node, params, data,
                                                    input, output);