summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gd-2.2.5-heap-based-buffer-overflow.patch28
-rw-r--r--gd-2.2.5-potential-double-free.patch283
-rw-r--r--gd.spec14
3 files changed, 324 insertions, 1 deletions
diff --git a/gd-2.2.5-heap-based-buffer-overflow.patch b/gd-2.2.5-heap-based-buffer-overflow.patch
new file mode 100644
index 0000000..ae795d0
--- /dev/null
+++ b/gd-2.2.5-heap-based-buffer-overflow.patch
@@ -0,0 +1,28 @@
+From 98b2e94e62d873acbcc6d968f1f97af9749fe021 Mon Sep 17 00:00:00 2001
+From: Ondrej Dubaj <odubaj@redhat.com>
+Date: Tue, 4 Jun 2019 10:54:45 +0200
+Subject: [PATCH] heap based buffer overflow in
+ gd_color_match.c:gdImageColorMatch() in libgd as used in imagecolormatch()
+
+---
+ src/gd_color_match.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/gd_color_match.c b/src/gd_color_match.c
+index f0842b6..a94a841 100755
+--- a/src/gd_color_match.c
++++ b/src/gd_color_match.c
+@@ -31,8 +31,8 @@ BGD_DECLARE(int) gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
+ return -4; /* At least 1 color must be allocated */
+ }
+
+- buf = (unsigned long *)gdMalloc(sizeof(unsigned long) * 5 * im2->colorsTotal);
+- memset (buf, 0, sizeof(unsigned long) * 5 * im2->colorsTotal );
++ buf = (unsigned long *)gdMalloc(sizeof(unsigned long) * 5 * gdMaxColors);
++ memset (buf, 0, sizeof(unsigned long) * 5 * gdMaxColors );
+
+ for (x=0; x < im1->sx; x++) {
+ for( y=0; y<im1->sy; y++ ) {
+--
+2.17.1
+
diff --git a/gd-2.2.5-potential-double-free.patch b/gd-2.2.5-potential-double-free.patch
new file mode 100644
index 0000000..788a068
--- /dev/null
+++ b/gd-2.2.5-potential-double-free.patch
@@ -0,0 +1,283 @@
+From 4d9d8368d08c3a2be3ea4193b9314fffeddace52 Mon Sep 17 00:00:00 2001
+From: Ondrej Dubaj <odubaj@redhat.com>
+Date: Tue, 4 Jun 2019 13:38:41 +0200
+Subject: [PATCH] Potential double-free in gdImage*Ptr()
+
+Whenever `gdImage*Ptr()` calls `gdImage*Ctx()` and the latter fails, we
+must not call `gdDPExtractData()`; otherwise a double-free would
+happen. Since `gdImage*Ctx()` are void functions, and we can't change
+that for BC reasons, we're introducing static helpers which are used
+internally.
+
+We're adding a regression test for `gdImageJpegPtr()`, but not for
+`gdImageGifPtr()` and `gdImageWbmpPtr()` since we don't know how to
+trigger failure of the respective `gdImage*Ctx()` calls.
+
+This potential security issue has been reported by Solmaz Salimi (aka.
+Rooney).
+---
+ src/gd_gif_out.c | 19 +++++++++++++++----
+ src/gd_jpeg.c | 20 ++++++++++++++++----
+ src/gd_wbmp.c | 21 ++++++++++++++++++---
+ tests/jpeg/CMakeLists.txt | 1 +
+ tests/jpeg/Makemodule.am | 3 ++-
+ tests/jpeg/jpeg_ptr_double_free.c | 31 +++++++++++++++++++++++++++++++
+ 6 files changed, 83 insertions(+), 12 deletions(-)
+ create mode 100644 tests/jpeg/jpeg_ptr_double_free.c
+
+diff --git a/src/gd_gif_out.c b/src/gd_gif_out.c
+index 6fe707d..4a05c09 100755
+--- a/src/gd_gif_out.c
++++ b/src/gd_gif_out.c
+@@ -99,7 +99,7 @@ static void char_init(GifCtx *ctx);
+ static void char_out(int c, GifCtx *ctx);
+ static void flush_char(GifCtx *ctx);
+
+-
++static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out);
+
+
+ /*
+@@ -131,8 +131,11 @@ BGD_DECLARE(void *) gdImageGifPtr(gdImagePtr im, int *size)
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ if (out == NULL) return NULL;
+- gdImageGifCtx(im, out);
+- rv = gdDPExtractData(out, size);
++ if (!_gdImageGifCtx(im, out)) {
++ rv = gdDPExtractData(out, size);
++ } else {
++ rv = NULL;
++ }
+ out->gd_free(out);
+ return rv;
+ }
+@@ -220,6 +223,12 @@ BGD_DECLARE(void) gdImageGif(gdImagePtr im, FILE *outFile)
+
+ */
+ BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
++{
++ _gdImageGifCtx(im, out);
++}
++
++/* returns 0 on success, 1 on failure */
++static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
+ {
+ gdImagePtr pim = 0, tim = im;
+ int interlace, BitsPerPixel;
+@@ -231,7 +240,7 @@ BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
+ based temporary image. */
+ pim = gdImageCreatePaletteFromTrueColor(im, 1, 256);
+ if(!pim) {
+- return;
++ return 1;
+ }
+ tim = pim;
+ }
+@@ -247,6 +256,8 @@ BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
+ /* Destroy palette based temporary image. */
+ gdImageDestroy( pim);
+ }
++
++ return 0;
+ }
+
+
+diff --git a/src/gd_jpeg.c b/src/gd_jpeg.c
+index 271ef46..bd8fc27 100755
+--- a/src/gd_jpeg.c
++++ b/src/gd_jpeg.c
+@@ -123,6 +123,8 @@ static void fatal_jpeg_error(j_common_ptr cinfo)
+ exit(99);
+ }
+
++static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality);
++
+ /*
+ * Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
+ * QUALITY. If QUALITY is in the range 0-100, increasing values
+@@ -237,8 +239,11 @@ BGD_DECLARE(void *) gdImageJpegPtr(gdImagePtr im, int *size, int quality)
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ if (out == NULL) return NULL;
+- gdImageJpegCtx(im, out, quality);
+- rv = gdDPExtractData(out, size);
++ if (!_gdImageJpegCtx(im, out, quality)) {
++ rv = gdDPExtractData(out, size);
++ } else {
++ rv = NULL;
++ }
+ out->gd_free(out);
+ return rv;
+ }
+@@ -259,6 +264,12 @@ void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile);
+
+ */
+ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
++{
++ _gdImageJpegCtx(im, outfile, quality);
++}
++
++/* returns 0 on success, 1 on failure */
++static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
+ {
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+@@ -293,7 +304,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
+ if(row) {
+ gdFree(row);
+ }
+- return;
++ return 1;
+ }
+
+ cinfo.err->emit_message = jpeg_emit_message;
+@@ -334,7 +345,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
+ if(row == 0) {
+ gd_error("gd-jpeg: error: unable to allocate JPEG row structure: gdCalloc returns NULL\n");
+ jpeg_destroy_compress(&cinfo);
+- return;
++ return 1;
+ }
+
+ rowptr[0] = row;
+@@ -411,6 +422,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ gdFree(row);
++ return 0;
+ }
+
+
+diff --git a/src/gd_wbmp.c b/src/gd_wbmp.c
+index 0028273..341ff6e 100755
+--- a/src/gd_wbmp.c
++++ b/src/gd_wbmp.c
+@@ -88,6 +88,8 @@ int gd_getin(void *in)
+ return (gdGetC((gdIOCtx *)in));
+ }
+
++static int _gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out);
++
+ /*
+ Function: gdImageWBMPCtx
+
+@@ -100,6 +102,12 @@ int gd_getin(void *in)
+ out - the stream where to write
+ */
+ BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
++{
++ _gdImageWBMPCtx(image, fg, out);
++}
++
++/* returns 0 on success, 1 on failure */
++static int _gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
+ {
+ int x, y, pos;
+ Wbmp *wbmp;
+@@ -107,7 +115,7 @@ BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
+ /* create the WBMP */
+ if((wbmp = createwbmp(gdImageSX(image), gdImageSY(image), WBMP_WHITE)) == NULL) {
+ gd_error("Could not create WBMP\n");
+- return;
++ return 1;
+ }
+
+ /* fill up the WBMP structure */
+@@ -123,11 +131,15 @@ BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
+
+ /* write the WBMP to a gd file descriptor */
+ if(writewbmp(wbmp, &gd_putout, out)) {
++ freewbmp(wbmp);
+ gd_error("Could not save WBMP\n");
++ return 1;
+ }
+
+ /* des submitted this bugfix: gdFree the memory. */
+ freewbmp(wbmp);
++
++ return 0;
+ }
+
+ /*
+@@ -271,8 +283,11 @@ BGD_DECLARE(void *) gdImageWBMPPtr(gdImagePtr im, int *size, int fg)
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ if (out == NULL) return NULL;
+- gdImageWBMPCtx(im, fg, out);
+- rv = gdDPExtractData(out, size);
++ if (!_gdImageWBMPCtx(im, fg, out)) {
++ rv = gdDPExtractData(out, size);
++ } else {
++ rv = NULL;
++ }
+ out->gd_free(out);
+ return rv;
+ }
+diff --git a/tests/jpeg/CMakeLists.txt b/tests/jpeg/CMakeLists.txt
+index 19964b0..a8d8162 100755
+--- a/tests/jpeg/CMakeLists.txt
++++ b/tests/jpeg/CMakeLists.txt
+@@ -2,6 +2,7 @@ IF(JPEG_FOUND)
+ LIST(APPEND TESTS_FILES
+ jpeg_empty_file
+ jpeg_im2im
++ jpeg_ptr_double_free
+ jpeg_null
+ )
+
+diff --git a/tests/jpeg/Makemodule.am b/tests/jpeg/Makemodule.am
+index 7e5d317..b89e169 100755
+--- a/tests/jpeg/Makemodule.am
++++ b/tests/jpeg/Makemodule.am
+@@ -2,7 +2,8 @@ if HAVE_LIBJPEG
+ libgd_test_programs += \
+ jpeg/jpeg_empty_file \
+ jpeg/jpeg_im2im \
+- jpeg/jpeg_null
++ jpeg/jpeg_null \
++ jpeg/jpeg_ptr_double_free
+
+ if HAVE_LIBPNG
+ libgd_test_programs += \
+diff --git a/tests/jpeg/jpeg_ptr_double_free.c b/tests/jpeg/jpeg_ptr_double_free.c
+new file mode 100644
+index 0000000..c80aeb6
+--- /dev/null
++++ b/tests/jpeg/jpeg_ptr_double_free.c
+@@ -0,0 +1,31 @@
++/**
++ * Test that failure to convert to JPEG returns NULL
++ *
++ * We are creating an image, set its width to zero, and pass this image to
++ * `gdImageJpegPtr()` which is supposed to fail, and as such should return NULL.
++ *
++ * See also <https://github.com/libgd/libgd/issues/381>
++ */
++
++
++#include "gd.h"
++#include "gdtest.h"
++
++
++int main()
++{
++ gdImagePtr src, dst;
++ int size;
++
++ src = gdImageCreateTrueColor(1, 10);
++ gdTestAssert(src != NULL);
++
++ src->sx = 0; /* this hack forces gdImageJpegPtr() to fail */
++
++ dst = gdImageJpegPtr(src, &size, 0);
++ gdTestAssert(dst == NULL);
++
++ gdImageDestroy(src);
++
++ return gdNumFailures();
++}
+\ No newline at end of file
+--
+2.17.1
+
diff --git a/gd.spec b/gd.spec
index 66bf99d..3548f60 100644
--- a/gd.spec
+++ b/gd.spec
@@ -32,7 +32,7 @@ Name: gd
Name: gd-last
%endif
Version: 2.2.5
-Release: 8%{?prever}%{?short}%{?dist}
+Release: 10%{?prever}%{?short}%{?dist}
License: MIT
URL: http://libgd.github.io/
%if 0%{?commit:1}
@@ -48,6 +48,10 @@ Patch1: gd-2.1.0-multilib.patch
Patch2: gd-2.2.5-upstream.patch
# CVE-2018-1000222 - https://github.com/libgd/libgd/commit/ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5
Patch3: gd-2.2.5-gdImageBmpPtr-double-free.patch
+# CVE-2019-6977
+Patch4: gd-2.2.5-heap-based-buffer-overflow.patch
+# CVE-2019-6978
+Patch5: gd-2.2.5-potential-double-free.patch
BuildRequires: freetype-devel
BuildRequires: fontconfig-devel
@@ -143,6 +147,8 @@ files for gd, a graphics library for creating PNG and JPEG graphics.
%patch1 -p1 -b .mlib
%patch2 -p1 -b .upstream
%patch3 -p1 -b .gdImageBmpPtr-free
+%patch4 -p1
+%patch5 -p1
: $(perl config/getver.pl)
@@ -237,6 +243,12 @@ grep %{version} $RPM_BUILD_ROOT%{_libdir}/pkgconfig/gdlib.pc
%changelog
+* Fri Nov 01 2019 odubaj@redhat.com - 2.2.5-10
+- Fixed heap based buffer overflow in gd_color_match.c:gdImageColorMatch() in libgd as used in imagecolormatch()
+- Resolves: RHBZ#1678104 (CVE-2019-6977)
+- Fixed potential double-free in gdImage*Ptr()
+- Resolves: RHBZ#1671391 (CVE-2019-6978)
+
* Mon Mar 18 2019 Remi Collet <remi@fedoraproject.org> - 2.2.5-8
- rebuild using libwebp7 on EL-7