CVE-2022-41895: Out-of-bounds Read (CWE-125)
value: TensorFlow is an open source platform for machine learning. If `MirrorPadGrad` is given outsize input `paddings`, TensorFlow will give a heap OOB error. We have patched the issue in GitHub commit 717ca98d8c3bba348ff62281fdf38dcb5ea1ec92. The fix will be included in TensorFlow 2.11. We will also cherrypick this commit on TensorFlow 2.10.1, 2.9.3, and TensorFlow 2.8.4, as these are also affected and still in supported range.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.5
Published: 2022-11-18T22:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: Python
Files changed: tensorflow/core/kernels/image/mirror_pad_op.cc, tensorflow/python/kernel_tests/array_ops/array_ops_test.py
Commit date: 2022-10-12 12:45:24 -0700
Commit message: Adding missing requirement on inputs for MirrorPadGrad op and updating arithmetic to account for int32 padding values.

PiperOrigin-RevId: 480691952

Diff: diff --git a/tensorflow/core/kernels/image/mirror_pad_op.cc b/tensorflow/core/kernels/image/mirror_pad_op.cc
index 9b9ba45251711..b4bf3b3997513 100644
--- a/tensorflow/core/kernels/image/mirror_pad_op.cc
+++ b/tensorflow/core/kernels/image/mirror_pad_op.cc
@@ -295,17 +295,25 @@ class MirrorPadGradOp : public OpKernel {
 
     // Compute the shape of the output tensor, and allocate it.
     TensorShape output_shape;
     typename TTypes<Tpaddings>::ConstMatrix paddings = in1.matrix<Tpaddings>();
     for (int d = 0; d < dims; ++d) {
-      const Tpaddings before = paddings(d, 0);  // Pad before existing elements.
-      const Tpaddings after = paddings(d, 1);   // Pad after existing elements.
+      const int64_t before = paddings(d, 0);  // Pad before existing elements.
+      const int64_t after = paddings(d, 1);   // Pad after existing elements.
       OP_REQUIRES(context, before >= 0 && after >= 0,
                   errors::InvalidArgument(
                       "Paddings must be non-negative: ", before, ", ", after));
 
-      const int64_t out_size = in0.dim_size(d) - (before + after);
+      const int64_t in_size = in0.dim_size(d);
+      const int64_t total_padding = before + after;
+      OP_REQUIRES(
+          context, total_padding < in_size && total_padding >= 0,
+          errors::InvalidArgument(
+              "Total paddings must be less than the input dimension size: ",
+              total_padding, " was not less than ", in_size));
+
+      const int64_t out_size = in_size - total_padding;
       if (offset_ == 0) {  // SYMMETRIC mode.
         OP_REQUIRES(context, before <= out_size && after <= out_size,
                     errors::InvalidArgument("paddings must be no greater "
                                             "than the output dimension size: ",
                                             before, ", ", after,
diff --git a/tensorflow/python/kernel_tests/array_ops/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops/array_ops_test.py
index a9f4180ed4c70..c14703cde3934 100644
--- a/tensorflow/python/kernel_tests/array_ops/array_ops_test.py
+++ b/tensorflow/python/kernel_tests/array_ops/array_ops_test.py
@@ -1615,10 +1615,25 @@ class PadTest(test_util.TensorFlowTestCase):
       padded = array_ops.pad(t, paddings, "CONSTANT")
       self.assertAllEqual(padded.numpy(),
                           [[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 2, 3, 0, 0],
                            [0, 0, 4, 5, 6, 0, 0], [0, 0, 0, 0, 0, 0, 0]])
 
+  # b/246325518: Bad shape size. Explicitly testing different execution paths.
+  def testInvalidMirrorPadGradEagerMode(self):
+    with context.eager_mode():
+      with self.assertRaises(Exception):
+        gen_array_ops.MirrorPadGrad(
+            input=[1], paddings=[[0x77f00000, 0xa000000]], mode="REFLECT")
+
+  # b/246325518: Bad shape size. Explicitly testing different execution paths.
+  def testInvalidMirrorPadGradGraphMode(self):
+    with context.graph_mode():
+      with self.assertRaises(Exception):
+        result = gen_array_ops.MirrorPadGrad(
+            input=[1], paddings=[[0x77f00000, 0xa000000]], mode="REFLECT")
+        self.evaluate(result)
+
   def testSymmetricMirrorPadGrad(self):
     t = np.broadcast_to(np.arange(0, 7), (3, 2, 1, 7))
     paddings = constant_op.constant([
         [1, 1],
         [0, 0],

Vulnerable code:       const Tpaddings before = paddings(d, 0);  // Pad before existing elements.
      const Tpaddings after = paddings(d, 1);   // Pad after existing elements.
      const int64_t out_size = in0.dim_size(d) - (before + after);
Fixed code:       const int64_t before = paddings(d, 0);  // Pad before existing elements.
      const int64_t after = paddings(d, 1);   // Pad after existing elements.
      const int64_t in_size = in0.dim_size(d);
      const int64_t total_padding = before + after;
      OP_REQUIRES(
          context, total_padding < in_size && total_padding >= 0,
          errors::InvalidArgument(
              "Total paddings must be less than the input dimension size: ",
              total_padding, " was not less than ", in_size));

      const int64_t out_size = in_size - total_padding;
  # b/246325518: Bad shape size. Explicitly testing different execution paths.
  def testInvalidMirrorPadGradEagerMode(self):
    with context.eager_mode():
      with self.assertRaises(Exception):
        gen_array_ops.MirrorPadGrad(
            input=[1], paddings=[[0x77f00000, 0xa000000]], mode="REFLECT")

  # b/246325518: Bad shape size. Explicitly testing different execution paths.
  def testInvalidMirrorPadGradGraphMode(self):
    with context.graph_mode():
      with self.assertRaises(Exception):
        result = gen_array_ops.MirrorPadGrad(
            input=[1], paddings=[[0x77f00000, 0xa000000]], mode="REFLECT")
        self.evaluate(result)