CVE-2023-25801: Double Free (CWE-415)
value: TensorFlow is an open source machine learning platform. Prior to versions 2.12.0 and 2.11.1, `nn_ops.fractional_avg_pool_v2` and `nn_ops.fractional_max_pool_v2` require the first and fourth elements of their parameter `pooling_ratio` to be equal to 1.0, as pooling on batch and channel dimensions is not supported. A fix is included in TensorFlow 2.12.0 and 2.11.1.
CWE description: The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations.
CVSS v3 base score: 7.8
Published: 2023-03-25T00:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: Python
Files changed: tensorflow/core/kernels/fractional_avg_pool_op.cc, tensorflow/core/kernels/fractional_max_pool_op.cc, tensorflow/python/kernel_tests/nn_ops/fractional_avg_pool_op_test.py, tensorflow/python/kernel_tests/nn_ops/fractional_max_pool_op_test.py
Commit date: 2023-01-12 13:33:52 -0800
Commit message: Fix security vulnerability with FractionalMax(AVG)Pool with illegal pooling_ratio

PiperOrigin-RevId: 501651261

Diff: diff --git a/tensorflow/core/kernels/fractional_avg_pool_op.cc b/tensorflow/core/kernels/fractional_avg_pool_op.cc
index 18768ddcbc08d..7f8777ff54028 100644
--- a/tensorflow/core/kernels/fractional_avg_pool_op.cc
+++ b/tensorflow/core/kernels/fractional_avg_pool_op.cc
@@ -49,11 +49,11 @@ class FractionalAvgPoolOp : public OpKernel {
                   errors::InvalidArgument(
                       "pooling_ratio cannot be smaller than 1, got: ",
                       pooling_ratio_[i]));
     }
     OP_REQUIRES(
-        context, pooling_ratio_[0] == 1 || pooling_ratio_[3] == 1,
+        context, pooling_ratio_[0] == 1 && pooling_ratio_[3] == 1,
         errors::Unimplemented("Fractional average pooling is not yet "
                               "supported on the batch nor channel dimension."));
     OP_REQUIRES_OK(context, context->GetAttr("deterministic", &deterministic_));
     OP_REQUIRES_OK(context, context->GetAttr("seed", &seed_));
     OP_REQUIRES_OK(context, context->GetAttr("seed2", &seed2_));
diff --git a/tensorflow/core/kernels/fractional_max_pool_op.cc b/tensorflow/core/kernels/fractional_max_pool_op.cc
index ec08b5c502872..1e9238da3bd0f 100644
--- a/tensorflow/core/kernels/fractional_max_pool_op.cc
+++ b/tensorflow/core/kernels/fractional_max_pool_op.cc
@@ -51,11 +51,11 @@ class FractionalMaxPoolOp : public OpKernel {
                       "pooling_ratio cannot be smaller than 1, got: ",
                       pooling_ratio_[i]));
     }
 
     OP_REQUIRES(
-        context, pooling_ratio_[0] == 1 || pooling_ratio_[3] == 1,
+        context, pooling_ratio_[0] == 1 && pooling_ratio_[3] == 1,
         errors::Unimplemented("Fractional max pooling is not yet "
                               "supported on the batch nor channel dimension."));
 
     OP_REQUIRES_OK(context, context->GetAttr("deterministic", &deterministic_));
     OP_REQUIRES_OK(context, context->GetAttr("seed", &seed_));
diff --git a/tensorflow/python/kernel_tests/nn_ops/fractional_avg_pool_op_test.py b/tensorflow/python/kernel_tests/nn_ops/fractional_avg_pool_op_test.py
index 59b20de84b4c4..21c48dd51b9e7 100644
--- a/tensorflow/python/kernel_tests/nn_ops/fractional_avg_pool_op_test.py
+++ b/tensorflow/python/kernel_tests/nn_ops/fractional_avg_pool_op_test.py
@@ -349,11 +349,11 @@ class FractionalAvgTest(test.TestCase):
             seed=0,
             seed2=0,
             name=None)
         self.evaluate(result)
 
