CVE-2021-29566: Out-of-bounds Write (CWE-787)
value: TensorFlow is an end-to-end open source platform for machine learning. An attacker can write outside the bounds of heap allocated arrays by passing invalid arguments to `tf.raw_ops.Dilation2DBackpropInput`. This is because the implementation(https://github.com/tensorflow/tensorflow/blob/afd954e65f15aea4d438d0a219136fc4a63a573d/tensorflow/core/kernels/dilation_ops.cc#L321-L322) does not validate before writing to the output array. The values for `h_out` and `w_out` are guaranteed to be in range for `out_backprop` (as they are loop indices bounded by the size of the array). However, there are no similar guarantees relating `h_in_max`/`w_in_max` and `in_backprop`. 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.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2021-05-14T20:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/dilation_ops.cc
Commit date: 2021-05-04 18:41:15 -0700
Commit message: Add missing validations in dillation ops.

PiperOrigin-RevId: 372037158
Change-Id: I4ee304c84a02550c030288a6534000b934fc1599

Diff: diff --git a/tensorflow/core/kernels/dilation_ops.cc b/tensorflow/core/kernels/dilation_ops.cc
index 738ea31d555d5..996ddb62bfefe 100644
--- a/tensorflow/core/kernels/dilation_ops.cc
+++ b/tensorflow/core/kernels/dilation_ops.cc
@@ -128,10 +128,11 @@ class DilationOp : public OpKernel {
     int64 pad_top = 0, pad_left = 0;
     int64 out_rows = 0, out_cols = 0;
     ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
                &rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
                &out_cols);
+    if (!context->status().ok()) return;
 
     // Output tensor is of the following dimensions:
     // [ batch, out_rows, out_cols, depth ]
     const int batch = input.dim_size(0);
     const int depth = input.dim_size(3);
@@ -227,10 +228,11 @@ class DilationBackpropInputOp : public OpKernel {
     int64 pad_top = 0, pad_left = 0;
     int64 out_rows = 0, out_cols = 0;
     ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
                &rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
                &out_cols);
+    if (!context->status().ok()) return;
 
     // Verify that the incoming gradient tensor has the expected size
     // [ batch, out_rows, out_cols, depth ]
     const int batch = input.dim_size(0);
     const int depth = input.dim_size(3);
@@ -316,12 +318,14 @@ struct DilationBackpropInput<CPUDevice, T> {
                     }
                   }
                 }
               }
             }
-            in_backprop(b, h_in_max, w_in_max, d) +=
-                out_backprop(b, h_out, w_out, d);
+            if (h_in_max < input_rows && w_in_max < input_cols) {
+              in_backprop(b, h_in_max, w_in_max, d) +=
+                  out_backprop(b, h_out, w_out, d);
+            }
           }
         }
       }
     }
   }
@@ -347,10 +351,11 @@ class DilationBackpropFilterOp : public OpKernel {
     int64 pad_top = 0, pad_left = 0;
     int64 out_rows = 0, out_cols = 0;
     ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
                &rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
                &out_cols);
+    if (!context->status().ok()) return;
 
     // Verify that the incoming gradient tensor has the expected size
     // [ batch, out_rows, out_cols, depth ]
     const int batch = input.dim_size(0);
     const int depth = input.dim_size(3);
@@ -436,12 +441,14 @@ struct DilationBackpropFilter<CPUDevice, T> {
                     }
                   }
                 }
               }
             }
-            filter_backprop(h_max, w_max, d) +=
-                out_backprop(b, h_out, w_out, d);
+            if (h_max < filter_rows && w_max < filter_cols) {
+              filter_backprop(h_max, w_max, d) +=
+                  out_backprop(b, h_out, w_out, d);
+            }
           }
         }
       }
     }
   }

Vulnerable code:             in_backprop(b, h_in_max, w_in_max, d) +=
                out_backprop(b, h_out, w_out, d);
            filter_backprop(h_max, w_max, d) +=
                out_backprop(b, h_out, w_out, d);
Fixed code:     if (!context->status().ok()) return;
    if (!context->status().ok()) return;
            if (h_in_max < input_rows && w_in_max < input_cols) {
              in_backprop(b, h_in_max, w_in_max, d) +=
                  out_backprop(b, h_out, w_out, d);
            }
    if (!context->status().ok()) return;
            if (h_max < filter_rows && w_max < filter_cols) {
              filter_backprop(h_max, w_max, d) +=
                  out_backprop(b, h_out, w_out, d);
            }