diff --git a/SOURCES/gimp-2.8.22-fix-fclose-leak.patch b/SOURCES/gimp-2.8.22-fix-fclose-leak.patch new file mode 100644 index 0000000..7304182 --- /dev/null +++ b/SOURCES/gimp-2.8.22-fix-fclose-leak.patch @@ -0,0 +1,479 @@ +From 523d9b4e96da5de6f6324fa727df1ac2cc36371a Mon Sep 17 00:00:00 2001 +From: Josef Ridky +Date: Thu, 23 Aug 2018 10:05:34 +0200 +Subject: [PATCH] OpenScanHub: Fix a leak with missing fclose in file-xmc.c + +cherry picked from commit 2987f012f9289b7d608adbccc73166800b3dcf6a +The code to output "seems to have an incorrect toc size." is not +implemented, so no change about the part from the same commit. +--- + plug-ins/common/file-cel.c | 9 +++++ + plug-ins/common/file-gif-load.c | 12 ++++++ + plug-ins/common/file-xbm.c | 6 +++ + plug-ins/common/file-xmc.c | 53 +++++++++++++++++++------- + plug-ins/file-fli/fli-gimp.c | 11 +++++- + plug-ins/pygimp/plug-ins/whirlpinch.py | 2 +- + 6 files changed, 77 insertions(+), 16 deletions(-) + +diff --git a/plug-ins/common/file-cel.c b/plug-ins/common/file-cel.c +index 4803275aa5..12418c4949 100644 +--- a/plug-ins/common/file-cel.c ++++ b/plug-ins/common/file-cel.c +@@ -365,6 +365,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("EOF or error while reading image header")); ++ fclose (fp); + return -1; + } + +@@ -385,6 +386,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("EOF or error while reading image header")); ++ fclose (fp); + return -1; + } + +@@ -393,6 +395,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("is not a CEL image file")); ++ fclose (fp); + return -1; + } + +@@ -407,6 +410,7 @@ load_image (const gchar *file, + default: + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("illegal bpp value in image: %hhu"), bpp); ++ fclose (fp); + return -1; + } + +@@ -423,6 +427,7 @@ load_image (const gchar *file, + _("illegal image dimensions: width: %d, horizontal offset: " + "%d, height: %d, vertical offset: %d"), + width, offx, height, offy); ++ fclose (fp); + return -1; + } + +@@ -472,6 +477,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("EOF or error while reading image data")); ++ fclose (fp); + return -1; + } + +@@ -507,6 +513,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("EOF or error while reading image data")); ++ fclose (fp); + return -1; + } + +@@ -532,6 +539,7 @@ load_image (const gchar *file, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("EOF or error while reading image data")); ++ fclose (fp); + return -1; + } + +@@ -549,6 +557,7 @@ load_image (const gchar *file, + default: + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported bit depth (%d)!"), bpp); ++ fclose (fp); + return -1; + } + +diff --git a/plug-ins/common/file-gif-load.c b/plug-ins/common/file-gif-load.c +index 2aee9f37d9..9aa3f6ca0f 100644 +--- a/plug-ins/common/file-gif-load.c ++++ b/plug-ins/common/file-gif-load.c +@@ -365,6 +365,7 @@ load_image (const gchar *filename, + if (! ReadOK (fd, buf, 6)) + { + g_message ("Error reading magic number"); ++ fclose (fd); + return -1; + } + +@@ -372,6 +373,7 @@ load_image (const gchar *filename, + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s", _("This is not a GIF file")); ++ fclose (fd); + return -1; + } + +@@ -381,12 +383,14 @@ load_image (const gchar *filename, + if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) + { + g_message ("Bad version number, not '87a' or '89a'"); ++ fclose (fd); + return -1; + } + + if (! ReadOK (fd, buf, 7)) + { + g_message ("Failed to read screen descriptor"); ++ fclose (fd); + return -1; + } + +@@ -404,6 +408,7 @@ load_image (const gchar *filename, + &GifScreen.GrayScale)) + { + g_message ("Error reading global colormap"); ++ fclose (fd); + return -1; + } + } +@@ -421,12 +426,14 @@ load_image (const gchar *filename, + if (! ReadOK (fd, &c, 1)) + { + g_message ("EOF / read error on image data"); ++ fclose (fd); + return image_ID; /* will be -1 if failed on first image! */ + } + + if (c == ';') + { + /* GIF terminator */ ++ fclose (fd); + return image_ID; + } + +@@ -436,6 +443,7 @@ load_image (const gchar *filename, + if (! ReadOK (fd, &c, 1)) + { + g_message ("EOF / read error on extension function code"); ++ fclose (fd); + return image_ID; /* will be -1 if failed on first image! */ + } + +@@ -455,6 +463,7 @@ load_image (const gchar *filename, + if (! ReadOK (fd, buf, 9)) + { + g_message ("Couldn't read left/top/width/height"); ++ fclose (fd); + return image_ID; /* will be -1 if failed on first image! */ + } + +@@ -467,6 +476,7 @@ load_image (const gchar *filename, + if (! ReadColorMap (fd, bitPixel, localColorMap, &grayScale)) + { + g_message ("Error reading local colormap"); ++ fclose (fd); + return image_ID; /* will be -1 if failed on first image! */ + } + +@@ -514,6 +524,8 @@ load_image (const gchar *filename, + break; + } + ++ fclose (fd); ++ + return image_ID; + } + +diff --git a/plug-ins/common/file-xbm.c b/plug-ins/common/file-xbm.c +index cdf30eaf90..5737001792 100644 +--- a/plug-ins/common/file-xbm.c ++++ b/plug-ins/common/file-xbm.c +@@ -820,6 +820,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nCould not read header (ftell == %ld)"), + gimp_filename_to_utf8 (filename), ftell (fp)); ++ fclose (fp); + return -1; + } + +@@ -827,6 +828,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nNo image width specified"), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -834,6 +836,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nImage width is larger than GIMP can handle"), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -841,6 +844,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nNo image height specified"), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -848,6 +852,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nImage height is larger than GIMP can handle"), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -855,6 +860,7 @@ load_image (const gchar *filename, + { + g_message (_("'%s':\nNo image data type specified"), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +diff --git a/plug-ins/common/file-xmc.c b/plug-ins/common/file-xmc.c +index a75c8fbde3..6d054fc4cc 100644 +--- a/plug-ins/common/file-xmc.c ++++ b/plug-ins/common/file-xmc.c +@@ -659,10 +659,11 @@ load_image (const gchar *filename, GError **error) + return -1; + } + +- if (!XcursorFileLoad (fp, &commentsp, &imagesp)) ++ if (! XcursorFileLoad (fp, &commentsp, &imagesp)) + { + g_set_error (error, 0, 0, _("'%s' is not a valid X cursor."), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -679,6 +680,7 @@ load_image (const gchar *filename, GError **error) + g_set_error (error, 0, 0, + _("Frame %d of '%s' is too wide for an X cursor."), + i + 1, gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + if (imagesp->images[i]->height > MAX_LOAD_DIMENSION) +@@ -686,6 +688,7 @@ load_image (const gchar *filename, GError **error) + g_set_error (error, 0, 0, + _("Frame %d of '%s' is too high for an X cursor."), + i + 1, gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + } +@@ -704,7 +707,10 @@ load_image (const gchar *filename, GError **error) + gimp_image_set_filename (image_ID, filename); + + if (! set_hotspot_to_parasite (image_ID)) +- return -1; ++ { ++ fclose (fp); ++ return -1; ++ } + + /* Temporary buffer */ + tmppixel = g_new (guint32, img_width * img_height); +@@ -722,9 +728,12 @@ load_image (const gchar *filename, GError **error) + ,i ,delay, imagesp->images[i]->width, imagesp->images[i]->height); + + framename = make_framename (imagesp->images[i]->size, delay, +- DISPLAY_DIGIT(imagesp->nimage), error); +- if (!framename) +- return -1; ++ DISPLAY_DIGIT (imagesp->nimage), error); ++ if (! framename) ++ { ++ fclose (fp); ++ return -1; ++ } + + layer_ID = gimp_layer_new (image_ID, framename, + imagesp->images[i]->width, +@@ -782,6 +791,7 @@ load_image (const gchar *filename, GError **error) + parasiteName[commentsp->comments[i]->comment_type -1])) + { + DM_XMC ("Failed to write %ith comment.\n", i); ++ fclose (fp); + return -1; + } + } +@@ -889,6 +899,7 @@ load_thumbnail (const gchar *filename, gint32 thumb_size, + g_set_error (error, 0, 0, + _("there is no image chunk in \"%s\"."), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -931,6 +942,7 @@ load_thumbnail (const gchar *filename, gint32 thumb_size, + g_set_error (error, 0, 0, + _("'%s' is too wide for an X cursor."), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + if (*thumb_height > MAX_LOAD_DIMENSION) +@@ -938,6 +950,7 @@ load_thumbnail (const gchar *filename, gint32 thumb_size, + g_set_error (error, 0, 0, + _("'%s' is too high for an X cursor."), + gimp_filename_to_utf8 (filename)); ++ fclose (fp); + return -1; + } + +@@ -1462,7 +1475,8 @@ save_image (const gchar *filename, + imagesp = XcursorImagesCreate(nlayers); + if (!imagesp) + { +- DM_XMC("Failed to XcursorImagesCreate!\n"); ++ DM_XMC ("Failed to XcursorImagesCreate!\n"); ++ fclose (fp); + return FALSE; + } + imagesp->nimage = nlayers; +@@ -1499,14 +1513,18 @@ save_image (const gchar *filename, + { + g_set_error (error, 0, 0, + _("Frame '%s' is too wide. Please reduce to no more than %dpx."), +- gimp_any_to_utf8 (framename, -1, NULL), MAX_SAVE_DIMENSION); ++ gimp_any_to_utf8 (framename, -1, NULL), ++ MAX_SAVE_DIMENSION); ++ fclose (fp); + return FALSE; + } + if (drawable->height > MAX_SAVE_DIMENSION) + { + g_set_error (error, 0, 0, + _("Frame '%s' is too high. Please reduce to no more than %dpx."), +- gimp_any_to_utf8 (framename, -1, NULL), MAX_SAVE_DIMENSION); ++ gimp_any_to_utf8 (framename, -1, NULL), ++ MAX_SAVE_DIMENSION); ++ fclose (fp); + return FALSE; + } + if (drawable->height == 0 ||drawable->width == 0) +@@ -1514,6 +1532,7 @@ save_image (const gchar *filename, + g_set_error (error, 0, 0, + _("Width and/or height of frame '%s' is zero!"), + gimp_any_to_utf8 (framename, -1, NULL)); ++ fclose (fp); + return FALSE; + } + +@@ -1535,6 +1554,7 @@ save_image (const gchar *filename, + if (!imagesp->images[i]) + { + DM_XMC ("Failed to XcursorImageCreate.\n"); ++ fclose (fp); + return FALSE; + } + imagesp->images[i]->pixels[0] = 0x0; +@@ -1557,6 +1577,7 @@ save_image (const gchar *filename, + "Try to change the hot spot position, " + "layer geometry or save without auto-crop."), + gimp_any_to_utf8 (framename, -1, NULL)); ++ fclose (fp); + return FALSE; + } + } +@@ -1589,6 +1610,7 @@ save_image (const gchar *filename, + if (!imagesp->images[i]) + { + DM_XMC ("Failed to XcursorImageCreate.\n"); ++ fclose (fp); + return FALSE; + } + /* +@@ -1636,8 +1658,11 @@ save_image (const gchar *filename, + imagesp->images[i]->delay, + DISPLAY_DIGIT(imagesp->nimage), + error); +- if (!framename) +- return FALSE; ++ if (! framename) ++ { ++ fclose (fp); ++ return FALSE; ++ } + + gimp_item_set_name (orig_layers[nlayers - 1 - i], framename); + g_free (framename); +@@ -1691,8 +1716,9 @@ save_image (const gchar *filename, + { + if (! XcursorFileSave (fp, commentsp, imagesp)) + { +- DM_XMC("Failed to XcursorFileSave.\t%p\t%p\t%p\n", +- fp, commentsp, imagesp); ++ DM_XMC ("Failed to XcursorFileSave.\t%p\t%p\t%p\n", ++ fp, commentsp, imagesp); ++ fclose (fp); + return FALSE; + } + +@@ -1701,7 +1727,8 @@ save_image (const gchar *filename, + { + if (! XcursorFileSaveImages (fp, imagesp)) + { +- DM_XMC("Failed to XcursorFileSaveImages.\t%p\t%p\n", fp, imagesp); ++ DM_XMC ("Failed to XcursorFileSaveImages.\t%p\t%p\n", fp, imagesp); ++ fclose (fp); + return FALSE; + } + } +diff --git a/plug-ins/file-fli/fli-gimp.c b/plug-ins/file-fli/fli-gimp.c +index e3843eb5db..be772d3c3f 100644 +--- a/plug-ins/file-fli/fli-gimp.c ++++ b/plug-ins/file-fli/fli-gimp.c +@@ -505,9 +505,14 @@ load_image (const gchar *filename, + + fli_read_header (file, &fli_header); + if (fli_header.magic == NO_HEADER) +- return -1; ++ { ++ fclose (file); ++ return -1; ++ } + else +- fseek (file, 128, SEEK_SET); ++ { ++ fseek (file, 128, SEEK_SET); ++ } + + /* + * Fix parameters +@@ -528,11 +533,13 @@ load_image (const gchar *filename, + if (to_frame < 1) + { + /* nothing to do ... */ ++ fclose (file); + return -1; + } + if (from_frame >= fli_header.frames) + { + /* nothing to do ... */ ++ fclose (file); + return -1; + } + if (to_frame>fli_header.frames) +diff --git a/plug-ins/pygimp/plug-ins/whirlpinch.py b/plug-ins/pygimp/plug-ins/whirlpinch.py +index 7897f13294..e1fbc376de 100755 +--- a/plug-ins/pygimp/plug-ins/whirlpinch.py ++++ b/plug-ins/pygimp/plug-ins/whirlpinch.py +@@ -125,7 +125,7 @@ def whirl_pinch(image, drawable, whirl, pinch, radius): + if cx >= 0: ix = int(cx) + else: ix = -(int(-cx) + 1) + if cy >= 0: iy = int(cy) +- else: iy = -(int(-cx) + 1) ++ else: iy = -(int(-cy) + 1) + pixel[0] = pft.get_pixel(ix, iy) + pixel[1] = pft.get_pixel(ix+1, iy) + pixel[2] = pft.get_pixel(ix, iy+1) +-- +2.43.0 + diff --git a/SOURCES/gimp-CVE-2022-30067.patch b/SOURCES/gimp-CVE-2022-30067.patch new file mode 100644 index 0000000..99dee94 --- /dev/null +++ b/SOURCES/gimp-CVE-2022-30067.patch @@ -0,0 +1,39 @@ +diff -ruNp a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c +--- a/app/xcf/xcf-load.c 2017-04-30 23:47:39.000000000 +0200 ++++ b/app/xcf/xcf-load.c 2022-12-06 13:56:21.018561154 +0100 +@@ -657,7 +657,12 @@ xcf_load_image_props (XcfInfo *info, + break; + + case PROP_PATHS: +- xcf_load_old_paths (info, image); ++ { ++ goffset base = info->cp; ++ ++ if (! xcf_load_old_paths (info, image)) ++ xcf_seek_pos (info, base + prop_size, NULL); ++ } + break; + + case PROP_USER_UNIT: +@@ -1765,8 +1770,11 @@ xcf_load_old_paths (XcfInfo *info, + info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1); + info->cp += xcf_read_int32 (info->fp, &num_paths, 1); + ++/* GIMP_LOG (XCF, "Number of old paths: %u", num_paths); */ ++ + while (num_paths-- > 0) +- xcf_load_old_path (info, image); ++ if (! xcf_load_old_path (info, image)) ++ return FALSE; + + active_vectors = + GIMP_VECTORS (gimp_container_get_child_by_index (gimp_image_get_vectors (image), +@@ -1817,7 +1825,7 @@ xcf_load_old_path (XcfInfo *info, + } + else if (version != 1) + { +- g_warning ("Unknown path type. Possibly corrupt XCF file"); ++ g_warning ("Unknown path type (version: %u). Possibly corrupt XCF file.\n", version); + + return FALSE; + } diff --git a/SOURCES/gimp-CVE-2022-32990.patch b/SOURCES/gimp-CVE-2022-32990.patch new file mode 100644 index 0000000..24e1515 --- /dev/null +++ b/SOURCES/gimp-CVE-2022-32990.patch @@ -0,0 +1,31 @@ +From 22af0bcfe67c1c86381f33975ca7fdbde6b36b39 Mon Sep 17 00:00:00 2001 +From: Jacob Boerema +Date: Sun, 5 Jun 2022 15:38:24 -0400 +Subject: [PATCH] app: fix #8230 crash in gimp_layer_invalidate_boundary when + channel is NULL + +gimp_channel_is_empty returns FALSE if channel is NULL. This causes +gimp_layer_invalidate_boundary to crash if the mask channel is NULL. + +With a NULL channel gimp_channel_is_empty should return TRUE, just like +the similar gimp_image_is_empty does, because returning FALSE here +suggests we have a non empty channel. +--- + app/core/gimpchannel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c +index 7b6a9851ae..502821ba58 100644 +--- a/app/core/gimpchannel.c ++++ b/app/core/gimpchannel.c +@@ -1827,7 +1827,7 @@ gimp_channel_boundary (GimpChannel *channel, + gboolean + gimp_channel_is_empty (GimpChannel *channel) + { +- g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); ++ g_return_val_if_fail (GIMP_IS_CHANNEL (channel), TRUE); + + return GIMP_CHANNEL_GET_CLASS (channel)->is_empty (channel); + } +-- +GitLab diff --git a/SOURCES/gimp-CVE-2023-44442.patch b/SOURCES/gimp-CVE-2023-44442.patch new file mode 100644 index 0000000..d4e978d --- /dev/null +++ b/SOURCES/gimp-CVE-2023-44442.patch @@ -0,0 +1,30 @@ +From 592d80b282f3bf09e8e4e07a2ccdb57c6a9a0a0b Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Thu, 25 Jan 2024 13:34:59 +0900 +Subject: [PATCH] plug-ins: Fix vulnerability in file-psd + +This patch adds a missing break statement after an error condition +is detected to prevent the code from continuing afterwards. +Fixes CVE-2023-44442 + +upstream commit: 985c0a20e18b5b3b8a48ee9cb12287b1d5732d3d + +--- + plug-ins/file-psd/psd-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/plug-ins/file-psd/psd-util.c b/plug-ins/file-psd/psd-util.c +index 661d17e..9452e04 100644 +--- a/plug-ins/file-psd/psd-util.c ++++ b/plug-ins/file-psd/psd-util.c +@@ -389,6 +389,7 @@ decode_packbits (const gchar *src, + { + IFDBG(2) g_debug ("Overrun in packbits replicate of %d chars", n - unpack_left); + error_code = 2; ++ break; + } + dat = *src; + for (; n > 0; --n) +-- +2.43.0 + diff --git a/SOURCES/gimp-CVE-2023-44444.patch b/SOURCES/gimp-CVE-2023-44444.patch new file mode 100644 index 0000000..c9b901d --- /dev/null +++ b/SOURCES/gimp-CVE-2023-44444.patch @@ -0,0 +1,33 @@ +From b992bc60103d8c3bbd2aa46293c9f0e4f350114c Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Thu, 25 Jan 2024 13:38:12 +0900 +Subject: [PATCH] plug-ins: Fix PSP vulnerability (ZDI-CAN-22097) + +When reading RLE compressed data, a buffer was allocated to 127 bytes. +However, it can potentially be used to read 128 bytes, leading to a +off-by-one vulnerability. This patch allocates 128 bytes to the buffer +to prevent this from occurring. +Fixes CVE-2023-44444 + +upstream commit: e1bfd87195e4fe60a92df70cde65464d032dd3c1 + +--- + plug-ins/common/file-psp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plug-ins/common/file-psp.c b/plug-ins/common/file-psp.c +index 7c3d04b..f5c5d94 100644 +--- a/plug-ins/common/file-psp.c ++++ b/plug-ins/common/file-psp.c +@@ -1196,7 +1196,7 @@ read_channel_data (FILE *f, + + q = pixels[0] + offset; + endq = q + npixels * bytespp; +- buf = g_malloc (127); ++ buf = g_malloc (128); + while (q < endq) + { + fread (&runcount, 1, 1, f); +-- +2.43.0 + diff --git a/SOURCES/gimp-buffer-overflow.patch b/SOURCES/gimp-buffer-overflow.patch new file mode 100644 index 0000000..6a23f30 --- /dev/null +++ b/SOURCES/gimp-buffer-overflow.patch @@ -0,0 +1,603 @@ +From b7219d51b150fa10018ccc810824940ea56284f1 Mon Sep 17 00:00:00 2001 +From: Jacob Boerema +Date: Tue, 8 Nov 2022 14:10:05 -0500 +Subject: [PATCH] plug-ins: improve security in flame plug-in + +- Use g_malloc* functions instead of malloc, so we don't continue on +failed allocations unless we test for NULL. +- Make sure we don't iterate past the known number of control points (ncps). +- Safely allocate, initialize and free points. Since points seems to be +used uninitialized, we use g_malloc0 to set everything to 0. + +(cherry picked from commit 981979bb39a9453f33d8c33f12ef19ff15be25ba) +--- + plug-ins/flame/libifs.c | 17 +++++++++++++---- + plug-ins/flame/rect.c | 13 +++++++------ + 2 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/plug-ins/flame/libifs.c b/plug-ins/flame/libifs.c +index 16259d46a5..461ac5c96d 100644 +--- a/plug-ins/flame/libifs.c ++++ b/plug-ins/flame/libifs.c +@@ -692,6 +692,8 @@ interpolate (control_point cps[], + int i, j, i1, i2; + double c0, c1, t; + ++ g_return_if_fail (ncps > 0); ++ + if (ncps == 1) + { + *result = cps[0]; +@@ -710,12 +712,14 @@ interpolate (control_point cps[], + else + { + i1 = 0; +- while (cps[i1].time < time) ++ while (i1 < ncps && cps[i1].time < time) + i1++; + i1--; + i2 = i1 + 1; +- if (time - cps[i1].time > -1e-7 && +- time - cps[i1].time < 1e-7) ++ ++ if (i2 == ncps || ++ (time - cps[i1].time > -1e-7 && ++ time - cps[i1].time < 1e-7)) + { + *result = cps[i1]; + return; +@@ -1373,7 +1380,8 @@ estimate_bounding_box (control_point *cp, + int low_target = batch * eps; + int high_target = batch - low_target; + point min, max, delta; +- point *points = malloc (sizeof (point) * batch); ++ point *points = g_malloc0 (sizeof (point) * batch); ++ + iterate (cp, batch, 20, points); + + min[0] = min[1] = 1e10; +@@ -1420,6 +1428,7 @@ estimate_bounding_box (control_point *cp, + delta[0] = delta[0] / 2.0; + delta[1] = delta[1] / 2.0; + } ++ g_free (points); + } + + /* this has serious flaws in it */ +diff --git a/plug-ins/flame/rect.c b/plug-ins/flame/rect.c +index 4951bfdfc8..0ff0f5f89c 100644 +--- a/plug-ins/flame/rect.c ++++ b/plug-ins/flame/rect.c +@@ -20,6 +20,7 @@ + + #include + ++#include "libgimp/gimp.h" + + /* for batch + * interpolate +@@ -122,7 +123,7 @@ render_rectangle (frame_spec *spec, + if ((filter_width ^ oversample) & 1) + filter_width++; + +- filter = malloc (sizeof (double) * filter_width * filter_width); ++ filter = g_malloc (sizeof (double) * filter_width * filter_width); + /* fill in the coefs */ + for (i = 0; i < filter_width; i++) + for (j = 0; j < filter_width; j++) +@@ -135,8 +136,8 @@ render_rectangle (frame_spec *spec, + } + normalize_vector(filter, filter_width * filter_width); + } +- temporal_filter = malloc (sizeof (double) * nbatches); +- temporal_deltas = malloc (sizeof (double) * nbatches); ++ temporal_filter = g_malloc (sizeof (double) * nbatches); ++ temporal_deltas = g_malloc (sizeof (double) * nbatches); + if (nbatches > 1) + { + double t; +@@ -173,11 +174,11 @@ render_rectangle (frame_spec *spec, + { + if (last_block != NULL) + free (last_block); +- last_block = malloc (memory_rqd); ++ last_block = g_try_malloc (memory_rqd); + if (last_block == NULL) + { +- fprintf (stderr, "render_rectangle: cannot malloc %d bytes.\n", +- memory_rqd); ++ g_printerr ("render_rectangle: cannot malloc %d bytes.\n", ++ memory_rqd); + exit (1); + } + last_block_size = memory_rqd; +--- +From 5481b110f955213cca2e893f71b275a19f2530f7 Mon Sep 17 00:00:00 2001 +From: Jacob Boerema +Date: Mon, 31 Oct 2022 14:22:44 -0400 +Subject: [PATCH] plug-ins: fix crash when reading corrupt flame settings file + +Thanks to a report by Stefan Cornelius, we became aware that the flame +plug-in does no checking for correct input when loading a pre-saved +settings file. + +I reworked the parser to read one or more values based on the type of +token, making sure we also don't read past the end of our token buffer. + +All int values have a min and max value set. If any unexpected input is +encountered, we will give a warning. + +(cherry picked from commit 89c83ef4c7a83bca5ca40f79d638ff365eb61464) +--- + plug-ins/flame/libifs.c | 341 +++++++++++++++++++++++++++++----------- + 1 file changed, 251 insertions(+), 90 deletions(-) + +diff --git a/plug-ins/flame/libifs.c b/plug-ins/flame/libifs.c +index 7f158c853f..16259d46a5 100644 +--- a/plug-ins/flame/libifs.c ++++ b/plug-ins/flame/libifs.c +@@ -911,8 +911,6 @@ compare_xforms (const void *va, + + /* + * given a pointer to a string SS, fill fields of a control point CP. +- * return a pointer to the first unused char in SS. totally barfucious, +- * must integrate with tcl soon... + */ + + void +@@ -921,10 +919,9 @@ parse_control_point (char **ss, + { + char *argv[MAXARGS]; + int argc, i, j; +- int set_cm = 0, set_image_size = 0, set_nbatches = 0, set_white_level = 0, set_cmap_inter = 0; +- int set_spatial_oversample = 0; +- double *slot = NULL, xf, cm, t, nbatches, white_level, spatial_oversample, cmap_inter; +- double image_size[2]; ++ gint64 xf_index = 0; ++ gint parse_errors = 0; ++ double *slot = NULL, t; + + for (i = 0; i < NXFORMS; i++) + { +@@ -949,94 +946,258 @@ parse_control_point (char **ss, + } + + tokenize (ss, argv, &argc); +- for (i = 0; i < argc; i++) ++ ++ i = 0; ++ while (i < argc) + { +- if (streql("xform", argv[i])) +- slot = &xf; +- else if (streql("time", argv[i])) +- slot = &cp->time; +- else if (streql("brightness", argv[i])) +- slot = &cp->brightness; +- else if (streql("contrast", argv[i])) +- slot = &cp->contrast; +- else if (streql("gamma", argv[i])) +- slot = &cp->gamma; +- else if (streql("zoom", argv[i])) +- slot = &cp->zoom; +- else if (streql("image_size", argv[i])) +- { +- slot = image_size; +- set_image_size = 1; +- } +- else if (streql("center", argv[i])) +- slot = cp->center; +- else if (streql("pulse", argv[i])) +- slot = (double *) cp->pulse; +- else if (streql("wiggle", argv[i])) +- slot = (double *) cp->wiggle; +- else if (streql("pixels_per_unit", argv[i])) +- slot = &cp->pixels_per_unit; +- else if (streql("spatial_filter_radius", argv[i])) +- slot = &cp->spatial_filter_radius; +- else if (streql("sample_density", argv[i])) +- slot = &cp->sample_density; +- else if (streql("nbatches", argv[i])) +- { +- slot = &nbatches; +- set_nbatches = 1; +- } +- else if (streql("white_level", argv[i])) +- { +- slot = &white_level; +- set_white_level = 1; +- } +- else if (streql("spatial_oversample", argv[i])) +- { +- slot = &spatial_oversample; +- set_spatial_oversample = 1; +- } +- else if (streql("cmap", argv[i])) +- { +- slot = &cm; +- set_cm = 1; +- } +- else if (streql("density", argv[i])) +- slot = &cp->xform[(int)xf].density; +- else if (streql("color", argv[i])) +- slot = &cp->xform[(int)xf].color; +- else if (streql("coefs", argv[i])) +- { +- slot = cp->xform[(int)xf].c[0]; +- cp->xform[(int)xf].density = 1.0; +- } +- else if (streql("var", argv[i])) +- slot = cp->xform[(int)xf].var; +- else if (streql("cmap_inter", argv[i])) +- { +- slot = &cmap_inter; +- set_cmap_inter = 1; ++ gint itoken; ++ ++ itoken = i; ++ if (i < argc) ++ { ++ /* First value belonging to token. */ ++ i++; + } + else +- *slot++ = g_strtod(argv[i], NULL); +- } +- if (set_cm) +- { +- cp->cmap_index = (int) cm; +- get_cmap(cp->cmap_index, cp->cmap, 256); +- } +- if (set_image_size) +- { +- cp->width = (int) image_size[0]; +- cp->height = (int) image_size[1]; ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ ++ if (streql ("xform", argv[itoken])) ++ { ++ if (! g_ascii_string_to_signed (argv[i++], 10, 0, NXFORMS-1, &xf_index, NULL)) ++ { ++ g_printerr ("Invalid xform index '%s'\n", argv[i-1]); ++ parse_errors++; ++ xf_index = 0; ++ } ++ } ++ else if (streql ("density", argv[itoken])) ++ { ++ cp->xform[xf_index].density = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("color", argv[itoken])) ++ { ++ cp->xform[xf_index].color = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("coefs", argv[itoken])) ++ { ++ /* We need 6 coef values and we know are at the first */ ++ if (i + 5 >= argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ slot = cp->xform[xf_index].c[0]; ++ for (j = 0; j < 6; j++) ++ { ++ *slot++ = g_strtod (argv[i++], NULL); ++ } ++ cp->xform[xf_index].density = 1.0; ++ } ++ else if (streql ("var", argv[itoken])) ++ { ++ /* We need NVARS var values and we know are at the first */ ++ if (i + NVARS > argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ slot = cp->xform[xf_index].var; ++ for (j = 0; j < NVARS; j++) ++ { ++ *slot++ = g_strtod (argv[i++], NULL); ++ } ++ } ++ else if (streql ("time", argv[itoken])) ++ { ++ cp->time = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("brightness", argv[itoken])) ++ { ++ cp->brightness = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("contrast", argv[itoken])) ++ { ++ cp->contrast = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("gamma", argv[itoken])) ++ { ++ cp->gamma = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("zoom", argv[itoken])) ++ { ++ cp->zoom = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("image_size", argv[itoken])) ++ { ++ gint64 w, h; ++ ++ /* We need 2 values and we know are at the first */ ++ if (i + 1 >= argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ if (! g_ascii_string_to_signed (argv[i++], 10, 1, GIMP_MAX_IMAGE_SIZE, &w, NULL)) ++ { ++ g_printerr ("Ignoring invalid image width '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else if (! g_ascii_string_to_signed (argv[i++], 10, 1, GIMP_MAX_IMAGE_SIZE, &h, NULL)) ++ { ++ g_printerr ("Ignoring invalid image_size heigth '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->width = w; ++ cp->height = h; ++ } ++ } ++ else if (streql ("center", argv[itoken])) ++ { ++ /* We need 2 values and we know are at the first */ ++ if (i + 1 >= argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ cp->center[0] = g_strtod (argv[i++], NULL); ++ cp->center[1] = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("pixels_per_unit", argv[itoken])) ++ { ++ cp->pixels_per_unit = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("pulse", argv[itoken])) ++ { ++ /* We need 4 values and we know are at the first */ ++ if (i + 3 >= argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ slot = &cp->pulse[0][0]; ++ for (j = 0; j < 4; j++) ++ { ++ *slot++ = g_strtod (argv[i++], NULL); ++ } ++ } ++ else if (streql ("wiggle", argv[itoken])) ++ { ++ /* We need 4 values and we know are at the first */ ++ if (i + 3 >= argc) ++ { ++ g_printerr ("Not enough parameters. File may be corrupt!\n"); ++ parse_errors++; ++ break; ++ } ++ slot = &cp->wiggle[0][0]; ++ for (j = 0; j < 4; j++) ++ { ++ *slot++ = g_strtod (argv[i++], NULL); ++ } ++ } ++ else if (streql ("spatial_oversample", argv[itoken])) ++ { ++ gint64 oversample; ++ ++ /* Values in the gui seem to be between 1 and 4 */ ++ if (! g_ascii_string_to_signed (argv[i++], 10, 1, 4, &oversample, NULL)) ++ { ++ g_printerr ("Ignoring invalid spatial oversample value '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->spatial_oversample = oversample; ++ } ++ } ++ else if (streql ("spatial_filter_radius", argv[itoken])) ++ { ++ cp->spatial_filter_radius = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("sample_density", argv[itoken])) ++ { ++ cp->sample_density = g_strtod (argv[i++], NULL); ++ } ++ else if (streql ("nbatches", argv[itoken])) ++ { ++ gint64 nbatches; ++ ++ /* Not sure what the maximum should be. It always seems to be set to 1. */ ++ if (! g_ascii_string_to_signed (argv[i++], 10, 0, 2, &nbatches, NULL)) ++ { ++ g_printerr ("Ignoring invalid nbatches value '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->nbatches = nbatches; ++ } ++ } ++ else if (streql ("white_level", argv[itoken])) ++ { ++ gint64 wl; ++ ++ if (! g_ascii_string_to_signed (argv[i++], 10, 0, 255, &wl, NULL)) ++ { ++ g_printerr ("Ignoring invalid white level value '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->white_level = wl; ++ } ++ } ++ else if (streql ("cmap", argv[itoken])) ++ { ++ gint64 cmi; ++ ++ /* -1 = random */ ++ if (! g_ascii_string_to_signed (argv[i++], 10, -1, 255, &cmi, NULL)) ++ { ++ g_printerr ("Ignoring invalid color map value '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->cmap_index = cmi; ++ } ++ } ++ else if (streql ("cmap_inter", argv[itoken])) ++ { ++ gint64 cmi; ++ ++ /* 0 or 1 */ ++ if (! g_ascii_string_to_signed (argv[i++], 10, 0, 1, &cmi, NULL)) ++ { ++ g_printerr ("Ignoring invalid color interpolate value '%s'\n", argv[i-1]); ++ parse_errors++; ++ } ++ else ++ { ++ cp->cmap_inter = cmi; ++ } ++ } ++ else ++ { ++ g_printerr ("Invalid token '%s'. File may be corrupt!\n", argv[itoken]); ++ parse_errors++; ++ } + } +- if (set_cmap_inter) +- cp->cmap_inter = (int) cmap_inter; +- if (set_nbatches) +- cp->nbatches = (int) nbatches; +- if (set_spatial_oversample) +- cp->spatial_oversample = (int) spatial_oversample; +- if (set_white_level) +- cp->white_level = (int) white_level; ++ ++ if (parse_errors > 0) ++ g_warning ("Input file contains %d errors. File may be corrupt!", parse_errors); ++ + for (i = 0; i < NXFORMS; i++) + { + t = 0.0; +-- +From b36cc3ab3f0440edc611f35cc16442839526aa09 Mon Sep 17 00:00:00 2001 +From: Jacob Boerema +Date: Mon, 31 Oct 2022 14:00:54 -0400 +Subject: [PATCH] plug-ins: fix missing input buffer length checking in flame + +The flame plug-in can read stored settings from a file. The expected +input is that a ; signifies the end of input. + +However, with user input we cannot depend on this to be true, so we need +to make sure that we do not read past the end of our input buffer. +To do so, we add a length check. + +(cherry picked from commit 536c7cbc4b7c5fe5e1d03ac249d74f851a0e2e87) +--- + plug-ins/flame/libifs.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/plug-ins/flame/libifs.c b/plug-ins/flame/libifs.c +index a4af48bb30..7f158c853f 100644 +--- a/plug-ins/flame/libifs.c ++++ b/plug-ins/flame/libifs.c +@@ -842,10 +842,12 @@ tokenize (char **ss, + char *argv[], + int *argc) + { +- char *s = *ss; +- int i = 0, state = 0; ++ char *s = *ss; ++ int i = 0, state = 0; ++ gint len = 0; + +- while (*s != ';') ++ len = strlen (s); ++ while (*s != ';' && len > 0) + { + char c = *s; + switch (state) +@@ -870,6 +872,7 @@ tokenize (char **ss, + state = 0; + } + s++; ++ len--; + } + *s = 0; + *ss = s + 1; +-- +From b3186d72ee559b8ba78900acba134967338bf642 Mon Sep 17 00:00:00 2001 +From: Jacob Boerema +Date: Mon, 31 Oct 2022 13:57:14 -0400 +Subject: [PATCH] plug-ins: fix failure to load flame saved settings from file + +We were using the plug-in name with underscores, which is incorrect. +Since nobody ever complained about this, this doesn't seem to be used +very often. + +We will use the const that defines the plug-in name instead. + +(cherry picked from commit 193596397e6671ccb3684683adf1d2af48c14d05) +--- + plug-ins/flame/flame.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plug-ins/flame/flame.c b/plug-ins/flame/flame.c +index e7480cba1c..f2e3898f65 100644 +--- a/plug-ins/flame/flame.c ++++ b/plug-ins/flame/flame.c +@@ -436,7 +436,7 @@ file_response_callback (GtkFileChooser *chooser, + fclose (f); + /* i want to update the existing dialogue, but it's + too painful */ +- gimp_set_data ("plug_in_flame", &config, sizeof (config)); ++ gimp_set_data (PLUG_IN_PROC, &config, sizeof (config)); + /* gtk_widget_destroy(dialog); */ + set_flame_preview (); + set_edit_preview (); +-- +diff -urNp a/plug-ins/flame/libifs.c b/plug-ins/flame/libifs.c +--- a/plug-ins/flame/libifs.c 2023-01-11 12:37:26.893377867 +0100 ++++ b/plug-ins/flame/libifs.c 2023-01-11 12:38:31.093911423 +0100 +@@ -865,15 +865,18 @@ tokenize (char **ss, + i++; + state = 1; + } ++ break; + case 1: + if (g_ascii_isspace (c)) + { + *s = 0; + state = 0; + } ++ break; + case 2: + if (c == '\n') + state = 0; ++ break; + } + s++; + len--; diff --git a/SPECS/gimp.spec b/SPECS/gimp.spec index 7dc8d24..4df92d5 100644 --- a/SPECS/gimp.spec +++ b/SPECS/gimp.spec @@ -75,7 +75,7 @@ Summary: GNU Image Manipulation Program Name: gimp Epoch: 2 Version: 2.8.22 -Release: %{?prerelprefix}15%{dotprerel}%{dotgitrev}%{?dist} +Release: %{?prerelprefix}25%{dotprerel}%{dotgitrev}%{?dist} # Compute some version related macros. # Ugly, need to get quoting percent signs straight. @@ -89,10 +89,11 @@ Release: %{?prerelprefix}15%{dotprerel}%{dotgitrev}%{?dist} %if ! %unstable %global lib_minor %(echo $[%minor * 100]) %global lib_micro %micro -%else # unstable +%else +# unstable %global lib_minor %(echo $[%minor * 100 + %{micro}]) %global lib_micro 0 -%endif # unstable +%endif %if %{with poppler} # poppler is "GPLv2 or GPLv3" which makes plug-ins linking to libpoppler such @@ -209,6 +210,14 @@ Patch7: gimp-2.8.22-CVE-2017-17788.patch Patch8: gimp-2.8.22-CVE-2017-17789.patch Patch9: gimp-2.8.22-python.patch +Patch10: gimp-CVE-2022-30067.patch +Patch11: gimp-CVE-2022-32990.patch +Patch12: gimp-buffer-overflow.patch +#Patch13: gimp-2.8.22-python-path.patch +Patch14: gimp-CVE-2023-44442.patch +Patch15: gimp-CVE-2023-44444.patch +Patch16: gimp-2.8.22-fix-fclose-leak.patch + # use external help browser directly if help browser plug-in is not built Patch100: gimp-2.8.6-external-help-browser.patch @@ -302,6 +311,13 @@ EOF %patch7 -p1 -b .CVE-17788 %patch8 -p1 -b .CVE-17789 %patch9 -p1 +%patch10 -p1 -b .CVE-2022-30067 +%patch11 -p1 -b .CVE-2022-32990 +%patch12 -p1 -b .buffer-overflow +#%patch13 -p1 -b .python-path +%patch14 -p1 -b .CVE-2023-44442 +%patch15 -p1 -b .CVE-2023-44444 +%patch16 -p1 -b .fclose-leak %if ! %{with helpbrowser} %patch100 -p1 -b .external-help-browser @@ -361,7 +377,7 @@ autoreconf %ifos linux --with-linux-input \ %endif -%if use_poppler +%if %{with poppler} --with-poppler \ %else --without-poppler \ @@ -641,6 +657,38 @@ make check %endif %changelog +* Thu Jan 25 2024 Masahiro Matsuya - 2:2.8.22-25 +- fix CVE-2023-44442 +- fix CVE-2023-44444 +- disable gimp-2.8.22-python-path.patch required for flatpak +- partially cherry-pick from upstream commit 2987f012 to fix fclose leak + Resolves: RHEL-17048 RHEL-17060 + +* Fri Feb 17 2023 Josef Ridky - 2:2.8.22-24 +- fallback to RPM gegl + +* Fri Feb 17 2023 Josef Ridky - 2:2.8.22-23 +- enforce gegl04 + +* Fri Feb 17 2023 Josef Ridky - 2:2.8.22-22 +- change gegl requirement to gegl04 + +* Thu Feb 16 2023 Josef Ridky - 2:2.8.22-21 +- set manual shebang in python files + +* Thu Feb 16 2023 Josef Ridky - 2:2.8.22-20 +- fix python path in source code + +* Wed Jan 11 2023 Josef Ridky - 2:2.8.22-19 +- fix CVE-2022-32990 (#2104192) +- fix buffer overflow (#2143177) + +* Tue Dec 06 2022 Josef Ridky - 2:2.8.22-18 +- fix CVE-2022-30067 (#2091200) + +* Mon Aug 29 2022 Josef Ridky - 2:2.8.22-17 +- spec bump + * Wed Sep 12 2018 Josef Ridky - 2:2.8.22-15 - rebuild for removing pygtk2-libglade