2ab6fb
From 22eb3dc56d8cb71af2c2d413ae587cc401704780 Mon Sep 17 00:00:00 2001
2ab6fb
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
2ab6fb
Date: Wed, 18 May 2022 11:24:37 +0300
2ab6fb
Subject: [PATCH 2/4] matroskademux: Fix integer overflows in zlib/bz2/etc
2ab6fb
 decompression code
2ab6fb
2ab6fb
Various variables were of smaller types than needed and there were no
2ab6fb
checks for any overflows when doing additions on the sizes. This is all
2ab6fb
checked now.
2ab6fb
2ab6fb
In addition the size of the decompressed data is limited to 120MB now as
2ab6fb
any larger sizes are likely pathological and we can avoid out of memory
2ab6fb
situations in many cases like this.
2ab6fb
2ab6fb
Also fix a bug where the available output size on the next iteration in
2ab6fb
the zlib/bz2 decompression code was provided too large and could
2ab6fb
potentially lead to out of bound writes.
2ab6fb
2ab6fb
Thanks to Adam Doupe for analyzing and reporting the issue.
2ab6fb
2ab6fb
CVE: CVE-2022-1922, CVE-2022-1923, CVE-2022-1924, CVE-2022-1925
2ab6fb
2ab6fb
https://gstreamer.freedesktop.org/security/sa-2022-0002.html
2ab6fb
2ab6fb
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1225
2ab6fb
2ab6fb
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2610>
2ab6fb
---
2ab6fb
 gst/matroska/matroska-read-common.c | 76 +++++++++++++++++++++++------
2ab6fb
 1 file changed, 61 insertions(+), 15 deletions(-)
2ab6fb
2ab6fb
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
2ab6fb
index 90d6e38e17..0ee9a787a4 100644
2ab6fb
--- a/gst/matroska/matroska-read-common.c
2ab6fb
+++ b/gst/matroska/matroska-read-common.c
2ab6fb
@@ -70,6 +70,10 @@ typedef struct
2ab6fb
   gboolean audio_only;
2ab6fb
 } TargetTypeContext;
2ab6fb
 
2ab6fb
+/* 120MB as maximum decompressed data size. Anything bigger is likely
2ab6fb
+ * pathological, and like this we avoid out of memory situations in many cases
2ab6fb
+ */
2ab6fb
+#define MAX_DECOMPRESS_SIZE (120 * 1024 * 1024)
2ab6fb
 
2ab6fb
 static gboolean
2ab6fb
 gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
@@ -77,19 +81,23 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
     GstMatroskaTrackCompressionAlgorithm algo)
2ab6fb
 {
2ab6fb
   guint8 *new_data = NULL;
2ab6fb
-  guint new_size = 0;
2ab6fb
+  gsize new_size = 0;
2ab6fb
   guint8 *data = *data_out;
2ab6fb
-  guint size = *size_out;
2ab6fb
+  const gsize size = *size_out;
2ab6fb
   gboolean ret = TRUE;
2ab6fb
 
2ab6fb
+  if (size > G_MAXUINT32) {
2ab6fb
+    GST_WARNING ("too large compressed data buffer.");
2ab6fb
+    ret = FALSE;
2ab6fb
+    goto out;
2ab6fb
+  }
2ab6fb
+
2ab6fb
   if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
2ab6fb
 #ifdef HAVE_ZLIB
2ab6fb
     /* zlib encoded data */
2ab6fb
     z_stream zstream;
2ab6fb
-    guint orig_size;
2ab6fb
     int result;
2ab6fb
 
2ab6fb
-    orig_size = size;
2ab6fb
     zstream.zalloc = (alloc_func) 0;
2ab6fb
     zstream.zfree = (free_func) 0;
2ab6fb
     zstream.opaque = (voidpf) 0;
2ab6fb
@@ -99,8 +107,8 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
       goto out;
2ab6fb
     }
2ab6fb
     zstream.next_in = (Bytef *) data;
2ab6fb
-    zstream.avail_in = orig_size;
2ab6fb
-    new_size = orig_size;
2ab6fb
+    zstream.avail_in = size;
2ab6fb
+    new_size = size;
2ab6fb
     new_data = g_malloc (new_size);
2ab6fb
     zstream.avail_out = new_size;
2ab6fb
     zstream.next_out = (Bytef *) new_data;
2ab6fb
@@ -114,10 +122,18 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
         break;
2ab6fb
       }
2ab6fb
 
2ab6fb
+      if (new_size > G_MAXSIZE - 4096 || new_size + 4096 > MAX_DECOMPRESS_SIZE) {
2ab6fb
+        GST_WARNING ("too big decompressed data");
2ab6fb
+        result = Z_MEM_ERROR;
2ab6fb
+        break;
2ab6fb
+      }
2ab6fb
+
2ab6fb
       new_size += 4096;
2ab6fb
       new_data = g_realloc (new_data, new_size);
2ab6fb
       zstream.next_out = (Bytef *) (new_data + zstream.total_out);
2ab6fb
-      zstream.avail_out += 4096;
2ab6fb
+      /* avail_out is an unsigned int */
2ab6fb
+      g_assert (new_size - zstream.total_out <= G_MAXUINT);
2ab6fb
+      zstream.avail_out = new_size - zstream.total_out;
2ab6fb
     } while (zstream.avail_in > 0);
