Blame SOURCES/9efd93e20dd7789e4172ad6c8f4108271b3fb1ee.patch

5cc3f7
From 9efd93e20dd7789e4172ad6c8f4108271b3fb1ee Mon Sep 17 00:00:00 2001
5cc3f7
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
5cc3f7
Date: Thu, 4 Mar 2021 13:05:19 +0200
5cc3f7
Subject: [PATCH] matroskademux: Fix extraction of multichannel WavPack
5cc3f7
5cc3f7
The old code had a couple of issues that all lead to potential memory
5cc3f7
safety bugs.
5cc3f7
5cc3f7
  - Use a constant for the Wavpack4Header size instead of using sizeof.
5cc3f7
    It's written out into the data and not from the struct and who knows
5cc3f7
    what special alignment/padding requirements some C compilers have.
5cc3f7
  - gst_buffer_set_size() does not realloc the buffer when setting a
5cc3f7
    bigger size than allocated, it only allows growing up to the maximum
5cc3f7
    allocated size. Instead use a GstAdapter to collect all the blocks
5cc3f7
    and take out everything at once in the end.
5cc3f7
  - Check that enough data is actually available in the input and
5cc3f7
    otherwise handle it an error in all cases instead of silently
5cc3f7
    ignoring it.
5cc3f7
5cc3f7
Among other things this fixes out of bounds writes because the code
5cc3f7
assumed gst_buffer_set_size() can grow the buffer and simply wrote after
5cc3f7
the end of the buffer.
5cc3f7
5cc3f7
Thanks to Natalie Silvanovich for reporting.
5cc3f7
5cc3f7
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/859
5cc3f7
5cc3f7
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/904>
5cc3f7
---
5cc3f7
 gst/matroska/matroska-demux.c | 99 +++++++++++++++++++----------------
5cc3f7
 gst/matroska/matroska-ids.h   |  2 +
5cc3f7
 2 files changed, 55 insertions(+), 46 deletions(-)
