https://bugs.gentoo.org/969286
https://www.zerodayinitiative.com/advisories/ZDI-25-911/
https://gitlab.gnome.org/GNOME/gimp/-/issues/14811
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/2444
https://gitlab.gnome.org/GNOME/gimp/-/commit/0f309f9a8d82f43fa01383bc5a5c41d28727d9e3

From ea423250c1f3dca4a1cea15e2644c5b04fda478b Mon Sep 17 00:00:00 2001
From: Jacob Boerema <jgboerema@gmail.com>
Date: Wed, 3 Sep 2025 13:31:45 -0400
Subject: [PATCH] plug-ins: fix dicom plug-in ZDI-CAN-27863

GIMP DCM File Parsing Heap-based Buffer Overflow Remote Code Execution
Vulnerability

This adds more safety checks and sets actual GError's instead of just
calling gimp_quit.

Cherry-picked from 3d909166463731e94dfe62042d76225ecfc4c1e4

Cherry-picked to 2.10 and modified to work correctly with this context:
6bca8c4f8970d976c731463f938ae39df3c3fd4c
72df7883ef503bc81a2e1498bfcb842dd97da221
--- a/plug-ins/common/file-dicom.c
+++ b/plug-ins/common/file-dicom.c
@@ -330,6 +330,7 @@ load_image (const gchar  *filename,
   gint            bits_stored       = 0;
   gint            high_bit          = 0;
   guint8         *pix_buf           = NULL;
+  guint64         pixbuf_size       = 0;
   gboolean        is_signed         = FALSE;
   guint8          in_sequence       = 0;
   gboolean        implicit_encoding = FALSE;
@@ -385,6 +386,7 @@ load_image (const gchar  *filename,
       guint16  ctx_us;
       guint8  *value;
       guint32  tag;
+      size_t   actual_read;
 
       if (fread (&group_word, 1, 2, DICOM) == 0)
         break;
@@ -489,15 +491,24 @@ load_image (const gchar  *filename,
 
       if (element_length >= (G_MAXUINT - 6))
         {
-          g_message ("'%s' seems to have an incorrect value field length.",
-                     gimp_filename_to_utf8 (filename));
-          gimp_quit ();
+          g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                       _("'%s' has an an incorrect value for field size. Possibly corrupt image."),
+                       gimp_filename_to_utf8 (filename));
+          g_free (dicominfo);
+          fclose (DICOM);
+          return -1;
         }
 
       /* Read contents. Allocate a bit more to make room for casts to int
        below. */
       value = g_new0 (guint8, element_length + 4);
-      fread (value, 1, element_length, DICOM);
+      actual_read = fread (value, 1, element_length, DICOM);
+      if (actual_read < element_length)
+        {
+          g_warning ("Missing data: needed %u bytes, got %u. Possibly corrupt image.",
+                     element_length, (guint32) actual_read);
+          element_length = actual_read;
+        }
 
       /* ignore everything inside of a sequence */
       if (in_sequence)
@@ -510,7 +521,7 @@ load_image (const gchar  *filename,
       if (big_endian && group_word != 0x0002)
         ctx_us = GUINT16_SWAP_LE_BE (ctx_us);
 
-      g_debug ("group: %04x, element: %04x, length: %d",
+      g_debug ("group: %04x, element: %04x, length: %u",
                group_word, element_word, element_length);
       g_debug ("Value: %s", (char*)value);
       /* Recognize some critical tags */
@@ -644,6 +655,7 @@ load_image (const gchar  *filename,
       if (group_word == 0x7fe0 && element_word == 0x0010)
         {
           pix_buf = value;
+          pixbuf_size = element_length;
         }
       else
         {
@@ -674,25 +686,50 @@ load_image (const gchar  *filename,
         }
     }
 
+  g_debug ("Bpp: %d, wxh: %u x %u, spp: %d\n", bpp, width, height, samples_per_pixel);
+
   if ((bpp != 8) && (bpp != 16))
     {
-      g_message ("'%s' has a bpp of %d which GIMP cannot handle.",
-                 gimp_filename_to_utf8 (filename), bpp);
-      gimp_quit ();
+      g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                   _("'%s' has a bpp of %d which GIMP cannot handle."),
+                   gimp_filename_to_utf8 (filename), bpp);
+      g_free (pix_buf);
+      g_free (dicominfo);
+      fclose (DICOM);
+      return -1;
     }
 
   if ((width > GIMP_MAX_IMAGE_SIZE) || (height > GIMP_MAX_IMAGE_SIZE))
     {
-      g_message ("'%s' has a larger image size (%d x %d) than GIMP can handle.",
-                 gimp_filename_to_utf8 (filename), width, height);
-      gimp_quit ();
+      g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                   _("'%s' has a larger image size (%d x %d) than GIMP can handle."),
+                   gimp_filename_to_utf8 (filename), width, height);
+      g_free (pix_buf);
+      g_free (dicominfo);
+      fclose (DICOM);
+      return -1;
     }
 
   if (samples_per_pixel > 3)
     {
-      g_message ("'%s' has samples per pixel of %d which GIMP cannot handle.",
-                 gimp_filename_to_utf8 (filename), samples_per_pixel);
-      gimp_quit ();
+      g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                   _("'%s' has samples per pixel of %d which GIMP cannot handle."),
+                   gimp_filename_to_utf8 (filename), samples_per_pixel);
+      g_free (pix_buf);
+      g_free (dicominfo);
+      fclose (DICOM);
+      return -1;
+    }
+
+  if ((guint64) width * height * (bpp >> 3) * samples_per_pixel > pixbuf_size)
+    {
+      g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                   _("'%s' has not enough pixel data. Possibly corrupt image."),
+                   gimp_filename_to_utf8 (filename));
+      g_free (pix_buf);
+      g_free (dicominfo);
+      fclose (DICOM);
+      return -1;
     }
 
   dicominfo->width  = width;
-- 
2.52.0

