From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Tue, 2 Aug 2016 12:10:33 +0200
Subject: Fix invalid read in gdImageCreateFromTiffPtr()

tiff_invalid_read.tiff is corrupt, and causes an invalid read in
gdImageCreateFromTiffPtr(), but not in gdImageCreateFromTiff(). The culprit
is dynamicGetbuf(), which doesn't check for out-of-bound reads. In this case,
dynamicGetbuf() is called with a negative dp->pos, but also positive buffer
overflows have to be handled, in which case 0 has to be returned (cf. commit
75e29a9).

Fixing dynamicGetbuf() exhibits that the corrupt TIFF would still create
the image, because the return value of TIFFReadRGBAImage() is not checked.
We do that, and let createFromTiffRgba() fail if TIFFReadRGBAImage() fails.

This issue had been reported by Ibrahim El-Sayed to security@libgd.org.
---
 src/gd_io_dp.c                      |  15 ++++++---
 src/gd_tiff.c                       |  27 +++++++++-------
 tests/tiff/CMakeLists.txt           |   1 +
 tests/tiff/tiff_invalid_read.c      |  61 ++++++++++++++++++++++++++++++++++++
 tests/tiff/tiff_invalid_read_1.tiff | Bin 0 -> 3304 bytes
 tests/tiff/tiff_invalid_read_2.tiff | Bin 0 -> 429 bytes
 tests/tiff/tiff_invalid_read_3.tiff | Bin 0 -> 428 bytes
 7 files changed, 87 insertions(+), 17 deletions(-)
 create mode 100644 tests/tiff/tiff_invalid_read.c
 create mode 100644 tests/tiff/tiff_invalid_read_1.tiff
 create mode 100644 tests/tiff/tiff_invalid_read_2.tiff
 create mode 100644 tests/tiff/tiff_invalid_read_3.tiff

Index: libgd2-2.1.1/src/gd_io_dp.c
===================================================================
--- libgd2-2.1.1.orig/src/gd_io_dp.c	2016-10-18 14:16:28.629017465 +0200
+++ libgd2-2.1.1/src/gd_io_dp.c	2016-10-18 14:16:28.629017465 +0200
@@ -253,6 +253,7 @@
 	appendDynamic(dctx->dp, &b, 1);
 }
 
+/* returns the number of bytes actually read; 0 on EOF and error */
 static int dynamicGetbuf(gdIOCtxPtr ctx, void *buf, int len)
 {
 	int rlen, remain;
@@ -262,21 +263,25 @@
 	dctx = (dpIOCtxPtr) ctx;
 	dp = dctx->dp;
 
+	if (dp->pos < 0 || dp->pos >= dp->realSize) {
+		return 0;
+	}
+
 	remain = dp->logicalSize - dp->pos;
 	if(remain >= len) {
 		rlen = len;
 	} else {
 		if(remain <= 0) {
-			/* 2.0.34: EOF is incorrect. We use 0 for
-			 * errors and EOF, just like fileGetbuf,
-			 * which is a simple fread() wrapper.
-			 * TBB. Original bug report: Daniel Cowgill. */
-			return 0; /* NOT EOF */
+			return 0;
 		}
 
 		rlen = remain;
 	}
 
+	if (dp->pos + rlen > dp->realSize) {
+		rlen = dp->realSize - dp->pos;
+	}
+
 	memcpy(buf, (void *) ((char *)dp->data + dp->pos), rlen);
 	dp->pos += rlen;
 
Index: libgd2-2.1.1/src/gd_tiff.c
===================================================================
--- libgd2-2.1.1.orig/src/gd_tiff.c	2016-10-18 14:16:28.629017465 +0200
+++ libgd2-2.1.1/src/gd_tiff.c	2016-10-18 14:16:28.629017465 +0200
@@ -727,6 +727,7 @@
 	int height = im->sy;
 	uint32 *buffer;
 	uint32 rgba;
+	int success;
 
 	/* switch off colour merging on target gd image just while we write out
 	 * content - we want to preserve the alpha data until the user chooses
@@ -739,18 +740,20 @@
 		return GD_FAILURE;
 	}
 
-	TIFFReadRGBAImage(tif, width, height, buffer, 0);
+	success = TIFFReadRGBAImage(tif, width, height, buffer, 1);
 
-	for(y = 0; y < height; y++) {
-		for(x = 0; x < width; x++) {
-			/* if it doesn't already exist, allocate a new colour,
-			 * else use existing one */
-			rgba = buffer[(y * width + x)];
-			a = (0xff - TIFFGetA(rgba)) / 2;
-			color = gdTrueColorAlpha(TIFFGetR(rgba), TIFFGetG(rgba), TIFFGetB(rgba), a);
-
-			/* set pixel colour to this colour */
-			gdImageSetPixel(im, x, height - y - 1, color);
+	if (success) {
+		for(y = 0; y < height; y++) {
+			for(x = 0; x < width; x++) {
+				/* if it doesn't already exist, allocate a new colour,
+				 * else use existing one */
+				rgba = buffer[(y * width + x)];
+				a = (0xff - TIFFGetA(rgba)) / 2;
+				color = gdTrueColorAlpha(TIFFGetR(rgba), TIFFGetG(rgba), TIFFGetB(rgba), a);
+	
+				/* set pixel colour to this colour */
+				gdImageSetPixel(im, x, height - y - 1, color);
+			}
 		}
 	}
 
@@ -758,7 +761,7 @@
 
 	/* now reset colour merge for alpha blending routines */
 	gdImageAlphaBlending(im, alphaBlendingFlag);
-	return GD_SUCCESS;
+	return success;
 }
 
 /* gdImageCreateFromTiffCtx
