CVE-2022-23560: Out-of-bounds Write (CWE-787)
value: Tensorflow is an Open Source Machine Learning Framework. An attacker can craft a TFLite model that would allow limited reads and writes outside of arrays in TFLite. This exploits missing validation in the conversion from sparse tensors to dense tensors. The fix is included in TensorFlow 2.8.0. We will also cherrypick this commit on TensorFlow 2.7.1, TensorFlow 2.6.3, and TensorFlow 2.5.3, as these are also affected and still in supported range. Users are advised to upgrade as soon as possible.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 8.8
Published: 2022-02-04T23:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/lite/kernels/internal/utils/sparsity_format_converter.cc
Commit date: 2021-12-16 15:46:23 -0800
Commit message: [lite] Add some safety checks to avoid out of bound access for sparsity format

PiperOrigin-RevId: 416910386
Change-Id: Ic0b4dc048dc4b5a6309c572b8c4c9f776e4db60a

Diff: diff --git a/tensorflow/lite/kernels/internal/utils/sparsity_format_converter.cc b/tensorflow/lite/kernels/internal/utils/sparsity_format_converter.cc
index 22aa5d019e739..0595d49365c38 100644
--- a/tensorflow/lite/kernels/internal/utils/sparsity_format_converter.cc
+++ b/tensorflow/lite/kernels/internal/utils/sparsity_format_converter.cc
@@ -280,14 +280,16 @@ void FormatConverter<T>::InitSparseToDenseConverter(
 
   blocked_shape_.resize(original_rank);
   block_size_.resize(block_map_.size());
   for (int i = 0; i < original_rank; i++) {
     if (block_dim < block_map_.size() && block_map_[block_dim] == i) {
-      int orig_dim = traversal_order_[original_rank + block_dim];
-      block_size_[block_dim] = dense_size[orig_dim];
-      blocked_shape_[i] = dense_shape_[i] / dense_size[orig_dim];
-      block_dim++;
+      if (original_rank + block_dim < traversal_order_.size()) {
+        int orig_dim = traversal_order_[original_rank + block_dim];
+        block_size_[block_dim] = dense_size[orig_dim];
+        blocked_shape_[i] = dense_shape_[i] / dense_size[orig_dim];
+        block_dim++;
+      }
     } else {
       blocked_shape_[i] = dense_shape_[i];
     }
   }
 }
@@ -326,17 +328,19 @@ void FormatConverter<T>::Populate(const T* src_data, std::vector<int> indices,
     for (int i = 0; i < shape_of_level; i++) {
       indices[level] = i;
       Populate(src_data, indices, level + 1, prev_idx * shape_of_level + i,
                src_data_ptr, dest_data);
     }
-  } else {
+  } else if (prev_idx + 1 < dim_metadata_[metadata_idx].size()) {
     const auto& array_segments = dim_metadata_[metadata_idx];
     const auto& array_indices = dim_metadata_[metadata_idx + 1];
     for (int i = array_segments[prev_idx]; i < array_segments[prev_idx + 1];
          i++) {
-      indices[level] = array_indices[i];
-      Populate(src_data, indices, level + 1, i, src_data_ptr, dest_data);
+      if (i < array_indices.size() && level < indices.size()) {
+        indices[level] = array_indices[i];
+        Populate(src_data, indices, level + 1, i, src_data_ptr, dest_data);
+      }
     }
   }
 }
 
 template <typename T>

Vulnerable code:       int orig_dim = traversal_order_[original_rank + block_dim];
      block_size_[block_dim] = dense_size[orig_dim];
      blocked_shape_[i] = dense_shape_[i] / dense_size[orig_dim];
      block_dim++;
  } else {
      indices[level] = array_indices[i];
      Populate(src_data, indices, level + 1, i, src_data_ptr, dest_data);
Fixed code:       if (original_rank + block_dim < traversal_order_.size()) {
        int orig_dim = traversal_order_[original_rank + block_dim];
        block_size_[block_dim] = dense_size[orig_dim];
        blocked_shape_[i] = dense_shape_[i] / dense_size[orig_dim];
        block_dim++;
      }
  } else if (prev_idx + 1 < dim_metadata_[metadata_idx].size()) {
      if (i < array_indices.size() && level < indices.size()) {
        indices[level] = array_indices[i];
        Populate(src_data, indices, level + 1, i, src_data_ptr, dest_data);
      }