CVE-2016-3074: Incorrect Conversion between Numeric Types (CWE-681)
value: Integer signedness error in GD Graphics Library 2.1.1 (aka libgd or libgd2) allows remote attackers to cause a denial of service (crash) or potentially execute arbitrary code via crafted compressed gd2 data, which triggers a heap-based buffer overflow.
CWE description: When converting from one data type to another, such as long to integer, data can be omitted or translated in a way that produces unexpected values. If the resulting values are used in a sensitive context, then dangerous behaviors may occur.
CVSS v3 base score: 9.8
Published: 2016-04-26T14:59Z
Repository: https://github.com/libgd/libgd
Language: C
Files changed: .gitignore, src/gd_gd2.c, tests/Makefile.am, tests/gd2/gd2_read_corrupt.c
Commit date: 2016-04-16 03:51:22 -0400
Commit message: gd2: handle corrupt images better (CVE-2016-3074)

Make sure we do some range checking on corrupted chunks.

Thanks to Hans Jerry Illikainen <hji@dyntopia.com> for indepth report
and reproducer information.  Made for easy test case writing :).

Diff: diff --git a/.gitignore b/.gitignore
index a68f3b9c..35acd71d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -148,10 +148,11 @@ Makefile.in
 /tests/gdimagestringft/gdimagestringft_bbox
 /tests/gdtiled/bug00032
 /tests/gd2/gd2_im2im
 /tests/gd2/gd2_null
 /tests/gd2/gd2_read
+/tests/gd2/gd2_read_corrupt
 /tests/gdimagearc/bug00079
 /tests/gdimageline/gdimageline_aa
 /tests/gdimageline/bug00072
 /tests/gdimageline/bug00077
 /tests/gdimageline/bug00111
diff --git a/src/gd_gd2.c b/src/gd_gd2.c
index 6f284610..a50b33d6 100644
--- a/src/gd_gd2.c
+++ b/src/gd_gd2.c
@@ -163,10 +163,12 @@ _gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
 				goto fail2;
 			};
 			if (gdGetInt (&cidx[i].size, in) != 1) {
 				goto fail2;
 			};
+			if (cidx[i].offset < 0 || cidx[i].size < 0)
+				goto fail2;
 		};
 		*chunkIdx = cidx;
 	};
 
 	GD2_DBG (printf ("gd2 header complete\n"));
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ed2c35b4..b582266b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -127,11 +127,12 @@ check_PROGRAMS += \
 endif
 endif
 
 if HAVE_LIBZ
 check_PROGRAMS += \
-	gd2/gd2_null
+	gd2/gd2_null \
+	gd2/gd2_read_corrupt
 endif
 
 if HAVE_LIBPNG
 if HAVE_LIBZ
 check_PROGRAMS += \
diff --git a/tests/gd2/gd2_read_corrupt.c b/tests/gd2/gd2_read_corrupt.c
new file mode 100644
index 00000000..11f6a67b
--- /dev/null
+++ b/tests/gd2/gd2_read_corrupt.c
@@ -0,0 +1,25 @@
+/* Just try to read the invalid gd2 image & not crash. */
+#include "gd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "gdtest.h"
+
+int main()
+{
+	gdImagePtr im;
+	FILE *fp;
+	char path[1024];
+
+	/* Read the corrupt image. */
+	sprintf(path, "%s/gd2/invalid_neg_size.gd2", GDTEST_TOP_DIR);
+	fp = fopen(path, "rb");
+	if (!fp) {
+		printf("failed, cannot open file\n");
+		return 1;
+	}
+	im = gdImageCreateFromGd2(fp);
+	fclose(fp);
+
+	/* Should have failed & rejected it. */
+	return im == NULL ? 0 : 1;
+}
diff --git a/tests/gd2/invalid_neg_size.gd2 b/tests/gd2/invalid_neg_size.gd2
new file mode 100644
index 00000000..3075f15a
Binary files /dev/null and b/tests/gd2/invalid_neg_size.gd2 differ

Vulnerable code: 	gd2/gd2_null
Fixed code: /tests/gd2/gd2_read_corrupt
			if (cidx[i].offset < 0 || cidx[i].size < 0)
				goto fail2;
	gd2/gd2_null \
	gd2/gd2_read_corrupt
/* Just try to read the invalid gd2 image & not crash. */
#include "gd.h"
#include <stdio.h>
#include <stdlib.h>
#include "gdtest.h"

int main()
{
	gdImagePtr im;
	FILE *fp;
	char path[1024];

	/* Read the corrupt image. */
	sprintf(path, "%s/gd2/invalid_neg_size.gd2", GDTEST_TOP_DIR);
	fp = fopen(path, "rb");
	if (!fp) {
		printf("failed, cannot open file\n");
		return 1;
	}
	im = gdImageCreateFromGd2(fp);
	fclose(fp);

	/* Should have failed & rejected it. */
	return im == NULL ? 0 : 1;
}