5cc3f7
5cc3f7
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
5cc3f7
index 4eb3d2a9f..f890ae611 100644
5cc3f7
--- a/gst/matroska/matroska-demux.c
5cc3f7
+++ b/gst/matroska/matroska-demux.c
5cc3f7
@@ -3706,6 +3706,12 @@ gst_matroska_demux_add_wvpk_header (GstElement * element,
5cc3f7
     guint32 block_samples, tmp;
5cc3f7
     gsize size = gst_buffer_get_size (*buf);
5cc3f7
 
5cc3f7
+    if (size < 4) {
5cc3f7
+      GST_ERROR_OBJECT (element, "Too small wavpack buffer");
5cc3f7
+      gst_buffer_unmap (*buf, &map);
5cc3f7
+      return GST_FLOW_ERROR;
5cc3f7
+    }
5cc3f7
+
5cc3f7
     gst_buffer_extract (*buf, 0, &tmp, sizeof (guint32));
5cc3f7
     block_samples = GUINT32_FROM_LE (tmp);
5cc3f7
     /* we need to reconstruct the header of the wavpack block */
5cc3f7
@@ -3713,10 +3719,10 @@ gst_matroska_demux_add_wvpk_header (GstElement * element,
5cc3f7
     /* -20 because ck_size is the size of the wavpack block -8
5cc3f7
      * and lace_size is the size of the wavpack block + 12
5cc3f7
      * (the three guint32 of the header that already are in the buffer) */
5cc3f7
-    wvh.ck_size = size + sizeof (Wavpack4Header) - 20;
5cc3f7
+    wvh.ck_size = size + WAVPACK4_HEADER_SIZE - 20;
5cc3f7
 
5cc3f7
     /* block_samples, flags and crc are already in the buffer */
5cc3f7
-    newbuf = gst_buffer_new_allocate (NULL, sizeof (Wavpack4Header) - 12, NULL);
5cc3f7
+    newbuf = gst_buffer_new_allocate (NULL, WAVPACK4_HEADER_SIZE - 12, NULL);
5cc3f7
 
5cc3f7
     gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
5cc3f7
     data = outmap.data;
5cc3f7
@@ -3741,9 +3747,11 @@ gst_matroska_demux_add_wvpk_header (GstElement * element,
5cc3f7
     audiocontext->wvpk_block_index += block_samples;
5cc3f7
   } else {
5cc3f7
     guint8 *outdata = NULL;
5cc3f7
-    guint outpos = 0;
5cc3f7
-    gsize buf_size, size, out_size = 0;
5cc3f7
+    gsize buf_size, size;
5cc3f7
     guint32 block_samples, flags, crc, blocksize;
5cc3f7
+    GstAdapter *adapter;
5cc3f7
+
5cc3f7
+    adapter = gst_adapter_new ();
5cc3f7
 
5cc3f7
     gst_buffer_map (*buf, &map, GST_MAP_READ);
5cc3f7
     buf_data = map.data;
5cc3f7
@@ -3752,6 +3760,7 @@ gst_matroska_demux_add_wvpk_header (GstElement * element,
5cc3f7
     if (buf_size < 4) {
5cc3f7
       GST_ERROR_OBJECT (element, "Too small wavpack buffer");
5cc3f7
       gst_buffer_unmap (*buf, &map);
5cc3f7
+      g_object_unref (adapter);
5cc3f7
       return GST_FLOW_ERROR;
5cc3f7
     }
5cc3f7
 
5cc3f7
@@ -3773,59 +3782,57 @@ gst_matroska_demux_add_wvpk_header (GstElement * element,
5cc3f7
       data += 4;
5cc3f7
       size -= 4;
5cc3f7
 
5cc3f7
-      if (blocksize == 0 || size < blocksize)
5cc3f7
-        break;
5cc3f7
-
5cc3f7
-      g_assert ((newbuf == NULL) == (outdata == NULL));
5cc3f7
+      if (blocksize == 0 || size < blocksize) {
5cc3f7
+        GST_ERROR_OBJECT (element, "Too small wavpack buffer");
5cc3f7
+        gst_buffer_unmap (*buf, &map);
5cc3f7
+        g_object_unref (adapter);
5cc3f7
+        return GST_FLOW_ERROR;
5cc3f7
+      }
5cc3f7
 
5cc3f7
-      if (newbuf == NULL) {
5cc3f7
-        out_size = sizeof (Wavpack4Header) + blocksize;
5cc3f7
-        newbuf = gst_buffer_new_allocate (NULL, out_size, NULL);
5cc3f7
+      g_assert (newbuf == NULL);
5cc3f7
 
5cc3f7
-        gst_buffer_copy_into (newbuf, *buf,
5cc3f7
-            GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, -1);
5cc3f7
+      newbuf =
5cc3f7
+          gst_buffer_new_allocate (NULL, WAVPACK4_HEADER_SIZE + blocksize,
5cc3f7
+          NULL);
5cc3f7
+      gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
5cc3f7
+      outdata = outmap.data;
5cc3f7
+
5cc3f7
+      outdata[0] = 'w';
5cc3f7
+      outdata[1] = 'v';
5cc3f7
+      outdata[2] = 'p';
5cc3f7
+      outdata[3] = 'k';
5cc3f7
+      outdata += 4;
5cc3f7
+
5cc3f7
+      GST_WRITE_UINT32_LE (outdata, blocksize + WAVPACK4_HEADER_SIZE - 8);
5cc3f7
+      GST_WRITE_UINT16_LE (outdata + 4, wvh.version);
5cc3f7
+      GST_WRITE_UINT8 (outdata + 6, wvh.track_no);
5cc3f7
+      GST_WRITE_UINT8 (outdata + 7, wvh.index_no);
5cc3f7
+      GST_WRITE_UINT32_LE (outdata + 8, wvh.total_samples);
5cc3f7
+      GST_WRITE_UINT32_LE (outdata + 12, wvh.block_index);
5cc3f7
+      GST_WRITE_UINT32_LE (outdata + 16, block_samples);
5cc3f7
+      GST_WRITE_UINT32_LE (outdata + 20, flags);
5cc3f7
+      GST_WRITE_UINT32_LE (outdata + 24, crc);
5cc3f7
+      outdata += 28;
5cc3f7
+
5cc3f7
+      memcpy (outdata, data, blocksize);
5cc3f7
 
5cc3f7
-        outpos = 0;
5cc3f7
-        gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
5cc3f7
-        outdata = outmap.data;
5cc3f7
-      } else {
5cc3f7
-        gst_buffer_unmap (newbuf, &outmap);
5cc3f7
-        out_size += sizeof (Wavpack4Header) + blocksize;
5cc3f7
-        gst_buffer_set_size (newbuf, out_size);
5cc3f7
-        gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
5cc3f7
-        outdata = outmap.data;
5cc3f7
-      }
5cc3f7
+      gst_buffer_unmap (newbuf, &outmap);
5cc3f7
+      gst_adapter_push (adapter, newbuf);
5cc3f7
+      newbuf = NULL;
5cc3f7
 
5cc3f7
-      outdata[outpos] = 'w';
5cc3f7
-      outdata[outpos + 1] = 'v';
5cc3f7
-      outdata[outpos + 2] = 'p';
5cc3f7
-      outdata[outpos + 3] = 'k';
5cc3f7
-      outpos += 4;
5cc3f7
-
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos,
5cc3f7
-          blocksize + sizeof (Wavpack4Header) - 8);
5cc3f7
-      GST_WRITE_UINT16_LE (outdata + outpos + 4, wvh.version);
5cc3f7
-      GST_WRITE_UINT8 (outdata + outpos + 6, wvh.track_no);
5cc3f7
-      GST_WRITE_UINT8 (outdata + outpos + 7, wvh.index_no);
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos + 8, wvh.total_samples);
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos + 12, wvh.block_index);
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos + 16, block_samples);
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos + 20, flags);
5cc3f7
-      GST_WRITE_UINT32_LE (outdata + outpos + 24, crc);
5cc3f7
-      outpos += 28;
5cc3f7
-
5cc3f7
-      memmove (outdata + outpos, data, blocksize);
5cc3f7
-      outpos += blocksize;
5cc3f7
       data += blocksize;
