php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch fix-72558 for GD related Bug #72558

Patch version 2016-07-07 14:00 UTC

Return to Bug #72558 | Download this patch
Patch Revisions:

Developer: cmb

From fc9f1061267b115097eb39abc57cc149df01e46d Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmb@php.net>
Date: Thu, 7 Jul 2016 15:58:44 +0200
Subject: [PATCH] Bug #72558: Integer overflow error within
 _gdContributionsAlloc()

According to the respective patch for external libgd, we fix PHP's bundled
libgd. Namely, we fix the broken overflow check in libgd/gd.c, and we add
additional handling of allocation errors.
---
 ext/gd/libgd/gd.c               |  4 ++--
 ext/gd/libgd/gd_interpolation.c | 47 +++++++++++++++++++++++++++++++++--------
 ext/gd/tests/bug72558.phpt      | 16 ++++++++++++++
 3 files changed, 56 insertions(+), 11 deletions(-)
 create mode 100644 ext/gd/tests/bug72558.phpt

diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c
index a5799c5..84e5e5f 100644
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@ -186,11 +186,11 @@ gdImagePtr gdImageCreateTrueColor (int sx, int sy)
 		return NULL;
 	}
 
-	if (overflow2(sizeof(unsigned char *), sy)) {
+	if (overflow2(sizeof(int *), sy)) {
 		return NULL;
 	}
 
-	if (overflow2(sizeof(int), sx)) {
+	if (overflow2(sizeof(int *), sx)) {
 		return NULL;
 	}
 
diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c
index 8331996..7a0306e 100644
--- a/ext/gd/libgd/gd_interpolation.c
+++ b/ext/gd/libgd/gd_interpolation.c
@@ -888,9 +888,20 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
     res->WindowSize = windows_size;
     res->LineLength = line_length;
     res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
-
+	if (res->ContribRow == NULL) {
+		gdFree(res);
+		return NULL;
+	}
     for (u = 0 ; u < line_length ; u++) {
         res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
+		if (res->ContribRow[u].Weights == NULL) {
+			u--;
+			while (u >= 0) {
+				gdFree(res->ContribRow[u].Weights);
+				u--;
+			}
+			return NULL;
+		}
     }
     return res;
 }
@@ -923,7 +934,9 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi
 
     windows_size = 2 * (int)ceil(width_d) + 1;
     res = _gdContributionsAlloc(line_size, windows_size);
-
+	if (res == NULL) {
+		return NULL;
+	}
     for (u = 0; u < line_size; u++) {
         const double dCenter = (double)u / scale_d;
         /* get the significant edge points affecting the pixel */
@@ -986,7 +999,7 @@ static inline void _gdScaleRow(gdImagePtr pSrc,  unsigned int src_width, gdImage
     }
 }
 
-static inline void _gdScaleHoriz(gdImagePtr pSrc, unsigned int src_width, unsigned int src_height, gdImagePtr pDst,  unsigned int dst_width, unsigned int dst_height)
+static inline int _gdScaleHoriz(gdImagePtr pSrc, unsigned int src_width, unsigned int src_height, gdImagePtr pDst,  unsigned int dst_width, unsigned int dst_height)
 {
 	unsigned int u;
 	LineContribType * contrib;
@@ -1001,13 +1014,14 @@ static inline void _gdScaleHoriz(gdImagePtr pSrc, unsigned int src_width, unsign
 
 	contrib = _gdContributionsCalc(dst_width, src_width, (double)dst_width / (double)src_width, pSrc->interpolation);
 	if (contrib == NULL) {
-		return;
+		return 0;
 	}
 	/* Scale each row */
 	for (u = 0; u < dst_height - 1; u++) {
 		_gdScaleRow(pSrc, src_width, pDst, dst_width, u, contrib);
 	}
 	_gdContributionsFree (contrib);
+	return 1;
 }
 
 static inline void _gdScaleCol (gdImagePtr pSrc,  unsigned int src_width, gdImagePtr pRes, unsigned int dst_width, unsigned int dst_height, unsigned int uCol, LineContribType *contrib)
@@ -1033,7 +1047,7 @@ static inline void _gdScaleCol (gdImagePtr pSrc,  unsigned int src_width, gdImag
 	}
 }
 
-static inline void _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_width, const unsigned int src_height, const gdImagePtr pDst, const unsigned int dst_width, const unsigned int dst_height)
+static inline int _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_width, const unsigned int src_height, const gdImagePtr pDst, const unsigned int dst_width, const unsigned int dst_height)
 {
 	unsigned int u;
 	LineContribType * contrib;
@@ -1048,19 +1062,21 @@ static inline void _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_w
 
 	contrib = _gdContributionsCalc(dst_height, src_height, (double)(dst_height) / (double)(src_height), pSrc->interpolation);
 	if (contrib == NULL) {
-		return;
+		return 0;
 	}
 	/* scale each column */
 	for (u = 0; u < dst_width - 1; u++) {
 		_gdScaleCol(pSrc, src_width, pDst, dst_width, dst_height, u, contrib);
 	}
 	_gdContributionsFree(contrib);
+	return 1;
 }
 
 gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_width, const unsigned int src_height, const unsigned int new_width, const unsigned int new_height)
 {
 	gdImagePtr tmp_im;
 	gdImagePtr dst;
+	int scale_pass_res;
 
 	if (new_width == 0 || new_height == 0) {
 		return NULL;
@@ -1076,7 +1092,11 @@ gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_widt
 		return NULL;
 	}
 	gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
-	_gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
+	scale_pass_res = _gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
+	if (scale_pass_res != 1) {
+		gdImageDestroy(tmp_im);
+		return NULL;
+	}
 
 	dst = gdImageCreateTrueColor(new_width, new_height);
 	if (dst == NULL) {
@@ -1084,8 +1104,17 @@ gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_widt
 		return NULL;
 	}
 	gdImageSetInterpolationMethod(dst, src->interpolation_id);
-	_gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
-	gdImageDestroy(tmp_im);
+	scale_pass_res = _gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
+	if (scale_pass_res != 1) {
+		gdImageDestroy(dst);
+		if (src != tmp_im && tmp_im != NULL) {
+			gdImageDestroy(tmp_im);
+		}
+		return NULL;
+	}
+	if (src != tmp_im && tmp_im != NULL) {
+		gdImageDestroy(tmp_im);
+	}
 
 	return dst;
 }
diff --git a/ext/gd/tests/bug72558.phpt b/ext/gd/tests/bug72558.phpt
new file mode 100644
index 0000000..e534ba3
--- /dev/null
+++ b/ext/gd/tests/bug72558.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #72558: Integer overflow error within _gdContributionsAlloc()
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip gd extension not available');
+?>
+--FILE--
+<?php
+$im = imagecreate(1, 1);
+imagesetinterpolation($im, IMG_BELL);
+imagescale($im, 0x15555556, 1);
+imagedestroy($im);
+?>
+--EXPECTF--
+Warning: imagescale(): gd warning: product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully
+ in %s on line %d
-- 
2.8.1.windows.1

 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Aug 20 21:01:35 2017 UTC