[gimp] Issue #1730 - pat file that crashes gimp-2.10



commit 9b56ca8c1d556a051d9a4a04907f08f04da914a6
Author: Michael Natterer <mitch gimp org>
Date:   Fri Jul 6 13:07:28 2018 +0200

    Issue #1730 - pat file that crashes gimp-2.10
    
    Introduce GIMP_PATTERN_MAX_SIZE (10000) and GIMP_PATTERN_MAX_NAME (256)
    and validate pattern dimensions and pattern name length against them.
    
    Add GIMP_BRUSH_MAX_NAME and validate that too.
    
    Also make sure that the names are properly terminated, and some
    cleanup.

 app/core/gimpbrush-header.h   |  1 +
 app/core/gimpbrush-load.c     | 16 ++++++++++---
 app/core/gimppattern-header.h |  5 ++++
 app/core/gimppattern-load.c   | 29 +++++++++++++++--------
 plug-ins/common/file-gbr.c    | 19 +++++++++++++---
 plug-ins/common/file-gih.c    | 10 +++++++-
 plug-ins/common/file-pat.c    | 53 ++++++++++++++++++++++++++++---------------
 7 files changed, 99 insertions(+), 34 deletions(-)
---
diff --git a/app/core/gimpbrush-header.h b/app/core/gimpbrush-header.h
index 62f6840085..9935110c29 100644
--- a/app/core/gimpbrush-header.h
+++ b/app/core/gimpbrush-header.h
@@ -23,6 +23,7 @@
 #define GIMP_BRUSH_MAGIC         (('G' << 24) + ('I' << 16) + \
                                   ('M' << 8)  + ('P' << 0))
 #define GIMP_BRUSH_MAX_SIZE      10000 /* Max size in either dimension in px */
+#define GIMP_BRUSH_MAX_NAME      256   /* Max length of the brush's name     */
 
 
 /*  All field entries are MSB  */
diff --git a/app/core/gimpbrush-load.c b/app/core/gimpbrush-load.c
index c065e20d1f..60368181f0 100644
--- a/app/core/gimpbrush-load.c
+++ b/app/core/gimpbrush-load.c
@@ -188,7 +188,7 @@ gimp_brush_load_brush (GimpContext   *context,
       return NULL;
     }
 
