Vulnerability: Heap buffer overflow in `QuantizedMul` ### Impact
An attacker can cause a heap buffer overflow in `QuantizedMul` by passing in invalid thresholds for the quantization:

```python
import tensorflow as tf

x = tf.constant([256, 328], shape=[1, 2], dtype=tf.quint8)
y = tf.constant([256, 328], shape=[1, 2], dtype=tf.quint8)
min_x = tf.constant([], dtype=tf.float32)
max_x = tf.constant([], dtype=tf.float32)
min_y = tf.constant([], dtype=tf.float32)
max_y = tf.constant([], dtype=tf.float32)

tf.raw_ops.QuantizedMul(x=x, y=y, min_x=min_x, max_x=max_x, min_y=min_y, max_y=max_y)
```

This is because the [implementation](https://github.com/tensorflow/tensorflow/blob/87cf4d3ea9949051e50ca3f071fc909538a51cd0/tensorflow/core/kernels/quantized_mul_op.cc#L287-L290) assumes that the 4 arguments are always valid scalars and tries to access the numeric value directly:

```cc 
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);
```

However, if any of these tensors is empty, then `.flat<T>()` is an empty buffer and accessing the element at position 0 results in overflow.

### Patches
We have patched the issue in GitHub commit [efea03b38fb8d3b81762237dc85e579cc5fc6e87](https://github.com/tensorflow/tensorflow/commit/efea03b38fb8d3b81762237dc85e579cc5fc6e87).

The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.

### For more information
Please consult [our security guide](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md) for more information regarding the security model and how to contact us with issues and questions.

### Attribution
This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Vulnerability ID: GHSA-m3f9-w3p3-p669
CWE: CWE-787
Severity score: 2.5
Project: https://github.com/tensorflow/tensorflow
Published: 2021-05-21
File: tensorflow/core/kernels/quantized_mul_op.cc
Commit message: Validate inputs to `QuantizedMul`

PiperOrigin-RevId: 369756982
Change-Id: I00d960cc3b9316fd7a86bd37a44e341c96e17624
Commit author: Mihai Maruseac

Vulnerable version (before fix):
 class QuantizedMulOp : public OpKernel {   void Compute(OpKernelContext* context) override {     const Tensor& x = context->input(0);     const Tensor& y = context->input(1);     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);      BCast bcast(BCast::FromShape(x.shape()), BCast::FromShape(y.shape()));     if (!bcast.IsValid()) {

Fixed version (after fix):
 class QuantizedMulOp : public OpKernel {   void Compute(OpKernelContext* context) override {     const Tensor& x = context->input(0);     const Tensor& y = context->input(1);     auto& min_x_tensor = context->input(2);     OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_x_tensor.shape()),                 errors::InvalidArgument("min_x must be a scalar"));     const float min_x = min_x_tensor.flat<float>()(0);     auto& max_x_tensor = context->input(3);     OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_x_tensor.shape()),                 errors::InvalidArgument("max_x must be a scalar"));     const float max_x = max_x_tensor.flat<float>()(0);     auto& min_y_tensor = context->input(4);     OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_y_tensor.shape()),                 errors::InvalidArgument("min_y must be a scalar"));     const float min_y = min_y_tensor.flat<float>()(0);     auto& max_y_tensor = context->input(5);     OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_y_tensor.shape()),                 errors::InvalidArgument("max_y must be a scalar"));     const float max_y = max_y_tensor.flat<float>()(0);      BCast bcast(BCast::FromShape(x.shape()), BCast::FromShape(y.shape()));     if (!bcast.IsValid()) {

Patch:
patch: @@ -284,10 +284,22 @@ class QuantizedMulOp : public OpKernel {
   void Compute(OpKernelContext* context) override {
     const Tensor& x = context->input(0);
     const Tensor& y = context->input(1);
-    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);
+    auto& min_x_tensor = context->input(2);
+    OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_x_tensor.shape()),
+                errors::InvalidArgument("min_x must be a scalar"));
+    const float min_x = min_x_tensor.flat<float>()(0);
+    auto& max_x_tensor = context->input(3);
+    OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_x_tensor.shape()),
+                errors::InvalidArgument("max_x must be a scalar"));
+    const float max_x = max_x_tensor.flat<float>()(0);
+    auto& min_y_tensor = context->input(4);
+    OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_y_tensor.shape()),
+                errors::InvalidArgument("min_y must be a scalar"));
+    const float min_y = min_y_tensor.flat<float>()(0);
+    auto& max_y_tensor = context->input(5);
+    OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_y_tensor.shape()),
+                errors::InvalidArgument("max_y must be a scalar"));
+    const float max_y = max_y_tensor.flat<float>()(0);
 
     BCast bcast(BCast::FromShape(x.shape()), BCast::FromShape(y.shape()));
     if (!bcast.IsValid()) {
path: tensorflow/core/kernels/quantized_mul_op.cc