2ab6fb
 
2ab6fb
     if (result != Z_STREAM_END) {
2ab6fb
@@ -137,13 +153,11 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
 #ifdef HAVE_BZ2
2ab6fb
     /* bzip2 encoded data */
2ab6fb
     bz_stream bzstream;
2ab6fb
-    guint orig_size;
2ab6fb
     int result;
2ab6fb
 
2ab6fb
     bzstream.bzalloc = NULL;
2ab6fb
     bzstream.bzfree = NULL;
2ab6fb
     bzstream.opaque = NULL;
2ab6fb
-    orig_size = size;
2ab6fb
 
2ab6fb
     if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) {
2ab6fb
       GST_WARNING ("bzip2 initialization failed.");
2ab6fb
@@ -152,8 +166,8 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
     }
2ab6fb
 
2ab6fb
     bzstream.next_in = (char *) data;
2ab6fb
-    bzstream.avail_in = orig_size;
2ab6fb
-    new_size = orig_size;
2ab6fb
+    bzstream.avail_in = size;
2ab6fb
+    new_size = size;
2ab6fb
     new_data = g_malloc (new_size);
2ab6fb
     bzstream.avail_out = new_size;
2ab6fb
     bzstream.next_out = (char *) new_data;
2ab6fb
@@ -167,17 +181,31 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
         break;
2ab6fb
       }
2ab6fb
 
2ab6fb
+      if (new_size > G_MAXSIZE - 4096 || new_size + 4096 > MAX_DECOMPRESS_SIZE) {
2ab6fb
+        GST_WARNING ("too big decompressed data");
2ab6fb
+        result = BZ_MEM_ERROR;
2ab6fb
+        break;
2ab6fb
+      }
2ab6fb
+
2ab6fb
       new_size += 4096;
2ab6fb
       new_data = g_realloc (new_data, new_size);
2ab6fb
-      bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
2ab6fb
-      bzstream.avail_out += 4096;
2ab6fb
+      bzstream.next_out =
2ab6fb
+          (char *) (new_data + ((guint64) bzstream.total_out_hi32 << 32) +
2ab6fb
+          bzstream.total_out_lo32);
2ab6fb
+      /* avail_out is an unsigned int */
2ab6fb
+      g_assert (new_size - ((guint64) bzstream.total_out_hi32 << 32) +
2ab6fb
+          bzstream.total_out_lo32 <= G_MAXUINT);
2ab6fb
+      bzstream.avail_out =
2ab6fb
+          new_size - ((guint64) bzstream.total_out_hi32 << 32) +
2ab6fb
+          bzstream.total_out_lo32;
2ab6fb
     } while (bzstream.avail_in > 0);
2ab6fb
 
2ab6fb
     if (result != BZ_STREAM_END) {
2ab6fb
       ret = FALSE;
2ab6fb
       g_free (new_data);
2ab6fb
     } else {
2ab6fb
-      new_size = bzstream.total_out_lo32;
2ab6fb
+      new_size =
2ab6fb
+          ((guint64) bzstream.total_out_hi32 << 32) + bzstream.total_out_lo32;
2ab6fb
     }
2ab6fb
     BZ2_bzDecompressEnd (&bzstream);
2ab6fb
 
2ab6fb
@@ -189,7 +217,13 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
   } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
2ab6fb
     /* lzo encoded data */
2ab6fb
     int result;
2ab6fb
-    int orig_size, out_size;
2ab6fb
+    gint orig_size, out_size;
2ab6fb
+
2ab6fb
+    if (size > G_MAXINT) {
2ab6fb
+      GST_WARNING ("too large compressed data buffer.");
2ab6fb
+      ret = FALSE;
2ab6fb
+      goto out;
2ab6fb
+    }
2ab6fb
 
2ab6fb
     orig_size = size;
2ab6fb
     out_size = size;
2ab6fb
@@ -203,6 +237,11 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
       result = lzo1x_decode (new_data, &out_size, data, &orig_size);
2ab6fb
 
2ab6fb
       if (orig_size > 0) {
2ab6fb
+        if (new_size > G_MAXINT - 4096 || new_size + 4096 > MAX_DECOMPRESS_SIZE) {
2ab6fb
+          GST_WARNING ("too big decompressed data");
2ab6fb
+          result = LZO_ERROR;
2ab6fb
+          break;
2ab6fb
+        }
2ab6fb
         new_size += 4096;
2ab6fb
         new_data = g_realloc (new_data, new_size);
2ab6fb
       }
2ab6fb
@@ -221,6 +260,13 @@ gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
2ab6fb
   } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
2ab6fb
     /* header stripped encoded data */
2ab6fb
     if (enc->comp_settings_length > 0) {
2ab6fb
+      if (size > G_MAXSIZE - enc->comp_settings_length
2ab6fb
+          || size + enc->comp_settings_length > MAX_DECOMPRESS_SIZE) {
2ab6fb
+        GST_WARNING ("too big decompressed data");
2ab6fb
+        ret = FALSE;
2ab6fb
+        goto out;
2ab6fb
+      }
2ab6fb
+
2ab6fb
       new_data = g_malloc (size + enc->comp_settings_length);
2ab6fb
       new_size = size + enc->comp_settings_length;
2ab6fb
 
2ab6fb
-- 
2ab6fb
2.38.1
2ab6fb