From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Fri, 4 Oct 2024 13:00:57 +0300
Subject: wavparse: Check for short reads when parsing headers in pull mode
Origin: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/c627f3a28bc792580f9a9ebcbb309b2256e4a895
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2024-47776
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2024-47778

And also return the actual flow return to the caller instead of always returning
GST_FLOW_ERROR.

Thanks to Antonio Morales for finding and reporting the issue.

Fixes GHSL-2024-258, GHSL-2024-260
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3886
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3888

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8054>
---
 .../gst/wavparse/gstwavparse.c                | 63 ++++++++++++++-----
 1 file changed, 46 insertions(+), 17 deletions(-)

--- a/gst/wavparse/gstwavparse.c
+++ b/gst/wavparse/gstwavparse.c
@@ -1097,6 +1097,24 @@ parse_ds64 (GstWavParse * wav, GstBuffer
 }
 
 static GstFlowReturn
+gst_wavparse_pull_range_exact (GstWavParse * wav, guint64 offset, guint size,
+    GstBuffer ** buffer)
+{
+  GstFlowReturn res;
+
+  res = gst_pad_pull_range (wav->sinkpad, offset, size, buffer);
+  if (res != GST_FLOW_OK)
+    return res;
+
+  if (gst_buffer_get_size (*buffer) < size) {
+    gst_clear_buffer (buffer);
+    return GST_FLOW_EOS;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
 gst_wavparse_stream_headers (GstWavParse * wav)
 {
   GstFlowReturn res = GST_FLOW_OK;
@@ -1291,9 +1309,9 @@ gst_wavparse_stream_headers (GstWavParse
 
       buf = NULL;
       if ((res =
-              gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
+              gst_wavparse_pull_range_exact (wav, wav->offset, 8,
                   &buf)) != GST_FLOW_OK)
-        goto header_read_error;
+        goto header_pull_error;
       gst_buffer_map (buf, &map, GST_MAP_READ);
       tag = GST_READ_UINT32_LE (map.data);
       size = GST_READ_UINT32_LE (map.data + 4);
@@ -1396,9 +1414,9 @@ gst_wavparse_stream_headers (GstWavParse
             gst_buffer_unref (buf);
             buf = NULL;
             if ((res =
-                    gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
+                    gst_wavparse_pull_range_exact (wav, wav->offset + 8,
                         data_size, &buf)) != GST_FLOW_OK)
-              goto header_read_error;
+              goto header_pull_error;
             gst_buffer_extract (buf, 0, &wav->fact, 4);
             wav->fact = GUINT32_FROM_LE (wav->fact);
             gst_buffer_unref (buf);
@@ -1443,9 +1461,9 @@ gst_wavparse_stream_headers (GstWavParse
           gst_buffer_unref (buf);
           buf = NULL;
           if ((res =
-                  gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
-                      size, &buf)) != GST_FLOW_OK)
-            goto header_read_error;
+                  gst_wavparse_pull_range_exact (wav, wav->offset + 8, size,
+                      &buf)) != GST_FLOW_OK)
+            goto header_pull_error;
           gst_buffer_map (buf, &map, GST_MAP_READ);
           acid = (const gst_riff_acid *) map.data;
           tempo = acid->tempo;
@@ -1483,9 +1501,9 @@ gst_wavparse_stream_headers (GstWavParse
           gst_buffer_unref (buf);
           buf = NULL;
           if ((res =
-                  gst_pad_pull_range (wav->sinkpad, wav->offset, 12,
+                  gst_wavparse_pull_range_exact (wav, wav->offset, 12,
                       &buf)) != GST_FLOW_OK)
-            goto header_read_error;
+            goto header_pull_error;
           gst_buffer_extract (buf, 8, &ltag, 4);
           ltag = GUINT32_FROM_LE (ltag);
         }
@@ -1512,9 +1530,9 @@ gst_wavparse_stream_headers (GstWavParse
               buf = NULL;
               if (data_size > 0) {
                 if ((res =
-                        gst_pad_pull_range (wav->sinkpad, wav->offset,
+                        gst_wavparse_pull_range_exact (wav, wav->offset,
                             data_size, &buf)) != GST_FLOW_OK)
-                  goto header_read_error;
+                  goto header_pull_error;
               }
             }
             if (data_size > 0) {
@@ -1552,9 +1570,9 @@ gst_wavparse_stream_headers (GstWavParse
               buf = NULL;
               wav->offset += 12;
               if ((res =
-                      gst_pad_pull_range (wav->sinkpad, wav->offset,
+                      gst_wavparse_pull_range_exact (wav, wav->offset,
                           data_size, &buf)) != GST_FLOW_OK)
-                goto header_read_error;
+                goto header_pull_error;
               gst_buffer_map (buf, &map, GST_MAP_READ);
               gst_wavparse_adtl_chunk (wav, (const guint8 *) map.data,
                   data_size);
@@ -1597,9 +1615,9 @@ gst_wavparse_stream_headers (GstWavParse
           gst_buffer_unref (buf);
           buf = NULL;
           if ((res =
-                  gst_pad_pull_range (wav->sinkpad, wav->offset,
+                  gst_wavparse_pull_range_exact (wav, wav->offset,
                       data_size, &buf)) != GST_FLOW_OK)
-            goto header_read_error;
+            goto header_pull_error;
           gst_buffer_map (buf, &map, GST_MAP_READ);
           if (!gst_wavparse_cue_chunk (wav, (const guint8 *) map.data,
                   data_size)) {
@@ -1641,9 +1659,9 @@ gst_wavparse_stream_headers (GstWavParse
           gst_buffer_unref (buf);
           buf = NULL;
           if ((res =
-                  gst_pad_pull_range (wav->sinkpad, wav->offset,
+                  gst_wavparse_pull_range_exact (wav, wav->offset,
                       data_size, &buf)) != GST_FLOW_OK)
-            goto header_read_error;
+            goto header_pull_error;
           gst_buffer_map (buf, &map, GST_MAP_READ);
           if (!gst_wavparse_smpl_chunk (wav, (const guint8 *) map.data,
                   data_size)) {
@@ -1795,6 +1813,17 @@ header_read_error:
         ("Couldn't read in header %d (%s)", res, gst_flow_get_name (res)));
     goto fail;
   }
+header_pull_error:
+  {
+    if (res == GST_FLOW_EOS) {
+      GST_WARNING_OBJECT (wav, "Couldn't pull header %d (%s)", res,
+          gst_flow_get_name (res));
+    } else {
+      GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
+          ("Couldn't pull header %d (%s)", res, gst_flow_get_name (res)));
+    }
+    goto exit;
+  }
 }
 
 /*
