CVE-2022-21739: NULL Pointer Dereference (CWE-476)
value: Tensorflow is an Open Source Machine Learning Framework. The implementation of `QuantizedMaxPool` has an undefined behavior where user controlled inputs can trigger a reference binding to null pointer. The fix will be included in TensorFlow 2.8.0. We will also cherrypick this commit on TensorFlow 2.7.1, TensorFlow 2.6.3, and TensorFlow 2.5.3, as these are also affected and still in supported range.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 6.5
Published: 2022-02-03T14:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/quantized_pooling_ops.cc
Commit date: 2021-12-03 10:12:34 -0800
Commit message: Fix nullptr exception in QuantizedMaxPool op when empty list is sent to min_input or max_input parameters.

PiperOrigin-RevId: 413960973
Change-Id: I9e3ded593f3c4eabf0d6d5dc356e6a19a3ad2682

Diff: diff --git a/tensorflow/core/kernels/quantized_pooling_ops.cc b/tensorflow/core/kernels/quantized_pooling_ops.cc
index 17df3c223676a..b512369b3c4dd 100644
--- a/tensorflow/core/kernels/quantized_pooling_ops.cc
+++ b/tensorflow/core/kernels/quantized_pooling_ops.cc
@@ -13,10 +13,12 @@ See the License for the specific language governing permissions and
 limitations under the License.
 ==============================================================================*/
 
 // See docs in ../ops/nn_ops.cc.
 
+#include "tensorflow/core/framework/op_requires.h"
+#include "tensorflow/core/platform/errors.h"
 #define EIGEN_USE_THREADS
 
 #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
 #include "tensorflow/core/framework/numeric_op.h"
 #include "tensorflow/core/framework/op_kernel.h"
@@ -115,10 +117,22 @@ class QuantizedMaxPoolingOp : public MaxPoolingOp<Device, T> {
  public:
   explicit QuantizedMaxPoolingOp(OpKernelConstruction* context)
       : MaxPoolingOp<Device, T>(context) {}
 
   void Compute(OpKernelContext* context) override {
+    auto min_input_tensor = context->input(1);
+    auto max_input_tensor = context->input(2);
+    OP_REQUIRES(
+        context, min_input_tensor.NumElements() == 1,
+        errors::InvalidArgument(
+            "min_input must be a scalar float value, got tensor with shape ",
+            min_input_tensor.shape()));
+    OP_REQUIRES(
+        context, max_input_tensor.NumElements() == 1,
+        errors::InvalidArgument(
+            "max_input must be a scalar float value, got tensor with shape ",
+            max_input_tensor.shape()));
     const float min_input = context->input(1).flat<float>()(0);
     const float max_input = context->input(2).flat<float>()(0);
     MaxPoolingOp<Device, T>::Compute(context);
     Tensor* output_min = nullptr;
     OP_REQUIRES_OK(context, context->allocate_output(1, {}, &output_min));

Fixed code: #include "tensorflow/core/framework/op_requires.h"
#include "tensorflow/core/platform/errors.h"
    auto min_input_tensor = context->input(1);
    auto max_input_tensor = context->input(2);
    OP_REQUIRES(
        context, min_input_tensor.NumElements() == 1,
        errors::InvalidArgument(
            "min_input must be a scalar float value, got tensor with shape ",
            min_input_tensor.shape()));
    OP_REQUIRES(
        context, max_input_tensor.NumElements() == 1,
        errors::InvalidArgument(
            "max_input must be a scalar float value, got tensor with shape ",
            max_input_tensor.shape()));