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.
This commit is contained in:
Michael Natterer 2018-07-06 13:07:28 +02:00
parent 8195a56261
commit 9b56ca8c1d
7 changed files with 99 additions and 34 deletions

View File

@ -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 */

View File

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

View File

@ -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__ */

View File

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

View File

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

View File

@ -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));

View File

@ -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++)