CVE-2021-37653: Divide By Zero (CWE-369)
value: TensorFlow is an end-to-end open source platform for machine learning. In affected versions an attacker can trigger a crash via a floating point exception in `tf.raw_ops.ResourceGather`. The [implementation](https://github.com/tensorflow/tensorflow/blob/f24faa153ad31a4b51578f8181d3aaab77a1ddeb/tensorflow/core/kernels/resource_variable_ops.cc#L725-L731) computes the value of a value, `batch_size`, and then divides by it without checking that this value is not 0. We have patched the issue in GitHub commit ac117ee8a8ea57b73d34665cdf00ef3303bc0b11. 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 divides a value by zero.
CVSS v3 base score: 5.5
Published: 2021-08-12T18:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/resource_variable_ops.cc
Commit date: 2021-07-30 22:27:12 -0700
Commit message: Prevent division by 0 in `resource_variable_ops.cc`

PiperOrigin-RevId: 387939939
Change-Id: Ib04902d63756633999959a70613f2eaa30c2c151

Diff: diff --git a/tensorflow/core/kernels/resource_variable_ops.cc b/tensorflow/core/kernels/resource_variable_ops.cc
index 32a0a43364dea..8b9610724e582 100644
--- a/tensorflow/core/kernels/resource_variable_ops.cc
+++ b/tensorflow/core/kernels/resource_variable_ops.cc
@@ -708,11 +708,12 @@ class ResourceGatherOp : public OpKernel {
                                            &tmp_indices));
         functor::DenseUpdate<Device, Index, ASSIGN> copy_functor;
         copy_functor(c->eigen_device<Device>(), tmp_indices.flat<Index>(),
                      indices.flat<Index>());
 
-        AddBatchOffsets(&tmp_indices, params);
+        AddBatchOffsets(c, &tmp_indices, params);
+        if (!c->status().ok()) return;
         op_indices = &tmp_indices;
       }
 
       int64_t gather_dim_size = 1;
       for (int idx = 0; idx <= batch_dims_; ++idx) {
@@ -740,15 +741,21 @@ class ResourceGatherOp : public OpKernel {
  private:
   // Add the batch offset derived from params to each batch of indices.
   // Example: batch_dims = 1, indices = [[0, 1, 2], [0, 1, 2]]
   // If indexing into a params dimension of size 4, then the indices will become
   // [0, 1, 2, 4, 5, 6]
-  void AddBatchOffsets(Tensor* indices, const Tensor& params) {
+  void AddBatchOffsets(OpKernelContext* ctx, Tensor* indices,
+                       const Tensor& params) {
     int64_t batch_size = 1;  // The size of all batch dimensions.
     for (int idx = 0; idx < batch_dims_; ++idx) {
       batch_size *= params.dim_size(idx);
     }
+    OP_REQUIRES(
+        ctx, batch_size != 0,
+        errors::InvalidArgument(
+            "Inner size of indices would result in batch_size of 0 and a ",
+            "division by 0 in the implementation. This is illegal"));
 
     auto indices_flat = indices->flat<Index>();
     int64_t const index_inner_size = indices->NumElements() / batch_size;
     int64_t const batch_offset = params.dim_size(batch_dims_);
     for (int64_t batch_idx = 0, dest_idx = 0; batch_idx < batch_size;

Vulnerable code:         AddBatchOffsets(&tmp_indices, params);
  void AddBatchOffsets(Tensor* indices, const Tensor& params) {
Fixed code:         AddBatchOffsets(c, &tmp_indices, params);
        if (!c->status().ok()) return;
  void AddBatchOffsets(OpKernelContext* ctx, Tensor* indices,
                       const Tensor& params) {
    OP_REQUIRES(
        ctx, batch_size != 0,
        errors::InvalidArgument(
            "Inner size of indices would result in batch_size of 0 and a ",
            "division by 0 in the implementation. This is illegal"));