CVE-2016-10168: Integer Overflow or Wraparound (CWE-190)
value: Integer overflow in gd_io.c in the GD Graphics Library (aka libgd) before 2.2.4 allows remote attackers to have unspecified impact via vectors involving the number of horizontal and vertical chunks in an image.
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 7.8
Published: 2017-03-15T15:59Z
Repository: https://github.com/libgd/libgd
Language: C
Files changed: src/gd_gd2.c, tests/gd2/.gitignore, tests/gd2/CMakeLists.txt, tests/gd2/Makemodule.am, tests/gd2/bug00354.c
Commit date: 2016-12-17 17:38:02 +0100
Commit message: Fix #354: Signed Integer Overflow gd_io.c

GD2 stores the number of horizontal and vertical chunks as words (i.e. 2
byte unsigned). These values are multiplied and assigned to an int when
reading the image, what can cause integer overflows. We have to avoid
that, and also make sure that either chunk count is actually greater
than zero. If illegal chunk counts are detected, we bail out from
reading the image.

Diff: diff --git a/src/gd_gd2.c b/src/gd_gd2.c
index d07828c7..c2904caf 100644
--- a/src/gd_gd2.c
+++ b/src/gd_gd2.c
@@ -207,10 +207,14 @@ _gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
 		goto fail1;
 	};
 	GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
 
 	if (gd2_compressed (*fmt)) {
+		if (*ncx <= 0 || *ncy <= 0 || *ncx > INT_MAX / *ncy) {
+			GD2_DBG(printf ("Illegal chunk counts: %d * %d\n", *ncx, *ncy));
+			goto fail1;
+		}
 		nc = (*ncx) * (*ncy);
 
 		GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
 		if (overflow2(sizeof(t_chunk_info), nc)) {
 			goto fail1;
diff --git a/tests/gd2/.gitignore b/tests/gd2/.gitignore
index 39d8bf4e..8d3ee850 100644
--- a/tests/gd2/.gitignore
+++ b/tests/gd2/.gitignore
@@ -1,7 +1,8 @@
 /bug_289
 /bug00309
+/bug00354
 /gd2_empty_file
 /gd2_im2im
 /gd2_null
 /gd2_read
 /gd2_read_corrupt
diff --git a/tests/gd2/CMakeLists.txt b/tests/gd2/CMakeLists.txt
index 5a61d113..36de5737 100644
--- a/tests/gd2/CMakeLists.txt
+++ b/tests/gd2/CMakeLists.txt
@@ -1,8 +1,9 @@
 LIST(APPEND TESTS_FILES
 	bug_289
 	bug00309
+	bug00354
 	gd2_empty_file
 	gd2_im2im
 	gd2_null
 	php_bug_72339
 	gd2_read
diff --git a/tests/gd2/Makemodule.am b/tests/gd2/Makemodule.am
index c1fbf440..0322bd02 100644
--- a/tests/gd2/Makemodule.am
+++ b/tests/gd2/Makemodule.am
@@ -1,8 +1,9 @@
 libgd_test_programs += \
 	gd2/bug_289 \
 	gd2/bug00309 \
+	gd2/bug00354 \
 	gd2/gd2_empty_file \
 	gd2/php_bug_72339 \
 	gd2/gd2_read_corrupt \
 	gd2/too_few_image_data
 
@@ -17,10 +18,12 @@ libgd_test_programs += \
 endif
 endif
 
 EXTRA_DIST += \
 	gd2/CMakeLists.txt \
+	gd2/bug00354a.gd2 \
+	gd2/bug00354b.gd2 \
 	gd2/conv_gd2_exp.gd2 \
 	gd2/conv_test.gd2 \
 	gd2/conv_test_exp.png \
 	gd2/empty.gd2 \
 	gd2/invalid_header.gd2 \
diff --git a/tests/gd2/bug00354.c b/tests/gd2/bug00354.c
new file mode 100644
index 00000000..cc64254d
--- /dev/null
+++ b/tests/gd2/bug00354.c
@@ -0,0 +1,32 @@
+/**
+ * We're testing GD2 image files which report illegal chunk counts. These should
+ * not cause integer overflows or other issues, but instead simply fail to be
+ * loaded.
+ *
+ * See also <https://github.com/libgd/libgd/issues/354>.
+ */
+
+
+#include "gd.h"
+#include "gdtest.h"
+
+
+int main()
+{
+    gdImagePtr im;
+    FILE *fp;
+
+    fp = gdTestFileOpen2("gd2", "bug00354a.gd2");
+    gdTestAssert(fp != NULL);
+    im = gdImageCreateFromGd2(fp);
+    gdTestAssert(im == NULL);
+    fclose(fp);
+
+    fp = gdTestFileOpen2("gd2", "bug00354b.gd2");
+    gdTestAssert(fp != NULL);
+    im = gdImageCreateFromGd2(fp);
+    gdTestAssert(im == NULL);
+    fclose(fp);
+
+    return gdNumFailures();
+}
diff --git a/tests/gd2/bug00354a.gd2 b/tests/gd2/bug00354a.gd2
new file mode 100644
index 00000000..5060bfde
Binary files /dev/null and b/tests/gd2/bug00354a.gd2 differ
diff --git a/tests/gd2/bug00354b.gd2 b/tests/gd2/bug00354b.gd2
new file mode 100644
index 00000000..8600126b
Binary files /dev/null and b/tests/gd2/bug00354b.gd2 differ

Fixed code: 		if (*ncx <= 0 || *ncy <= 0 || *ncx > INT_MAX / *ncy) {
			GD2_DBG(printf ("Illegal chunk counts: %d * %d\n", *ncx, *ncy));
			goto fail1;
		}
/bug00354
	bug00354
	gd2/bug00354 \
	gd2/bug00354a.gd2 \
	gd2/bug00354b.gd2 \
/**
 * We're testing GD2 image files which report illegal chunk counts. These should
 * not cause integer overflows or other issues, but instead simply fail to be
 * loaded.
 *
 * See also <https://github.com/libgd/libgd/issues/354>.
 */


#include "gd.h"
#include "gdtest.h"


int main()
{
    gdImagePtr im;
    FILE *fp;

    fp = gdTestFileOpen2("gd2", "bug00354a.gd2");
    gdTestAssert(fp != NULL);
    im = gdImageCreateFromGd2(fp);
    gdTestAssert(im == NULL);
    fclose(fp);

    fp = gdTestFileOpen2("gd2", "bug00354b.gd2");
    gdTestAssert(fp != NULL);
    im = gdImageCreateFromGd2(fp);
    gdTestAssert(im == NULL);
    fclose(fp);

    return gdNumFailures();
}