CVE-2021-37674: Improper Validation of Specified Quantity in Input (CWE-1284)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions an attacker can trigger a denial of service via a segmentation fault in `tf.raw_ops.MaxPoolGrad` caused by missing validation. The [implementation](https://github.com/tensorflow/tensorflow/blob/460e000de3a83278fb00b61a16d161b1964f15f4/tensorflow/core/kernels/maxpooling_op.cc) misses some validation for the `orig_input` and `orig_output` tensors. The fixes for CVE-2021-29579 were incomplete. We have patched the issue in GitHub commit 136b51f10903e044308cf77117c0ed9871350475. 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.
CWE description: The product receives input that is expected to specify a quantity (such as size or length), but it does not validate or incorrectly validates that the quantity has the required properties.
CVSS v3 base score: 5.5
Published: 2021-08-12T23:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/maxpooling_op.cc, tensorflow/core/kernels/pooling_ops_common.cc
Commit date: 2021-07-30 20:55:05 -0700
Commit message: Add missing validation to `maxpooling_op.cc`

PiperOrigin-RevId: 387932441
Change-Id: I43a0b24e6a12cc965611144ba035accd384594b9

Diff: diff --git a/tensorflow/core/kernels/maxpooling_op.cc b/tensorflow/core/kernels/maxpooling_op.cc
index 8119b7fddf604..749b9c1d995eb 100644
--- a/tensorflow/core/kernels/maxpooling_op.cc
+++ b/tensorflow/core/kernels/maxpooling_op.cc
@@ -72,10 +72,11 @@ static void SpatialMaxPoolWithArgMaxHelper(
     OP_REQUIRES(
         context, (std::is_same<Targmax, int64>::value),
         errors::Internal("SpatialMaxPoolWithArgMaxHelper requires Targmax "
                          "to be int64 when input_backprop != nullptr"));
   }
+  if (tensor_in.NumElements() == 0 || output->NumElements() == 0) return;
 
   typedef Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
       ConstEigenMatrixMap;
   typedef Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
       EigenMatrixMap;
@@ -947,10 +948,14 @@ class MaxPoolingWithArgmaxOp : public OpKernel {
                                    &propagate_nans_));
   }
 
   void Compute(OpKernelContext* context) override {
     const Tensor& tensor_in = context->input(0);
+    OP_REQUIRES(context, tensor_in.dims() == 4,
+                errors::InvalidArgument("tensor_in must be 4-dimensional (2)"));
+    OP_REQUIRES(context, tensor_in.NumElements() > 0,
+                errors::InvalidArgument("tensor_in must not be empty (2)"));
 
     PoolParameters params{context,
                           ksize_,
                           stride_,
                           padding_,
diff --git a/tensorflow/core/kernels/pooling_ops_common.cc b/tensorflow/core/kernels/pooling_ops_common.cc
index 5e204520691ab..5bdaa6f5ff518 100644
--- a/tensorflow/core/kernels/pooling_ops_common.cc
+++ b/tensorflow/core/kernels/pooling_ops_common.cc
@@ -169,10 +169,12 @@ PoolParameters::PoolParameters(OpKernelContext* context,
                                 tensor_in_cols, window_cols, col_stride,
                                 padding, &out_width, &pad_left, &pad_right));
     pad_depth = 0;
     out_depth = depth;
   } else {
+    OP_REQUIRES(context, depth_window > 0,
+                errors::InvalidArgument("depth_window must not be 0"));
     // Our current version of depthwise max pooling does not support
     // any padding, and expects the depth_window to equal the
     // depth_stride (no overlapping).
     OP_REQUIRES(
         context, depth % depth_window == 0,

Fixed code:   if (tensor_in.NumElements() == 0 || output->NumElements() == 0) return;
    OP_REQUIRES(context, tensor_in.dims() == 4,
                errors::InvalidArgument("tensor_in must be 4-dimensional (2)"));
    OP_REQUIRES(context, tensor_in.NumElements() > 0,
                errors::InvalidArgument("tensor_in must not be empty (2)"));
    OP_REQUIRES(context, depth_window > 0,
                errors::InvalidArgument("depth_window must not be 0"));