CVE-2022-29210 (published 2022-05-21T00:15Z)

TensorFlow is an open source platform for machine learning. In version 2.8.0, the `TensorKey` hash function used total estimated `AllocatedBytes()`, which (a) is an estimate per tensor, and (b) is a very poor hash function for constants (e.g. `int32_t`). It also tried to access individual tensor bytes through `tensor.data()` of size `AllocatedBytes()`. This led to ASAN failures because the `AllocatedBytes()` is an estimate of total bytes allocated by a tensor, including any pointed-to constructs (e.g. strings), and does not refer to contiguous bytes in the `.data()` buffer. The discoverers could not use this byte vector anyway because types such as `tstring` include pointers, whereas they needed to hash the string values themselves. This issue is patched in Tensorflow versions 2.9.0 and 2.8.1.

Severity: LOW
CVSS v2 base score: 2.1 (AV:L/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/tensorflow/tensorflow
commit_details: repo_url: https://github.com/tensorflow/tensorflow
author: Antonio Sanchez
author_date: 2022-05-03 12:47:21-07:00
msg: Fix TensorKey hash function.

The original hash function only used total estimated `AllocatedBytes()`, which (a) is an estimate per tensor, and (b) is a very poor hash function for constants (e.g. `int32_t`).
It also tried to access individual tensor bytes through `tensor.data()` of size `AllocatedBytes()`.  This led to ASAN failures because the `AllocatedBytes()` is an estimate of total bytes allocated by a tensor, including any pointed-to constructs (e.g. strings), and does not refer to contiguous bytes in the `.data()` buffer.  We couldn't use this byte vector anyways, since types like `tstring` include pointers, whereas we need to hash the string values themselves.

Modified the hash function to more closely mirror the `==` operator.  This correctly handles `tstring` and any numeric types that do have contiguous storage.  Other types are currently left as unimplemented.

PiperOrigin-RevId: 446265413
repository: repo_url: https://github.com/tensorflow/tensorflow
repo_name: tensorflow/tensorflow
description: An Open Source Machine Learning Framework for Everyone
repo_language: C++
owner: tensorflow
file_changes: filename: tensor_key.h
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,7 @@ limitations under the License.
 #define TENSORFLOW_CORE_FRAMEWORK_TENSOR_KEY_H_
 
 #include "tensorflow/core/framework/tensor.h"
+#include "tensorflow/core/framework/types.h"
 
 namespace tensorflow {
 
@@ -32,8 +33,7 @@ class TensorKey : public Tensor {
     }
     if (DataTypeCanUseMemcpy(t1.dtype())) {
       return t1.tensor_data() == t2.tensor_data();
-    }
-    if (t1.dtype() == DT_STRING) {
+    } else if (t1.dtype() == DT_STRING) {
       const auto s1 = t1.unaligned_flat<tstring>();
       const auto s2 = t2.unaligned_flat<tstring>();
       for (int64_t i = 0, n = t1.NumElements(); i < n; ++i) {
@@ -42,6 +42,9 @@ class TensorKey : public Tensor {
         }
       }
       return true;
+    } else {
+      DCHECK(false) << "Unimplemented dtype " << DataTypeString(t1.dtype())
+                    << std::endl;
     }
     return false;
   }
@@ -53,14 +56,19 @@ class TensorKey : public Tensor {
   // Needed for absl hash function.
   template <typename H>
   friend H AbslHashValue(H h, const TensorKey& k) {
-    const uint8* d = static_cast<uint8*>(k.data());
-    size_t s = k.AllocatedBytes();
-    std::vector<uint8> vec;
-    vec.reserve(s);
-    for (int i = 0; i < s; i++) {
-      vec.push_back(d[i]);
+    if (DataTypeCanUseMemcpy(k.dtype())) {
+      return H::combine(std::move(h), k.tensor_data());
+    } else if (k.dtype() == DT_STRING) {
+      const auto strs = k.unaligned_flat<tstring>();
+      for (int64_t i = 0, n = k.NumElements(); i < n; ++i) {
+        h = H::combine(std::move(h), strs(i));
+      }
+      return h;
+    } else {
+      DCHECK(false) << "Unimplemented dtype " << DataTypeString(k.dtype())
+                    << std::endl;
     }
-    return H::combine(std::move(h), s);
+    return h;
   }
 };
 

programming_language: C++
filename: BUILD
change_type: ModificationType.MODIFY
diff: @@ -165,8 +165,6 @@ tf_py_test(
     grpc_enabled = True,
     tags = [
         "no_windows",  # TODO(b/192259628)
-        "noasan",  # TODO(b/164696004)
-        "notsan",  # TODO(b/164696004)
     ],
     deps = [
         "//tensorflow/python:array_ops",

programming_language: Python