CVE-2022-35967 (C++, published 2022-09-16T21:15Z)
Description: value: TensorFlow is an open source platform for machine learning. If `QuantizedAdd` is given `min_input` or `max_input` tensors of a nonzero rank, it results in a segfault that can be used to trigger a denial of service attack. We have patched the issue in GitHub commit 49b3824d83af706df0ad07e4e677d88659756d89. 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: 7.5)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/tensorflow/tensorflow
Files changed:
tensorflow/core/kernels/quantized_activation_ops.cc
tensorflow/core/kernels/quantized_activation_ops_test.cc
tensorflow/core/kernels/quantized_add_op.cc
tensorflow/python/kernel_tests/quantization_ops/quantization_ops_test.py
Commit message: Add IsScalar (rank == 0) check to min/max input tensors for QuantizedAdd/Relu/Relu6 op.

PiperOrigin-RevId: 461902847


Vulnerable code:
    const float min_input = context->input(1).flat<float>()(0);
    const float max_input = context->input(2).flat<float>()(0);
    const float min_input = context->input(1).flat<float>()(0);
    const float max_input = context->input(2).flat<float>()(0);
  AddInputFromArray<float>(TensorShape({1}), {input_min});
  AddInputFromArray<float>(TensorShape({1}), {input_max});
  AddInputFromArray<float>(TensorShape({1}), {input_min});
  AddInputFromArray<float>(TensorShape({1}), {input_max});
    const float min_x = context->input(2).flat<float>()(0);
    const float max_x = context->input(3).flat<float>()(0);
    const float min_y = context->input(4).flat<float>()(0);
    const float max_y = context->input(5).flat<float>()(0);

Fixed code:
    const Tensor& min_input_tensor = context->input(1);
    const Tensor& max_input_tensor = context->input(2);

    OP_REQUIRES(
        context, TensorShapeUtils::IsScalar(min_input_tensor.shape()),
        errors::InvalidArgument("`min_input` must be rank 0 but is rank ",
                                min_input_tensor.dims()));
    OP_REQUIRES(
        context, TensorShapeUtils::IsScalar(max_input_tensor.shape()),
        errors::InvalidArgument("`max_input` must be rank 0 but is rank ",
                                max_input_tensor.dims()));

    const float min_input = min_input_tensor.scalar<float>()();
    const float max_input = max_input_tensor.scalar<float>()();

    const Tensor& min_input_tensor = context->input(1);
    const Tensor& max_input_tensor = context->input(2);

    OP_REQUIRES(
        context, TensorShapeUtils::IsScalar(min_input_tensor.shape()),
        errors::InvalidArgument("`min_input` must be rank 0 but is rank ",
                                min_input_tensor.dims()));
    OP_REQUIRES(
        context, TensorShapeUtils::IsScalar(max_input_tensor.shape()),
        errors::InvalidArgument("`max_input` must be rank 0 but is rank ",
                                max_input_tensor.dims()));

    const float min_input = min_input_tensor.scalar<float>()();
    const float max_input = max_input_tensor.scalar<float>()();

  AddInputFromArray<float>(TensorShape({}), {input_min});
  AddInputFromArray<float>(TensorShape({}), {input_max});
  AddInputFromArray<float>(TensorShape({}), {input_min});
  AddInputFromArray<float>(TensorShape({}), {input_max});
#include "tensorflow/core/framework/tensor_shape.h"
    const Tensor& min_x_tensor = context->input(2);
    const Tensor& max_x_tensor = context->input(3);
    const Tensor& min_y_tensor = context->input(4);
    const Tensor& max_y_tensor = context->input(5);

    OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_x_tensor.shape()),
                errors::InvalidArgument("`min_x` must be rank 0 but is rank ",
                                        min_x_tensor.dims()));
    OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_x_tensor.shape()),
                errors::InvalidArgument("`max_x` must be rank 0 but is rank ",
                                        max_x_tensor.dims()));
    OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_y_tensor.shape()),
                errors::InvalidArgument("`min_y` must be rank 0 but is rank ",
                                        min_y_tensor.dims()));
    OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_y_tensor.shape()),
                errors::InvalidArgument("`max_y` must be rank 0 but is rank ",
                                        max_y_tensor.dims()));

    const float min_x = min_x_tensor.scalar<float>()();
    const float max_x = max_x_tensor.scalar<float>()();
    const float min_y = min_y_tensor.scalar<float>()();
    const float max_y = max_y_tensor.scalar<float>()();
class QuantizedAddOpTest(test_util.TensorFlowTestCase):

  @test_util.run_in_graph_and_eager_modes
  def test_invalid_inputs(self):
    x = constant_op.constant(
        np.int8(0), shape=[3, 3, 3, 3], dtype=dtypes.quint8)
    y = constant_op.constant(np.int8(0), shape=[3], dtype=dtypes.quint8)

    with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
                                "must be rank 0"):
      self.evaluate(
          math_ops.quantized_add(
              x=x,
              y=y,
              min_x=[],
              max_x=1.0,
              min_y=0.0,
              max_y=1.0,
              Toutput=dtypes.qint32))


class QuantizedReluOpTest(test_util.TensorFlowTestCase):

  @test_util.run_in_graph_and_eager_modes
  def test_invalid_inputs(self):
    inputs = constant_op.constant(
        np.int8(0), shape=[3, 3, 3, 3], dtype=dtypes.quint8)

    with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
                                "must be rank 0"):
      self.evaluate(
          nn_ops.quantized_relu(
              features=inputs,
              min_features=[],
              max_features=127.0,
              out_type=dtypes.quint8))


class QuantizedRelu6OpTest(test_util.TensorFlowTestCase):

  @test_util.run_in_graph_and_eager_modes
  def test_invalid_inputs(self):
    inputs = constant_op.constant(
        np.int8(0), shape=[3, 3, 3, 3], dtype=dtypes.quint8)

    with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
                                "must be rank 0"):
      self.evaluate(
          nn_ops.quantized_relu6(
              features=inputs,
              min_features=[],
              max_features=127.0,
              out_type=dtypes.quint8))