CVE-2022-21733 (published 2022-02-03T12:15Z)

Tensorflow is an Open Source Machine Learning Framework. The implementation of `StringNGrams` can be used to trigger a denial of service attack by causing an out of memory condition after an integer overflow. We are missing a validation on `pad_witdh` and that result in computing a negative value for `ngram_width` which is later used to allocate parts of the output. The fix will be 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.

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

Weakness information:
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/tensorflow/tensorflow
commit_details: repo_url: https://github.com/tensorflow/tensorflow
author: Isha Arkatkar
author_date: 2021-11-30 16:49:30-08:00
msg: Add a check for pad width to be a positive value.

PiperOrigin-RevId: 413275853
Change-Id: I261a8db9dabf5ce48a806a9e58129080c9fac619
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: string_ngrams_op.cc
change_type: ModificationType.MODIFY
diff: @@ -152,6 +152,16 @@ class StringNGramsOp : public tensorflow::OpKernel {
         // We don't have to worry about dynamic padding sizes here: if padding
         // was dynamic, every sequence would have had sufficient padding to
         // generate at least one ngram.
+
+        // If reached here, pad_width should be > 0, pad_width_ = -1,
+        // which indicates max(ngram_widths) - 1 cannot be used here since
+        // ngram_width is not known.
+        OP_REQUIRES(
+            context, pad_width_ >= 0,
+            errors::InvalidArgument("Pad width should be >= 0 when "
+                                    "preserve_short_sequences is True and "
+                                    "ngram_widths are not provided, got ",
+                                    pad_width_));
         int ngram_width = data_length + 2 * pad_width_;
         auto output_start = &ngrams_data[output_start_idx];
         int num_ngrams = 1;

programming_language: C++
filename: raw_ops_test.py
change_type: ModificationType.MODIFY
diff: @@ -28,7 +28,6 @@ from tensorflow.python.platform import test
 
 
 @test_util.run_all_in_graph_and_eager_modes
-@test_util.disable_tfrt
 class RawOpsTest(test.TestCase, parameterized.TestCase):
 
   def testSimple(self):
@@ -63,8 +62,9 @@ class RawOpsTest(test.TestCase, parameterized.TestCase):
   @parameterized.parameters([[0, 8]], [[-1, 6]])
   def testStringNGramsBadDataSplits(self, splits):
     data = ["aa", "bb", "cc", "dd", "ee", "ff"]
-    with self.assertRaisesRegex(errors.InvalidArgumentError,
-                                "Invalid split value"):
+    with self.assertRaisesRegex(
+        errors.InvalidArgumentError,
+        r"Invalid split value|First split value must be 0"):
       self.evaluate(
           gen_string_ops.string_n_grams(
               data=data,
@@ -76,6 +76,25 @@ class RawOpsTest(test.TestCase, parameterized.TestCase):
               pad_width=0,
               preserve_short_sequences=False))
 
+  def testStringSplit(self):
+    data = ["123456"]
+    data_splits = [0, 1]
+    separator = "a" * 15
+    ngram_widths = []
+    pad_width = -5
+    left_pad = right_pad = ""
+    with self.assertRaisesRegex(errors.InvalidArgumentError,
+                                "Pad width should be >= 0"):
+      self.evaluate(gen_string_ops.string_n_grams(
+          data=data,
+          data_splits=data_splits,
+          separator=separator,
+          ngram_widths=ngram_widths,
+          left_pad=left_pad,
+          right_pad=right_pad,
+          pad_width=pad_width,
+          preserve_short_sequences=True))
+
   def testGetSessionHandle(self):
     if context.executing_eagerly():
       with self.assertRaisesRegex(

programming_language: Python