CVE-2023-40474
authorMaintainers of GStreamer packages <gst-plugins-bad1.0@packages.debian.org>
Fri, 27 Oct 2023 20:55:02 +0000 (22:55 +0200)
committerThorsten Alteholz <debian@alteholz.de>
Fri, 27 Oct 2023 20:55:02 +0000 (22:55 +0200)
commit f73fc41f2ca6a0cd4e883aee64bf8e1c15ff68ce
Author: Sebastian Dröge <sebastian@centricular.com>
Date:   Thu Aug 10 15:45:01 2023 +0300

    mxfdemux: Fix integer overflow causing out of bounds writes when handling invalid uncompressed video

    Check ahead of time when parsing the track information whether
    width, height and bpp are valid and usable without overflows.

    Fixes ZDI-CAN-21660, CVE-2023-40474

    Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2896

    Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5365>

Gbp-Pq: Name CVE-2023-40474.patch

gst/mxf/mxfup.c

index d8b6664dab67efc5d48e05f14143a55e1df20e9d..b8c9cae05d3855eb4f0c256a08c6ccc809635cfe 100644 (file)
@@ -100,6 +100,64 @@ typedef struct
   guint32 image_end_offset;
 } MXFUPMappingData;
 
+/*----------- start of new functions -----------*/
+/*
+ * add some functions that are needed for CVE-2023-40474.patch
+ * but are only added later to gstreamer
+ */
+void gst_clear_caps (GstCaps ** caps_ptr);
+void gst_clear_mini_object (GstMiniObject ** object_ptr);
+
+/**
+ * gst_clear_caps: (skip)
+ * @caps_ptr: a pointer to a #GstCaps reference
+ *
+ * Clears a reference to a #GstCaps.
+ *
+ * @caps_ptr must not be %NULL.
+ *
+ * If the reference is %NULL then this function does nothing. Otherwise, the
+ * reference count of the caps is decreased and the pointer is set to %NULL.
+ *
+ * Since: 1.16
+ */
+void
+gst_clear_caps (GstCaps ** caps_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) caps_ptr);
+}
+
+
+/**
+ * gst_clear_mini_object: (skip)
+ * @object_ptr: a pointer to a #GstMiniObject reference
+ *
+ * Clears a reference to a #GstMiniObject.
+ *
+ * @object_ptr must not be %NULL.
+ *
+ * If the reference is %NULL then this function does nothing.
+ * Otherwise, the reference count of the object is decreased using
+ * gst_mini_object_unref() and the pointer is set to %NULL.
+ *
+ * A macro is also included that allows this function to be used without
+ * pointer casts.
+ *
+ * Since: 1.16
+ **/
+#undef gst_clear_mini_object
+void
+gst_clear_mini_object (GstMiniObject ** object_ptr)
+{
+  g_clear_pointer (object_ptr, gst_mini_object_unref);
+}
+/*----------- end of new functions -----------*/
+
+
+
+
+
+
 static gboolean
 mxf_is_up_essence_track (const MXFMetadataTimelineTrack * track)
 {
@@ -134,6 +192,8 @@ mxf_up_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
     gpointer mapping_data, GstBuffer ** outbuf)
 {
   MXFUPMappingData *data = mapping_data;
+  gsize expected_in_stride = 0, out_stride = 0;
+  gsize expected_in_size = 0, out_size = 0;
 
   /* SMPTE 384M 7.1 */
   if (key->u[12] != 0x15 || (key->u[14] != 0x01 && key->u[14] != 0x02
@@ -162,22 +222,25 @@ mxf_up_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
     }
   }
 
-  if (gst_buffer_get_size (buffer) != data->bpp * data->width * data->height) {
+  // Checked for overflows when parsing the descriptor
+  expected_in_stride = data->bpp * data->width;
+  out_stride = GST_ROUND_UP_4 (expected_in_stride);
+  expected_in_size = expected_in_stride * data->height;
+  out_size = out_stride * data->height;
+
+  if (gst_buffer_get_size (buffer) != expected_in_size) {
     GST_ERROR ("Invalid buffer size");
     gst_buffer_unref (buffer);
     return GST_FLOW_ERROR;
   }
 
-  if (data->bpp != 4
-      || GST_ROUND_UP_4 (data->width * data->bpp) != data->width * data->bpp) {
+  if (data->bpp != 4 || out_stride != expected_in_stride) {
     guint y;
     GstBuffer *ret;
     GstMapInfo inmap, outmap;
     guint8 *indata, *outdata;
 
-    ret =
-        gst_buffer_new_and_alloc (GST_ROUND_UP_4 (data->width * data->bpp) *
-        data->height);
+    ret = gst_buffer_new_and_alloc (out_size);
     gst_buffer_map (buffer, &inmap, GST_MAP_READ);
     gst_buffer_map (ret, &outmap, GST_MAP_WRITE);
     indata = inmap.data;
@@ -185,8 +248,8 @@ mxf_up_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
 
     for (y = 0; y < data->height; y++) {
       memcpy (outdata, indata, data->width * data->bpp);
-      outdata += GST_ROUND_UP_4 (data->width * data->bpp);
-      indata += data->width * data->bpp;
+      outdata += out_stride;
+      indata += expected_in_stride;
     }
 
     gst_buffer_unmap (buffer, &inmap);
@@ -394,6 +457,36 @@ mxf_up_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
     return NULL;
   }
 
+  if (caps) {
+    MXFUPMappingData *data = *mapping_data;
+    gsize expected_in_stride = 0, out_stride = 0;
+    gsize expected_in_size = 0, out_size = 0;
+
+    // Do some checking of the parameters to see if they're valid and
+    // we can actually work with them.
+    if (data->image_start_offset > data->image_end_offset) {
+      GST_WARNING ("Invalid image start/end offset");
+      g_free (data);
+      *mapping_data = NULL;
+      gst_clear_caps (&caps);
+
+      return NULL;
+    }
+
+    if (!g_size_checked_mul (&expected_in_stride, data->bpp, data->width) ||
+        (out_stride = GST_ROUND_UP_4 (expected_in_stride)) < expected_in_stride
+        || !g_size_checked_mul (&expected_in_size, expected_in_stride,
+            data->height)
+        || !g_size_checked_mul (&out_size, out_stride, data->height)) {
+      GST_ERROR ("Invalid resolution or bit depth");
+      g_free (data);
+      *mapping_data = NULL;
+      gst_clear_caps (&caps);
+
+      return NULL;
+    }
+  }
+
   return caps;
 }