CVE-2016-6214: Out-of-bounds Read (CWE-125)
value: gd_tga.c in the GD Graphics Library (aka libgd) before 2.2.3 allows remote attackers to cause a denial of service (out-of-bounds read) via a crafted TGA file.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 6.5
Published: 2016-08-12T15:59Z
Repository: https://github.com/libgd/libgd
Language: C
Files changed: src/gd_tga.c, tests/tga/.gitignore, tests/tga/CMakeLists.txt, tests/tga/Makemodule.am, tests/tga/bug00247a.c
Commit date: 2016-07-12 20:46:33 +0200
Commit message: Unsupported TGA bpp/alphabit combinations should error gracefully

Currently, only 24bpp without alphabits and 32bpp with 8 alphabits are
really supported. All other combinations will be rejected with a warning.

Diff: diff --git a/src/gd_tga.c b/src/gd_tga.c
index 20fe2d27..b4f8fa62 100644
--- a/src/gd_tga.c
+++ b/src/gd_tga.c
@@ -97,11 +97,11 @@ BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaCtx(gdIOCtx* ctx)
 		register int *tpix = image->tpixels[y];
 		for ( x = 0; x < tga->width; x++, tpix++) {
 			if (tga->bits == TGA_BPP_24) {
 				*tpix = gdTrueColor(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret]);
 				bitmap_caret += 3;
-			} else if (tga->bits == TGA_BPP_32 || tga->alphabits) {
+			} else if (tga->bits == TGA_BPP_32 && tga->alphabits) {
 				register int a = tga->bitmap[bitmap_caret + 3];
 
 				*tpix = gdTrueColorAlpha(tga->bitmap[bitmap_caret + 2], tga->bitmap[bitmap_caret + 1], tga->bitmap[bitmap_caret], gdAlphaMax - (a >> 1));
 				bitmap_caret += 4;
 			}
@@ -157,20 +157,16 @@ int read_header_tga(gdIOCtx *ctx, oTga *tga)
 	printf("flip h/v: %i / %i\n", tga->fliph, tga->flipv);
 	printf("alpha: %i\n", tga->alphabits);
 	printf("wxh: %i %i\n", tga->width, tga->height);
 #endif
 
-	switch(tga->bits) {
-	case 8:
-	case 16:
-	case 24:
-	case 32:
-		break;
-	default:
-		gd_error("bps %i not supported", tga->bits);
+	if (!((tga->bits == TGA_BPP_24 && tga->alphabits == 0)
+		|| (tga->bits == TGA_BPP_32 && tga->alphabits == 8)))
+	{
+		gd_error_ex(GD_WARNING, "gd-tga: %u bits per pixel with %u alpha bits not supported\n",
+			tga->bits, tga->alphabits);
 		return -1;
-		break;
 	}
 
 	tga->ident = NULL;
 
 	if (tga->identsize > 0) {
diff --git a/tests/tga/.gitignore b/tests/tga/.gitignore
index f811a246..14bf59fe 100644
--- a/tests/tga/.gitignore
+++ b/tests/tga/.gitignore
@@ -1,3 +1,4 @@
 /bug00084
 /bug00247
+/bug00247a
 /tga_null
diff --git a/tests/tga/CMakeLists.txt b/tests/tga/CMakeLists.txt
index a2553d1d..52a4223c 100644
--- a/tests/tga/CMakeLists.txt
+++ b/tests/tga/CMakeLists.txt
@@ -1,7 +1,8 @@
 LIST(APPEND TESTS_FILES
 	tga_null
 	bug00084
 	bug00247
+	bug00247a
 )
 
 ADD_GD_TESTS()
diff --git a/tests/tga/Makemodule.am b/tests/tga/Makemodule.am
index 93063a33..0052a275 100644
--- a/tests/tga/Makemodule.am
+++ b/tests/tga/Makemodule.am
@@ -1,9 +1,11 @@
 libgd_test_programs += \
 	tga/bug00084 \
 	tga/bug00247 \
+	tag/bug00247a \
 	tga/tga_null
 
 EXTRA_DIST += \
 	tga/CMakeLists.txt \
 	tga/bug00084.tga \
-	tga/bug00247.tga
+	tga/bug00247.tga \
+	tga/bug00247a.tga
diff --git a/tests/tga/bug00247a.c b/tests/tga/bug00247a.c
new file mode 100644
index 00000000..676efa3a
--- /dev/null
+++ b/tests/tga/bug00247a.c
@@ -0,0 +1,19 @@
+/*
+We test that a 8bpp TGA file will be gracefully rejected by
+gdImageCreateFromTga().
+*/
+
+#include <stdio.h>
+
+#include "gd.h"
+#include "gdtest.h"
+
+int main(int argc, char **argv)
+{
+    gdImagePtr im;
+    FILE *fp = gdTestFileOpen("tga/bug00247a.tga");
+    im = gdImageCreateFromTga(fp);
+    gdTestAssert(im == NULL);
+    fclose(fp);
+    return gdNumFailures();
+}
diff --git a/tests/tga/bug00247a.tga b/tests/tga/bug00247a.tga
new file mode 100644
index 00000000..65e55abe
Binary files /dev/null and b/tests/tga/bug00247a.tga differ

Vulnerable code: 			} else if (tga->bits == TGA_BPP_32 || tga->alphabits) {
	switch(tga->bits) {
	case 8:
	case 16:
	case 24:
	case 32:
		break;
	default:
		gd_error("bps %i not supported", tga->bits);
		break;
	tga/bug00247.tga
Fixed code: 			} else if (tga->bits == TGA_BPP_32 && tga->alphabits) {
	if (!((tga->bits == TGA_BPP_24 && tga->alphabits == 0)
		|| (tga->bits == TGA_BPP_32 && tga->alphabits == 8)))
	{
		gd_error_ex(GD_WARNING, "gd-tga: %u bits per pixel with %u alpha bits not supported\n",
			tga->bits, tga->alphabits);
/bug00247a
	bug00247a
	tag/bug00247a \
	tga/bug00247.tga \
	tga/bug00247a.tga
/*
We test that a 8bpp TGA file will be gracefully rejected by
gdImageCreateFromTga().
*/

#include <stdio.h>

#include "gd.h"
#include "gdtest.h"

int main(int argc, char **argv)
{
    gdImagePtr im;
    FILE *fp = gdTestFileOpen("tga/bug00247a.tga");
    im = gdImageCreateFromTga(fp);
    gdTestAssert(im == NULL);
    fclose(fp);
    return gdNumFailures();
}