CVE-2016-6906: Out-of-bounds Read (CWE-125)
value: The read_image_tga function in gd_tga.c in the GD Graphics Library (aka libgd) before 2.2.4 allows remote attackers to cause a denial of service (out-of-bounds read) via a crafted TGA file, related to the decompression buffer.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 5.5
Published: 2017-03-15T14:59Z
Repository: https://github.com/libgd/libgd
Language: C
Files changed: src/gd_tga.c, tests/tga/Makemodule.am, tests/tga/heap_overflow.c
Commit date: 2016-12-13 15:51:51 +0100
Commit message: Fix OOB reads of the TGA decompression buffer

It is possible to craft TGA files which will overflow the decompression
buffer, but not the image's bitmap. Therefore we also have to check for
potential decompression buffer overflows.

This issue had been reported by Ibrahim El-Sayed to security@libgd.org;
a modified case exposing an off-by-one error of the first patch had been
provided by Konrad Beckmann.

This commit is an amendment to commit fb0e0cce, so we use CVE-2016-6906
as well.

Diff: diff --git a/src/gd_tga.c b/src/gd_tga.c
index 68e4b17d..f80f0b16 100644
--- a/src/gd_tga.c
+++ b/src/gd_tga.c
@@ -293,11 +293,17 @@ int read_image_tga( gdIOCtx *ctx, oTga *tga )
 		}
 
 		buffer_caret = 0;
 
 		while( bitmap_caret < image_block_size ) {
-			
+
+			if (buffer_caret + pixel_block_size > rle_size) {
+				gdFree( decompression_buffer );
+				gdFree( conversion_buffer );
+				return -1;
+			}
+
 			if ((decompression_buffer[buffer_caret] & TGA_RLE_FLAG) == TGA_RLE_FLAG) {
 				encoded_pixels = ( ( decompression_buffer[ buffer_caret ] & ~TGA_RLE_FLAG ) + 1 );
 				buffer_caret++;
 
 				if ((bitmap_caret + (encoded_pixels * pixel_block_size)) > image_block_size
diff --git a/tests/tga/Makemodule.am b/tests/tga/Makemodule.am
index 916d7073..ab08dbff 100644
--- a/tests/tga/Makemodule.am
+++ b/tests/tga/Makemodule.am
@@ -13,9 +13,10 @@ EXTRA_DIST += \
 	tga/bug00084.tga \
 	tga/bug00247.tga \
 	tga/bug00247a.tga \
 	tga/bug00248.tga \
 	tga/bug00248a.tga \
-	tga/heap_overflow.tga \
+	tga/heap_overflow_1.tga \
+	tga/heap_overflow_2.tga \
 	tga/tga_read_rgb.png \
 	tga/tga_read_rgb.tga \
 	tga/tga_read_rgb_rle.tga
diff --git a/tests/tga/heap_overflow.c b/tests/tga/heap_overflow.c
index 0e9a2d00..ddd4b63e 100644
--- a/tests/tga/heap_overflow.c
+++ b/tests/tga/heap_overflow.c
@@ -1,29 +1,37 @@
 /**
- * Test that the crafted TGA file doesn't trigger OOB reads.
+ * Test that crafted TGA files don't trigger OOB reads.
  */
 
 
 #include "gd.h"
 #include "gdtest.h"
 
 
+static void check_file(char *basename);
 static size_t read_test_file(char **buffer, char *basename);
 
 
 int main()
+{
+    check_file("heap_overflow_1.tga");
+    check_file("heap_overflow_2.tga");
+
+    return gdNumFailures();
+}
+
+
+static void check_file(char *basename)
 {
     gdImagePtr im;
     char *buffer;
     size_t size;
 
-    size = read_test_file(&buffer, "heap_overflow.tga");
+    size = read_test_file(&buffer, basename);
     im = gdImageCreateFromTgaPtr(size, (void *) buffer);
     gdTestAssert(im == NULL);
     free(buffer);
-
-    return gdNumFailures();
 }
 
 
 static size_t read_test_file(char **buffer, char *basename)
 {
diff --git a/tests/tga/heap_overflow_1.tga b/tests/tga/heap_overflow_1.tga
new file mode 100644
index 00000000..e9bc0ecb
Binary files /dev/null and b/tests/tga/heap_overflow_1.tga differ
diff --git a/tests/tga/heap_overflow_2.tga b/tests/tga/heap_overflow_2.tga
new file mode 100644
index 00000000..2b681f2d
Binary files /dev/null and b/tests/tga/heap_overflow_2.tga differ

Vulnerable code: 			
	tga/heap_overflow.tga \
 * Test that the crafted TGA file doesn't trigger OOB reads.
    size = read_test_file(&buffer, "heap_overflow.tga");

    return gdNumFailures();
Fixed code: 
			if (buffer_caret + pixel_block_size > rle_size) {
				gdFree( decompression_buffer );
				gdFree( conversion_buffer );
				return -1;
			}

	tga/heap_overflow_1.tga \
	tga/heap_overflow_2.tga \
 * Test that crafted TGA files don't trigger OOB reads.
static void check_file(char *basename);
{
    check_file("heap_overflow_1.tga");
    check_file("heap_overflow_2.tga");

    return gdNumFailures();
}


static void check_file(char *basename)
    size = read_test_file(&buffer, basename);