-  if (header.width > GIMP_BRUSH_MAX_SIZE ||
+  if (header.width  > GIMP_BRUSH_MAX_SIZE ||
       header.height > GIMP_BRUSH_MAX_SIZE)
     {
       g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
@@ -247,7 +247,17 @@ gimp_brush_load_brush (GimpContext   *context,
     {
       gchar *utf8;
 
-      name = g_new (gchar, bn_size);
+      if (bn_size > GIMP_BRUSH_MAX_NAME)
+        {
+          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
+                       _("Invalid header data in '%s': "
+                         "Brush name is too long: %lu"),
+                       gimp_file_get_utf8_name (file),
+                       (gulong) bn_size);
+          return NULL;
+        }
+
+      name = g_new0 (gchar, bn_size + 1);
 
       if (! g_input_stream_read_all (input, name, bn_size,
                                      &bytes_read, NULL, error) ||
@@ -264,7 +274,7 @@ gimp_brush_load_brush (GimpContext   *context,
       name = utf8;
     }
 
-  if (!name)
+  if (! name)
     name = g_strdup (_("Unnamed"));
 
   brush = g_object_new (GIMP_TYPE_BRUSH,
diff --git a/app/core/gimppattern-header.h b/app/core/gimppattern-header.h
index f6befec163..37dbc983b3 100644
--- a/app/core/gimppattern-header.h
+++ b/app/core/gimppattern-header.h
@@ -18,9 +18,13 @@
 #ifndef __GIMP_PATTERN_HEADER_H__
 #define __GIMP_PATTERN_HEADER_H__
 
+
 #define GIMP_PATTERN_FILE_VERSION  1
 #define GIMP_PATTERN_MAGIC         (('G' << 24) + ('P' << 16) + \
                                     ('A' << 8)  + ('T' << 0))
+#define GIMP_PATTERN_MAX_SIZE      10000 /* Max size in either dimension in px */
+#define GIMP_PATTERN_MAX_NAME      256   /* Max length of the pattern's name   */
+
 
 /*  All field entries are MSB  */
 
@@ -40,4 +44,5 @@ struct _GimpPatternHeader
  *  comes the pattern data--width * height * bytes bytes of it...
  */
 
+
 #endif  /*  __GIMP_PATTERN_HEADER_H__  */
diff --git a/app/core/gimppattern-load.c b/app/core/gimppattern-load.c
index 5f119c5486..85729bf17a 100644
--- a/app/core/gimppattern-load.c
+++ b/app/core/gimppattern-load.c
@@ -45,7 +45,7 @@ gimp_pattern_load (GimpContext   *context,
   GimpPatternHeader  header;
   gsize              size;
   gsize              bytes_read;
-  gint               bn_size;
+  gsize              bn_size;
   gchar             *name = NULL;
 
   g_return_val_if_fail (G_IS_FILE (file), NULL);
@@ -70,8 +70,9 @@ gimp_pattern_load (GimpContext   *context,
   header.magic_number = g_ntohl (header.magic_number);
 
   /*  Check for correct file format */
-  if (header.magic_number != GIMP_PATTERN_MAGIC || header.version != 1 ||
-      header.header_size <= sizeof (header))
+  if (header.magic_number != GIMP_PATTERN_MAGIC ||
+      header.version      != 1                  ||
+      header.header_size  <= sizeof (header))
     {
       g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                    _("Unknown pattern format version %d."),
@@ -90,16 +91,16 @@ gimp_pattern_load (GimpContext   *context,
     }
 
   /*  Validate dimensions  */
-  if ((header.width  == 0) || (header.width  > GIMP_MAX_IMAGE_SIZE) ||
-      (header.height == 0) || (header.height > GIMP_MAX_IMAGE_SIZE) ||
+  if ((header.width  == 0) || (header.width  > GIMP_PATTERN_MAX_SIZE) ||
+      (header.height == 0) || (header.height > GIMP_PATTERN_MAX_SIZE) ||
       (G_MAXSIZE / header.width / header.height / header.bytes < 1))
     {
       g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                    _("Invalid header data in '%s': width=%lu, height=%lu, "
                      "bytes=%lu"), gimp_file_get_utf8_name (file),
-                   (unsigned long int)header.width,
-                   (unsigned long int)header.height,
-                   (unsigned long int)header.bytes);
+                   (gulong) header.width,
+                   (gulong) header.height,
+                   (gulong) header.bytes);
       goto error;
     }
 
@@ -108,7 +109,17 @@ gimp_pattern_load (GimpContext   *context,
     {
       gchar *utf8;
 
-      name = g_new (gchar, bn_size);
+      if (bn_size > GIMP_PATTERN_MAX_NAME)
+        {
+          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
+                       _("Invalid header data in '%s': "
+                         "Pattern name is too long: %lu"),
+                       gimp_file_get_utf8_name (file),
+                       (gulong) bn_size);
+          goto error;
+        }
+
+      name = g_new0 (gchar, bn_size + 1);
 
       if (! g_input_stream_read_all (input, name, bn_size,
                                      &bytes_read, NULL, error) ||
diff --git a/plug-ins/common/file-gbr.c b/plug-ins/common/file-gbr.c
index 38af555ff0..2ebaf78b26 100644
--- a/plug-ins/common/file-gbr.c
+++ b/plug-ins/common/file-gbr.c
@@ -395,8 +395,9 @@ load_image (GFile   *file,
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                    _("Invalid header data in '%s': width=%lu, height=%lu, "
                      "bytes=%lu"), g_file_get_parse_name (file),
-                   (unsigned long int)bh.width, (unsigned long int)bh.height,
-                   (unsigned long int)bh.bytes);
+                   (gulong) bh.width,
+                   (gulong) bh.height,
+                   (gulong) bh.bytes);
       return -1;
     }
 
@@ -459,7 +460,19 @@ load_image (GFile   *file,
 
   if ((size = (bh.header_size - sizeof (GimpBrushHeader))) > 0)
     {
-      gchar *temp = g_new (gchar, size);
+      gchar *temp;
+
+      if (size > GIMP_BRUSH_MAX_NAME)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                       _("Invalid header data in '%s': "
+                         "Brush name is too long: %lu"),
+                       gimp_file_get_utf8_name (file),
+                       (gulong) size);
+          return -1;
+        }
+
+      temp = g_new0 (gchar, size + 1);
 
       if (! g_input_stream_read_all (input, temp, size,
                                      &bytes_read, NULL, error) ||
diff --git a/plug-ins/common/file-gih.c b/plug-ins/common/file-gih.c
index 0d93212d30..8e0255332a 100644
--- a/plug-ins/common/file-gih.c
+++ b/plug-ins/common/file-gih.c
@@ -496,6 +496,14 @@ gih_load_one_brush (GInputStream  *input,
 
   if ((size = (bh.header_size - sizeof (bh))) > 0)
     {
+      if (size > GIMP_BRUSH_MAX_NAME)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                       _("Brush name is too long: %lu"),
+                       (gulong) size);
+          return FALSE;
+        }
+
       name = g_new0 (gchar, size + 1);
 
       if (! g_input_stream_read_all (input, name, size,
@@ -704,7 +712,7 @@ gih_load_image (GFile   *file,
 
   g_string_free (buffer, FALSE);
 
-  if (!name)
+  if (! name)
     {
       g_message ("Couldn't read name for brush pipe from '%s'",
                  g_file_get_parse_name (file));
diff --git a/plug-ins/common/file-pat.c b/plug-ins/common/file-pat.c
index 454fa761c3..c5cbf1a2ba 100644
--- a/plug-ins/common/file-pat.c
+++ b/plug-ins/common/file-pat.c
@@ -332,6 +332,7 @@ load_image (GFile   *file,
   GimpImageBaseType   base_type;
   GimpImageType       image_type;
   gsize               bytes_read;
+  gsize               size;
 
   gimp_progress_init_printf (_("Opening '%s'"),
                              g_file_get_parse_name (file));
@@ -364,22 +365,37 @@ load_image (GFile   *file,
       return -1;
     }
 
-  temp = g_new (gchar, ph.header_size - sizeof (GimpPatternHeader));
-
-  if (! g_input_stream_read_all (input,
-                                 temp, ph.header_size - sizeof (GimpPatternHeader),
-                                 &bytes_read, NULL, error) ||
-      bytes_read != ph.header_size - sizeof (GimpPatternHeader))
+  if ((size = (ph.header_size - sizeof (GimpPatternHeader))) > 0)
     {
+      if (size > GIMP_PATTERN_MAX_NAME)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                       _("Invalid header data in '%s': "
+                         "Pattern name is too long: %lu"),
+                       gimp_file_get_utf8_name (file),
+                       (gulong) size);
+          return -1;
+        }
+
+      temp = g_new0 (gchar, size + 1);
+
+      if (! g_input_stream_read_all (input, temp, size,
+                                     &bytes_read, NULL, error) ||
+          bytes_read != size)
+        {
+          g_free (temp);
+          g_object_unref (input);
+          return -1;
+        }
+
+      name = gimp_any_to_utf8 (temp, size - 1,
+                               _("Invalid UTF-8 string in pattern file '%s'."),
+                               g_file_get_parse_name (file));
       g_free (temp);
-      g_object_unref (input);
-      return -1;
     }
 
-  name = gimp_any_to_utf8 (temp, ph.header_size - sizeof (GimpPatternHeader) - 1,
-                           _("Invalid UTF-8 string in pattern file '%s'."),
-                           g_file_get_parse_name (file));
-  g_free (temp);
+  if (! name)
+    name = g_strdup (_("Unnamed"));
 
   /* Now there's just raw data left. */
 
@@ -417,15 +433,16 @@ load_image (GFile   *file,
     }
 
   /* Sanitize input dimensions and guard against overflows. */
-  if ((ph.width == 0) || (ph.width > GIMP_MAX_IMAGE_SIZE) ||
-      (ph.height == 0) || (ph.height > GIMP_MAX_IMAGE_SIZE) ||
+  if ((ph.width == 0)  || (ph.width  > GIMP_PATTERN_MAX_SIZE) ||
+      (ph.height == 0) || (ph.height > GIMP_PATTERN_MAX_SIZE) ||
       (G_MAXSIZE / ph.width / ph.bytes < 1))
     {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                    _("Invalid header data in '%s': width=%lu, height=%lu, "
                      "bytes=%lu"), g_file_get_parse_name (file),
-                   (unsigned long int)ph.width, (unsigned long int)ph.height,
-                   (unsigned long int)ph.bytes);
+                   (gulong) ph.width,
+                   (gulong) ph.height,
+                   (gulong) ph.bytes);
       g_object_unref (input);
       return -1;
     }
@@ -449,7 +466,7 @@ load_image (GFile   *file,
 
   buffer = gimp_drawable_get_buffer (layer_ID);
 
-  /* this can't overflow because ph.width is <= GIMP_MAX_IMAGE_SIZE */
+  /* this can't overflow because ph.width is <= GIMP_PATTERN_MAX_SIZE */
   buf = g_malloc (ph.width * ph.bytes);
 
   for (line = 0; line < ph.height; line++)
@@ -570,7 +587,7 @@ save_image (GFile   *file,
 
   line_size = width * babl_format_get_bytes_per_pixel (file_format);
 
-  /* this can't overflow because drawable->width is <= GIMP_MAX_IMAGE_SIZE */
+  /* this can't overflow because drawable->width is <= GIMP_PATTERN_MAX_SIZE */
   buf = g_alloca (line_size);
 
   for (line = 0; line < height; line++)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]