5cc3f7
       size -= blocksize;
5cc3f7
     }
5cc3f7
     gst_buffer_unmap (*buf, &map);
5cc3f7
-    gst_buffer_unref (*buf);
5cc3f7
 
5cc3f7
-    if (newbuf)
5cc3f7
-      gst_buffer_unmap (newbuf, &outmap);
5cc3f7
+    newbuf = gst_adapter_take_buffer (adapter, gst_adapter_available (adapter));
5cc3f7
+    g_object_unref (adapter);
5cc3f7
 
5cc3f7
+    gst_buffer_copy_into (newbuf, *buf,
5cc3f7
+        GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, -1);
5cc3f7
+    gst_buffer_unref (*buf);
5cc3f7
     *buf = newbuf;
5cc3f7
+
5cc3f7
     audiocontext->wvpk_block_index += block_samples;
5cc3f7
   }
5cc3f7
 
5cc3f7
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
5cc3f7
index 9b263d8a1..a0d68343f 100644
5cc3f7
--- a/gst/matroska/matroska-ids.h
5cc3f7
+++ b/gst/matroska/matroska-ids.h
5cc3f7
@@ -667,6 +667,8 @@ typedef struct _Wavpack4Header {
5cc3f7
   guint32 crc;           /* crc for actual decoded data                    */
5cc3f7
 } Wavpack4Header;
5cc3f7
 
5cc3f7
+#define WAVPACK4_HEADER_SIZE (32)
5cc3f7
+
5cc3f7
 typedef enum {
5cc3f7
   GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME = (1<<0),
5cc3f7
   GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA = (1<<1),
5cc3f7
-- 
5cc3f7
GitLab
5cc3f7