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 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