-  def testPoolingRatioValueOutOfRange(self):
+  def testPoolingRatioIllegalSmallValue(self):
     with self.cached_session() as _:
       # Whether turn on `TF2_BEHAVIOR` generates different error messages
       with self.assertRaisesRegex(
           (errors.InvalidArgumentError, ValueError),
           r"(pooling_ratio cannot be smaller than 1, got: .*)|(is negative)"):
@@ -366,10 +366,20 @@ class FractionalAvgTest(test.TestCase):
             seed=0,
             seed2=0,
         )
         self.evaluate(result)
 
+  def testPoolingIllegalRatioForBatch(self):
+    with self.cached_session() as _:
+      with self.assertRaises(errors.UnimplementedError):
+        result = nn_ops.gen_nn_ops.fractional_avg_pool(
+            np.zeros([3, 30, 50, 3]),
+            [2, 3, 1.5, 1],
+            True,
+            True)
+        self.evaluate(result)
+
 
 class FractionalAvgPoolGradTest(test.TestCase):
   """Tests for FractionalAvgPoolGrad.
 
   Two types of tests for FractionalAvgPoolGrad.
diff --git a/tensorflow/python/kernel_tests/nn_ops/fractional_max_pool_op_test.py b/tensorflow/python/kernel_tests/nn_ops/fractional_max_pool_op_test.py
index 9102973fa13b5..d1c7c3680e3ce 100644
--- a/tensorflow/python/kernel_tests/nn_ops/fractional_max_pool_op_test.py
+++ b/tensorflow/python/kernel_tests/nn_ops/fractional_max_pool_op_test.py
@@ -336,11 +336,11 @@ class FractionalMaxPoolTest(test.TestCase):
             seed=0,
             seed2=0,
             name=None)
         self.evaluate(result)
 
-  def testPoolingRatioValueOutOfRange(self):
+  def testPoolingRatioIllegalSmallValue(self):
     with self.cached_session() as _:
       # Whether turn on `TF2_BEHAVIOR` generates different error messages
       with self.assertRaisesRegex(
           (errors.InvalidArgumentError, ValueError),
           r"(pooling_ratio cannot be smaller than 1, got: .*)|(is negative)"):
@@ -353,10 +353,20 @@ class FractionalMaxPoolTest(test.TestCase):
             seed=0,
             seed2=0,
         )
         self.evaluate(result)
 
+  def testPoolingIllegalRatioForBatch(self):
+    with self.cached_session() as _:
+      with self.assertRaises(errors.UnimplementedError):
+        result = nn_ops.fractional_max_pool(
+            np.zeros([3, 30, 50, 3]),
+            [2, 3, 1.5, 1],
+            True,
+            True)
+        self.evaluate(result)
+
 
 class FractionalMaxPoolGradTest(test.TestCase):
   """Tests for FractionalMaxPoolGrad.
 
   Two types of tests for FractionalMaxPoolGrad.

Vulnerable code:         context, pooling_ratio_[0] == 1 || pooling_ratio_[3] == 1,
        context, pooling_ratio_[0] == 1 || pooling_ratio_[3] == 1,
  def testPoolingRatioValueOutOfRange(self):
  def testPoolingRatioValueOutOfRange(self):
Fixed code:         context, pooling_ratio_[0] == 1 && pooling_ratio_[3] == 1,
        context, pooling_ratio_[0] == 1 && pooling_ratio_[3] == 1,
  def testPoolingRatioIllegalSmallValue(self):
  def testPoolingIllegalRatioForBatch(self):
    with self.cached_session() as _:
      with self.assertRaises(errors.UnimplementedError):
        result = nn_ops.gen_nn_ops.fractional_avg_pool(
            np.zeros([3, 30, 50, 3]),
            [2, 3, 1.5, 1],
            True,
            True)
        self.evaluate(result)

  def testPoolingRatioIllegalSmallValue(self):
  def testPoolingIllegalRatioForBatch(self):
    with self.cached_session() as _:
      with self.assertRaises(errors.UnimplementedError):
        result = nn_ops.fractional_max_pool(
            np.zeros([3, 30, 50, 3]),
            [2, 3, 1.5, 1],
            True,
            True)
        self.evaluate(result)