From 1ccd8d999d3781d336f1495f8ad57c8ca8b48f37 Mon Sep 17 00:00:00 2001 From: Nils Philippsen <nils@redhat.com> Date: Fri, 20 Jul 2012 15:41:10 +0200 Subject: [PATCH] patch: CVE-2012-3403 Squashed commit of the following: commit 7e60d0f3f18746acb118c49b492569b75927e9bb Author: Nils Philippsen <nils@redhat.com> Date: Tue Jul 17 15:06:16 2012 +0200 CEL: use statically allocated palette buffer (backported from commit db603abe493b7a8e7759b12efea4bc25c48c2400) commit 02a3d5eda0a394e217281f20535ad3094d5b5ab7 Author: Nils Philippsen <nils@redhat.com> Date: Tue Jul 17 15:04:00 2012 +0200 CEL: validate header data (CVE-2012-3403) (backported from commit 9d9e4aa5917420ccc90fa60fb19e4e03bc966776) commit 20c1d140f9926d65b5aff95c05e8e8cd8d2e3488 Author: Nils Philippsen <nils@redhat.com> Date: Tue Jul 17 12:58:46 2012 +0200 CEL: check fread()/g_fopen() return values for errors (backported from commit 54ae056bfee8f2e6e04578cd2eb7956fefff8c44) --- plug-ins/common/CEL.c | 249 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 204 insertions(+), 45 deletions(-) diff --git a/plug-ins/common/CEL.c b/plug-ins/common/CEL.c index 065c989..d89f6f8 100644 --- a/plug-ins/common/CEL.c +++ b/plug-ins/common/CEL.c @@ -47,7 +47,8 @@ static void run (const gchar *name, gint *nreturn_vals, GimpParam **return_vals); -static gint load_palette (FILE *fp, +static gint load_palette (const gchar *file, + FILE *fp, guchar palette[]); static gint32 load_image (const gchar *file, const gchar *brief); @@ -56,7 +57,7 @@ static gint save_image (const gchar *file, gint32 image, gint32 layer); static void palette_dialog (const gchar *title); -static gboolean need_palette (const gchar *file); +static gint need_palette (const gchar *file); /* Globals... */ @@ -150,6 +151,7 @@ run (const gchar *name, GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 image; GimpExportReturn export = GIMP_EXPORT_CANCEL; + gint needs_palette = 0; run_mode = param[0].data.d_int32; @@ -187,20 +189,32 @@ run (const gchar *name, else if (run_mode == GIMP_RUN_INTERACTIVE) { /* Let user choose KCF palette (cancel ignores) */ - if (need_palette (param[1].data.d_string)) - palette_dialog (_("Load KISS Palette")); + needs_palette = need_palette (param[1].data.d_string); - gimp_set_data ("file_cel_save:length", &data_length, sizeof (gsize)); - gimp_set_data ("file_cel_save:data", palette_file, data_length); - } + if (needs_palette != -1) + { + if (needs_palette) + palette_dialog (_("Load KISS Palette")); - image = load_image (param[1].data.d_string, param[2].data.d_string); + gimp_set_data ("file_cel_save:length", &data_length, sizeof (gsize)); + gimp_set_data ("file_cel_save:data", palette_file, data_length); + } + } - if (image != -1) + if (needs_palette != -1) { - *nreturn_vals = 2; - values[1].type = GIMP_PDB_IMAGE; - values[1].data.d_image = image; + image = load_image (param[1].data.d_string, param[2].data.d_string); + + if (image != -1) + { + *nreturn_vals = 2; + values[1].type = GIMP_PDB_IMAGE; + values[1].data.d_image = image; + } + else + { + status = GIMP_PDB_EXECUTION_ERROR; + } } else { @@ -256,19 +270,31 @@ run (const gchar *name, } /* Peek into the file to determine whether we need a palette */ -static gboolean +static gint need_palette (const gchar *file) { FILE *fp; guchar header[32]; + size_t n_read; fp = fopen (file, "rb"); - if (!fp) - return FALSE; + if (fp == NULL) + { + g_message (_("Could not open '%s' for reading: %s"), + gimp_filename_to_utf8 (file), g_strerror (errno)); + return -1; + } + + n_read = fread (header, 32, 1, fp); - fread (header, 32, 1, fp); fclose (fp); + if (n_read < 1) + { + g_message (_("EOF or error while reading image header")); + return -1; + } + return (header[5] < 32); } @@ -280,11 +306,12 @@ load_image (const gchar *file, { FILE *fp; /* Read file pointer */ gchar *progress; /* Title for progress display */ - guchar header[32]; /* File header */ + guchar header[32], /* File header */ + file_mark, /* KiSS file type */ + bpp; /* Bits per pixel */ gint height, width, /* Dimensions of image */ offx, offy, /* Layer offets */ - colours, /* Number of colours */ - bpp; /* Bits per pixel */ + colours; /* Number of colours */ gint32 image, /* Image */ layer; /* Layer */ @@ -295,6 +322,7 @@ load_image (const gchar *file, GimpPixelRgn pixel_rgn; /* Pixel region for layer */ gint i, j, k; /* Counters */ + size_t n_read; /* Number of items read from file */ /* Open the file for reading */ @@ -314,7 +342,13 @@ load_image (const gchar *file, /* Get the image dimensions and create the image... */ - fread (header, 4, 1, fp); + n_read = fread (header, 4, 1, fp); + + if (n_read < 1) + { + g_message (_("EOF or error while reading image header")); + return -1; + } if (strncmp (header, "KiSS", 4)) { @@ -327,18 +361,49 @@ load_image (const gchar *file, } else { /* New-style image file, read full header */ - fread (header, 28, 1, fp); + n_read = fread (header, 28, 1, fp); + + if (n_read < 1) + { + g_message (_("EOF or error while reading image header")); + return -1; + } + + file_mark = header[0]; + if (file_mark != 0x20 && file_mark != 0x21) + { + g_message (_("is not a CEL image file")); + return -1; + } + bpp = header[1]; - if (bpp == 24) - colours = -1; - else - colours = (1 << header[1]); + switch (bpp) + { + case 4: + case 8: + case 32: + colours = (1 << bpp); + break; + default: + g_message (_("illegal bpp value in image: %hhu"), bpp); + return -1; + } + width = header[4] + (256 * header[5]); height = header[6] + (256 * header[7]); offx = header[8] + (256 * header[9]); offy = header[10] + (256 * header[11]); } + if ((width == 0) || (height == 0) || (width + offx > GIMP_MAX_IMAGE_SIZE) || + (height + offy > GIMP_MAX_IMAGE_SIZE)) + { + g_message (_("illegal image dimensions: width: %d, horizontal offset: " + "%d, height: %d, vertical offset: %d"), + width, offx, height, offy); + return -1; + } + if (bpp == 32) image = gimp_image_new (width + offx, height + offy, GIMP_RGB); else @@ -378,7 +443,14 @@ load_image (const gchar *file, switch (bpp) { case 4: - fread (buffer, (width+1)/2, 1, fp); + n_read = fread (buffer, (width+1)/2, 1, fp); + + if (n_read < 1) + { + g_message (_("EOF or error while reading image data")); + return -1; + } + for (j = 0, k = 0; j < width*2; j+= 4, ++k) { if (buffer[k] / 16 == 0) @@ -405,7 +477,14 @@ load_image (const gchar *file, break; case 8: - fread (buffer, width, 1, fp); + n_read = fread (buffer, width, 1, fp); + + if (n_read < 1) + { + g_message (_("EOF or error while reading image data")); + return -1; + } + for (j = 0, k = 0; j < width*2; j+= 2, ++k) { if (buffer[k] == 0) @@ -422,7 +501,14 @@ load_image (const gchar *file, break; case 32: - fread (line, width*4, 1, fp); + n_read = fread (line, width*4, 1, fp); + + if (n_read < 1) + { + g_message (_("EOF or error while reading image data")); + return -1; + } + /* The CEL file order is BGR so we need to swap B and R * to get the Gimp RGB order. */ @@ -452,7 +538,7 @@ load_image (const gchar *file, if (bpp != 32) { /* Use palette from file or otherwise default grey palette */ - palette = g_new (guchar, colours*3); + guchar palette[256*3]; /* Open the file for reading if user picked one */ if (palette_file == NULL) @@ -462,12 +548,22 @@ load_image (const gchar *file, else { fp = fopen (palette_file, "r"); + + if (fp == NULL) + { + g_message (_("Could not open '%s' for reading: %s"), + gimp_filename_to_utf8 (palette_file), + g_strerror (errno)); + return -1; + } } if (fp != NULL) { - colours = load_palette (fp, palette); + colours = load_palette (palette_file, fp, palette); fclose (fp); + if (colours < 0) + return -1; } else { @@ -478,10 +574,6 @@ load_image (const gchar *file, } gimp_image_set_colormap (image, palette + 3, colours - 1); - - /* Close palette file, give back allocated memory */ - - g_free (palette); } /* Now get everything redrawn and hand back the finished image */ @@ -493,32 +585,91 @@ load_image (const gchar *file, } static gint -load_palette (FILE *fp, +load_palette (const gchar *file, + FILE *fp, guchar palette[]) { guchar header[32]; /* File header */ guchar buffer[2]; - int i, bpp, colours= 0; + guchar file_mark, bpp; + gint i, colours = 0; + size_t n_read; + + n_read = fread (header, 4, 1, fp); + + if (n_read < 1) + { + g_message (_("'%s': EOF or error while reading palette header"), + gimp_filename_to_utf8 (file)); + return -1; + } - fread (header, 4, 1, fp); if (!strncmp(header, "KiSS", 4)) { - fread (header+4, 28, 1, fp); + n_read = fread (header+4, 28, 1, fp); + + if (n_read < 1) + { + g_message (_("'%s': EOF or error while reading palette header"), + gimp_filename_to_utf8 (file)); + return -1; + } + + file_mark = header[4]; + if (file_mark != 0x10) + { + g_message (_("'%s': is not a KCF palette file"), + gimp_filename_to_utf8 (file)); + return -1; + } + bpp = header[5]; + if (bpp != 12 && bpp != 24) + { + g_message (_("'%s': illegal bpp value in palette: %hhu"), + gimp_filename_to_utf8 (file), bpp); + return -1; + } + colours = header[8] + header[9] * 256; - if (bpp == 12) + if (colours != 16 && colours != 256) + { + g_message (_("'%s': illegal number of colors: %u"), + gimp_filename_to_utf8 (file), colours); + return -1; + } + + switch (bpp) { + case 12: for (i= 0; i < colours; ++i) { - fread (buffer, 1, 2, fp); + n_read = fread (buffer, 1, 2, fp); + + if (n_read < 2) + { + g_message (_("'%s': EOF or error while reading palette data"), + gimp_filename_to_utf8 (file)); + return -1; + } + palette[i*3]= buffer[0] & 0xf0; palette[i*3+1]= (buffer[1] & 0x0f) * 16; palette[i*3+2]= (buffer[0] & 0x0f) * 16; } - } - else - { - fread (palette, colours, 3, fp); + break; + case 24: + n_read = fread (palette, colours, 3, fp); + + if (n_read < 3) + { + g_message (_("'%s': EOF or error while reading palette data"), + gimp_filename_to_utf8 (file)); + return -1; + } + break; + default: + g_assert_not_reached (); } } else @@ -527,7 +678,15 @@ load_palette (FILE *fp, fseek (fp, 0, SEEK_SET); for (i= 0; i < colours; ++i) { - fread (buffer, 1, 2, fp); + n_read = fread (buffer, 1, 2, fp); + + if (n_read < 2) + { + g_message (_("'%s': EOF or error while reading palette data"), + gimp_filename_to_utf8 (file)); + return -1; + } + palette[i*3] = buffer[0] & 0xf0; palette[i*3+1] = (buffer[1] & 0x0f) * 16; palette[i*3+2] = (buffer[0] & 0x0f) * 16; -- 1.7.10.4