CVE-2016-7568: Integer Overflow or Wraparound (CWE-190)
value: Integer overflow in the gdImageWebpCtx function in gd_webp.c in the GD Graphics Library (aka libgd) through 2.2.3, as used in PHP through 7.0.11, allows remote attackers to cause a denial of service (heap-based buffer overflow) or possibly have unspecified other impact via crafted imagewebp and imagedestroy calls.
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: 9.8
Published: 2016-09-28T20:59Z
Repository: https://github.com/php/php-src
Language: Other
Files changed: NEWS, ext/gd/libgd/gd_webp.c
Commit date: 2016-09-16 11:41:42 +0200
Commit message: Merge branch 'PHP-5.6' into PHP-7.0

Diff: diff --cc NEWS
index 76cad3ea1c8,ef6cb570abc..42d30ab8ebb
--- a/NEWS
+++ b/NEWS
@@@ -20,20 -20,22 +20,22 @@@ PH
  - GD:
    . Fixed bug #67325 (imagetruecolortopalette: white is duplicated in palette).
      (cmb)
    . Fixed bug #50194 (imagettftext broken on transparent background w/o
      alphablending). (cmb)
+   . Fixed bug #73003 (Integer Overflow in gdImageWebpCtx of gd_webp.c). (trylab,
+     cmb)
  
  - Mbstring:
 -  . Fixed bug #72994 (mbc_to_code() out of bounds read). (Laruence, cmb)
 -  . Fixed bug #66964 (mb_convert_variables() cannot detect recursion). (Yasuo)
 +  . Fixed bug #66797 (mb_substr only takes 32-bit signed integer). (cmb)
 +  . Fixed bug #66964 (mb_convert_variables() cannot detect recursion) (Yasuo)
    . Fixed bug #72992 (mbstring.internal_encoding doesn't inherit default_charset).
      (Yasuo)
  
  - Opcache:
 -  . Fixed bug #72590 (Opcache restart with kill_all_lockers does not work).
 -    (Keyur) (julien backport)
 +  . Fixed bug #72982 (Memory leak in zend_accel_blacklist_update_regexp()
 +    function). (Laruence)
  
  - OpenSSL:
    . Fixed bug #73072 (Invalid path SNI_server_certs causes segfault).
      (Jakub Zelenka)
  
diff --cc ext/gd/libgd/gd_webp.c
index da0cc9d5b8c,985187edc26..0ce27e03b41
--- a/ext/gd/libgd/gd_webp.c
+++ b/ext/gd/libgd/gd_webp.c
@@@ -63,99 -88,25 +63,107 @@@ gdImagePtr gdImageCreateFromWebpCtx (gd
  		if (n>0 && n!=EOF) {
  			size += n;
  		}
  	} while (n>0 && n!=EOF);
  
 -	ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
 -	gdFree(filedata);
 -	if (ret != webp_success) {
 -		if (Y) free(Y);
 -		if (U) free(U);
 -		if (V) free(V);
 -		php_gd_error("WebP decode: fail to decode input data");
 +	if (WebPGetInfo(filedata,size, &width, &height) == 0) {
 +		zend_error(E_ERROR, "gd-webp cannot get webp info");
 +		gdFree(filedata);
  		return NULL;
  	}
 +
  	im = gdImageCreateTrueColor(width, height);
 -	gd_YUV420toRGBA(Y, U, V, im);
 +	if (!im) {
 +		gdFree(filedata);
 +		return NULL;
 +	}
 +	argb = WebPDecodeARGB(filedata, size, &width, &height);
 +	if (!argb) {
 +		zend_error(E_ERROR, "gd-webp cannot allocate temporary buffer");
 +		gdFree(filedata);
 +		gdImageDestroy(im);
 +		return NULL;
 +	}
 +	for (y = 0, p = argb;  y < height; y++) {
 +		for (x = 0; x < width; x++) {
 +			register uint8_t a = gdAlphaMax - (*(p++) >> 1);
 +			register uint8_t r = *(p++);
 +			register uint8_t g = *(p++);
 +			register uint8_t b = *(p++);
 +			im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
 +		}
 +	}
 +	gdFree(filedata);
 +	/* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
 +	free(argb);
 +	im->saveAlphaFlag = 1;
  	return im;
  }
  
 +void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
 +{
 +	uint8_t *argb;
 +	int x, y;
 +	uint8_t *p;
 +	uint8_t *out;
 +	size_t out_size;
 +
 +	if (im == NULL) {
 +		return;
 +	}
 +
 +	if (!gdImageTrueColor(im)) {
 +		zend_error(E_ERROR, "Paletter image not supported by webp");
 +		return;
 +	}
 +
 +	if (quantization == -1) {
 +		quantization = 80;
 +	}
 +
++	if (overflow2(gdImageSX(im), 4)) {
++		return;
++	}
++
++	if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
++		return;
++	}
++
 +	argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
 +	if (!argb) {
 +		return;
 +	}
 +	p = argb;
 +	for (y = 0; y < gdImageSY(im); y++) {
 +		for (x = 0; x < gdImageSX(im); x++) {
 +			register int c;
 +			register char a;
 +			c = im->tpixels[y][x];
 +			a = gdTrueColorGetAlpha(c);
 +			if (a == 127) {
 +				a = 0;
 +			} else {
 +				a = 255 - ((a << 1) + (a >> 6));
 +			}
 +			*(p++) = gdTrueColorGetRed(c);
 +			*(p++) = gdTrueColorGetGreen(c);
 +			*(p++) = gdTrueColorGetBlue(c); 
 +			*(p++) = a;
 +		}
 +	}
 +	out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out);
 +	if (out_size == 0) {
 +		zend_error(E_ERROR, "gd-webp encoding failed");
 +		goto freeargb;
 +	}
 +	gdPutBuf(out, out_size, outfile);
 +	free(out);
 +
 +freeargb:
 +	gdFree(argb);
 +}
 +
  void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
  {
  	gdIOCtx *out = gdNewFileCtx(outFile);
  	gdImageWebpCtx(im, out, quantization);
  	out->gd_free(out);

Fixed code:    . Fixed bug #73003 (Integer Overflow in gdImageWebpCtx of gd_webp.c). (trylab,
     cmb)
+	if (overflow2(gdImageSX(im), 4)) {
+		return;
+	}
+
+	if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
+		return;
+	}
+