CVE-2023-25667 (published 2023-03-25T00:15Z)

TensorFlow is an open source platform for machine learning. Prior to versions 2.12.0 and 2.11.1, integer overflow occurs when `2^31 <= num_frames * height * width * channels < 2^32`, for example Full HD screencast of at least 346 frames. A fix is included in TensorFlow version 2.12.0 and version 2.11.1.\n

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/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: Andrei Pikas
author_date: 2022-10-15 22:26:47+03:00
msg: Fix integer overflow for multiframe gifs.
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: decode_image_op.cc
change_type: ModificationType.MODIFY
diff: @@ -452,12 +452,12 @@ class DecodeImageV2Op : public OpKernel {
     // allocation til after dtype conversion is done. `gif`::Decode` supports
     // uint8 only.
     Tensor* output = nullptr;
-    int buffer_size = 0;
+    ptrdiff_t buffer_size = 0;
     string error_string;
     uint8* buffer = gif::Decode(
         input.data(), input.size(),
         [&](int num_frames, int width, int height, int channels) -> uint8* {
-          buffer_size = num_frames * height * width * channels;
+          buffer_size = ptrdiff_t(num_frames) * height * width * channels;
 
           Status status;
           // By the existing API, we support decoding GIF with `decode_jpeg` or

programming_language: C++
filename: gif_io.cc
change_type: ModificationType.MODIFY
diff: @@ -105,7 +105,7 @@ uint8* Decode(const void* srcdata, int datasize,
   uint8* const dstdata =
       allocate_output(target_num_frames, width, height, channel);
   if (!dstdata) return nullptr;
-  for (int k = 0; k < target_num_frames; k++) {
+  for (ptrdiff_t k = 0; k < target_num_frames; k++) {
     uint8* this_dst = dstdata + k * width * channel * height;
 
     SavedImage* this_image = &gif_file->SavedImages[k];
@@ -125,10 +125,10 @@ uint8* Decode(const void* srcdata, int datasize,
 
     if (k > 0) {
       uint8* last_dst = dstdata + (k - 1) * width * channel * height;
-      for (int i = 0; i < height; ++i) {
+      for (ptrdiff_t i = 0; i < height; ++i) {
         uint8* p_dst = this_dst + i * width * channel;
         uint8* l_dst = last_dst + i * width * channel;
-        for (int j = 0; j < width; ++j) {
+        for (ptrdiff_t j = 0; j < width; ++j) {
           p_dst[j * channel + 0] = l_dst[j * channel + 0];
           p_dst[j * channel + 1] = l_dst[j * channel + 1];
           p_dst[j * channel + 2] = l_dst[j * channel + 2];
@@ -141,9 +141,9 @@ uint8* Decode(const void* srcdata, int datasize,
       // If the first frame does not fill the entire canvas then fill the
       // unoccupied canvas with zeros (black).
       if (k == 0) {
-        for (int i = 0; i < height; ++i) {
+        for (ptrdiff_t i = 0; i < height; ++i) {
           uint8* p_dst = this_dst + i * width * channel;
-          for (int j = 0; j < width; ++j) {
+          for (ptrdiff_t j = 0; j < width; ++j) {
             p_dst[j * channel + 0] = 0;
             p_dst[j * channel + 1] = 0;
             p_dst[j * channel + 2] = 0;
@@ -165,9 +165,9 @@ uint8* Decode(const void* srcdata, int datasize,
       return nullptr;
     }
 
-    for (int i = imgTop; i < imgBottom; ++i) {
+    for (ptrdiff_t i = imgTop; i < imgBottom; ++i) {
       uint8* p_dst = this_dst + i * width * channel;
-      for (int j = imgLeft; j < imgRight; ++j) {
+      for (ptrdiff_t j = imgLeft; j < imgRight; ++j) {
         GifByteType color_index =
             this_image->RasterBits[(i - img_desc->Top) * (img_desc->Width) +
                                    (j - img_desc->Left)];

programming_language: C++
filename: gif_io_test.cc
change_type: ModificationType.MODIFY
diff: @@ -52,7 +52,7 @@ void TestDecodeGif(Env* env, DecodeGifTestCase testcase) {
         w = width;
         h = height;
         c = channels;
-        return new uint8[frame_cnt * height * width * channels];
+        return new uint8[ptrdiff_t(frame_cnt) * height * width * channels];
       },
       &error_string));
   ASSERT_NE(imgdata, nullptr);
@@ -72,7 +72,8 @@ TEST(GifTest, Gif) {
        {testdata_path + "optimized.gif", 12, 20, 40, 3},
        {testdata_path + "red_black.gif", 1, 16, 16, 3},
        {testdata_path + "scan.gif", 12, 20, 40, 3},
-       {testdata_path + "squares.gif", 2, 16, 16, 3}});
+       {testdata_path + "squares.gif", 2, 16, 16, 3},
+       {testdata_path + "3g_multiframe.gif", 519, 1920, 1080, 3}});
 
   for (const auto& tc : testcases) {
     TestDecodeGif(env, tc);

programming_language: C++
filename: BUILD
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,7 @@ filegroup(
         "scan.gif",
         "red_black.gif",
         "squares.gif",
+        "3g_multiframe.gif",
         "pendulum_sm.gif",
         # Add groundtruth frames for `pendulum_sm.gif`.
         # PNG format because it's lossless.

programming_language: Ruby