CVE-2014-2020: Numeric Errors (CWE-189)
value: ext/gd/gd.c in PHP 5.5.x before 5.5.9 does not check data types, which might allow remote attackers to obtain sensitive information by using a (1) string or (2) array data type in place of a numeric data type, as demonstrated by an imagecrop function call with a string for the x dimension value, a different vulnerability than CVE-2013-7226.
CWE description: Weaknesses in this category are related to improper calculation or conversion of numbers.
Published: 2014-02-18T11:55Z
Repository: https://github.com/php/php-src
Language: Other
Files changed: NEWS, ext/gd/gd.c, ext/gd/tests/bug66356.phpt, main/php_version.h
Commit date: 2013-12-27 14:04:59 +0800
Commit message: Fixed bug #66356 (Heap Overflow Vulnerability in imagecrop())

And also fixed the bug: arguments are altered after some calls

Diff: diff --git a/NEWS b/NEWS
index eecd4e80028..86eeb7cea9f 100644
--- a/NEWS
+++ b/NEWS
@@ -27,10 +27,11 @@ PHP                                                                        NEWS
 
 - Filter:
   . Fixed bug #66229 (128.0.0.0/16 isn't reserved any longer). (Adam)
 
 - GD:
+  . Fixed bug #66356 (Heap Overflow Vulnerability in imagecrop()). (Laruence)
   . Fixed bug #64405 (Use freetype-config for determining freetype2 dir(s)).
     (Adam)
     
 - PDO_odbc:
   . Fixed bug #66311 (Stack smashing protection kills PDO/ODBC queries). 
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index fb258214a15..49970c16883 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -1536,13 +1536,19 @@ PHP_FUNCTION(imagesetstyle)
 
 		if (zend_hash_get_current_data_ex(HASH_OF(styles), (void **) &item, &pos) == FAILURE) {
 			break;
 		}
 
-		convert_to_long_ex(item);
-
-		stylearr[index++] = Z_LVAL_PP(item);
+		if (Z_TYPE_PP(item) != IS_LONG) {
+			zval lval;
+			lval = **item;
+			zval_copy_ctor(&lval);
+			convert_to_long(&lval);
+			stylearr[index++] = Z_LVAL(lval);
+		} else {
+			stylearr[index++] = Z_LVAL_PP(item);
+		}
 	}
 
 	gdImageSetStyle(im, stylearr, index);
 
 	efree(stylearr);
@@ -3344,18 +3350,30 @@ static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
 
 	points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);
 
 	for (i = 0; i < npoints; i++) {
 		if (zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2), (void **) &var) == SUCCESS) {
-			SEPARATE_ZVAL((var));
-			convert_to_long(*var);
-			points[i].x = Z_LVAL_PP(var);
+			if (Z_TYPE_PP(var) != IS_LONG) {
+				zval lval;
+				lval = **var;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				points[i].x = Z_LVAL(lval);
+			} else {
+				points[i].x = Z_LVAL_PP(var);
+			}
 		}
 		if (zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1, (void **) &var) == SUCCESS) {
-			SEPARATE_ZVAL(var);
-			convert_to_long(*var);
-			points[i].y = Z_LVAL_PP(var);
+			if (Z_TYPE_PP(var) != IS_LONG) {
+				zval lval;
+				lval = **var;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				points[i].y = Z_LVAL(lval);
+			} else {
+				points[i].y = Z_LVAL_PP(var);
+			}
 		}
 	}
 
 	if (filled) {
 		gdImageFilledPolygon(im, points, npoints, col);
@@ -4857,13 +4875,19 @@ PHP_FUNCTION(imageconvolution)
 				RETURN_FALSE;
 			}
 
 			for (j=0; j<3; j++) {
 				if (zend_hash_index_find(Z_ARRVAL_PP(var), (j), (void **) &var2) == SUCCESS) {
-					SEPARATE_ZVAL(var2);
-					convert_to_double(*var2);
-					matrix[i][j] = (float)Z_DVAL_PP(var2);
+					if (Z_TYPE_PP(var2) != IS_DOUBLE) {
+						zval dval;
+						dval = **var;
+						zval_copy_ctor(&dval);
+						convert_to_double(&dval);
+						matrix[i][j] = (float)Z_DVAL(dval);
+					} else {
+						matrix[i][j] = (float)Z_DVAL_PP(var2);
+					}
 				} else {
 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must have a 3x3 matrix");
 					RETURN_FALSE;
 				}
 			}
@@ -4952,32 +4976,64 @@ PHP_FUNCTION(imagecrop)
 	}
 
 	ZEND_FETCH_RESOURCE(im, gdImagePtr, &IM, -1, "Image", le_gd);
 
 	if (zend_hash_find(HASH_OF(z_rect), "x", sizeof("x"), (void **)&tmp) != FAILURE) {
-		rect.x = Z_LVAL_PP(tmp);
+		if (Z_TYPE_PP(tmp) != IS_LONG) {
+			zval lval;
+			lval = **tmp;
+			zval_copy_ctor(&lval);
+			convert_to_long(&lval);
+			rect.x = Z_LVAL(lval);
+		} else {
+			rect.x = Z_LVAL_PP(tmp);
+		}
 	} else {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing x position");
 		RETURN_FALSE;
 	}
 
 	if (zend_hash_find(HASH_OF(z_rect), "y", sizeof("x"), (void **)&tmp) != FAILURE) {
-		rect.y = Z_LVAL_PP(tmp);
+		if (Z_TYPE_PP(tmp) != IS_LONG) {
+			zval lval;
+			lval = **tmp;
+			zval_copy_ctor(&lval);
+			convert_to_long(&lval);
+			rect.y = Z_LVAL(lval);
+		} else {
+			rect.y = Z_LVAL_PP(tmp);
+		}
 	} else {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing y position");
 		RETURN_FALSE;
 	}
 
 	if (zend_hash_find(HASH_OF(z_rect), "width", sizeof("width"), (void **)&tmp) != FAILURE) {
-		rect.width = Z_LVAL_PP(tmp);
+		if (Z_TYPE_PP(tmp) != IS_LONG) {
+			zval lval;
+			lval = **tmp;
+			zval_copy_ctor(&lval);
+			convert_to_long(&lval);
+			rect.width = Z_LVAL(lval);
+		} else {
+			rect.width = Z_LVAL_PP(tmp);
+		}
 	} else {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing width");
 		RETURN_FALSE;
 	}
 
 	if (zend_hash_find(HASH_OF(z_rect), "height", sizeof("height"), (void **)&tmp) != FAILURE) {
-		rect.height = Z_LVAL_PP(tmp);
+		if (Z_TYPE_PP(tmp) != IS_LONG) {
+			zval lval;
+			lval = **tmp;
+			zval_copy_ctor(&lval);
+			convert_to_long(&lval);
+			rect.height = Z_LVAL(lval);
+		} else {
+			rect.height = Z_LVAL_PP(tmp);
+		}
 	} else {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing height");
 		RETURN_FALSE;
 	}
 
@@ -5122,48 +5178,81 @@ PHP_FUNCTION(imageaffine)
 					break;
 				case IS_DOUBLE:
 					affine[i] = Z_DVAL_PP(zval_affine_elem);
 					break;
 				case IS_STRING:
-					convert_to_double_ex(zval_affine_elem);
-					affine[i] = Z_DVAL_PP(zval_affine_elem);
+					{
+						zval dval;
+						dval = **zval_affine_elem;
+						zval_copy_ctor(&dval);
+						convert_to_double(&dval);
+						affine[i] = Z_DVAL(dval);
+					}
 					break;
 				default:
 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type for element %i", i);
 					RETURN_FALSE;
 			}
 		}
 	}
 
 	if (z_rect != NULL) {
 		if (zend_hash_find(HASH_OF(z_rect), "x", sizeof("x"), (void **)&tmp) != FAILURE) {
-			convert_to_long_ex(tmp);
-			rect.x = Z_LVAL_PP(tmp);
+			if (Z_TYPE_PP(tmp) != IS_LONG) {
+				zval lval;
+				lval = **tmp;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				rect.x = Z_LVAL(lval);
+			} else {
+				rect.x = Z_LVAL_PP(tmp);
+			}
 		} else {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing x position");
 			RETURN_FALSE;
 		}
 
 		if (zend_hash_find(HASH_OF(z_rect), "y", sizeof("x"), (void **)&tmp) != FAILURE) {
-			convert_to_long_ex(tmp);
-			rect.y = Z_LVAL_PP(tmp);
+			if (Z_TYPE_PP(tmp) != IS_LONG) {
+				zval lval;
+				lval = **tmp;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				rect.y = Z_LVAL(lval);
+			} else {
+				rect.y = Z_LVAL_PP(tmp);
+			}
 		} else {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing y position");
 			RETURN_FALSE;
 		}
 
 		if (zend_hash_find(HASH_OF(z_rect), "width", sizeof("width"), (void **)&tmp) != FAILURE) {
-			convert_to_long_ex(tmp);
-			rect.width = Z_LVAL_PP(tmp);
+			if (Z_TYPE_PP(tmp) != IS_LONG) {
+				zval lval;
+				lval = **tmp;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				rect.width = Z_LVAL(lval);
+			} else {
+				rect.width = Z_LVAL_PP(tmp);
+			}
 		} else {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing width");
 			RETURN_FALSE;
 		}
 
 		if (zend_hash_find(HASH_OF(z_rect), "height", sizeof("height"), (void **)&tmp) != FAILURE) {
-			convert_to_long_ex(tmp);
-			rect.height = Z_LVAL_PP(tmp);
+			if (Z_TYPE_PP(tmp) != IS_LONG) {
+				zval lval;
+				lval = **tmp;
+				zval_copy_ctor(&lval);
+				convert_to_long(&lval);
+				rect.height = Z_LVAL(lval);
+			} else {
+				rect.height = Z_LVAL_PP(tmp);
+			}
 		} else {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing height");
 			RETURN_FALSE;
 		}
 		pRect = &rect;
@@ -5209,20 +5298,34 @@ PHP_FUNCTION(imageaffinematrixget)
 			double x, y;
 			if (Z_TYPE_P(options) != IS_ARRAY) {
 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array expected as options");
 			}
 			if (zend_hash_find(HASH_OF(options), "x", sizeof("x"), (void **)&tmp) != FAILURE) {
-				convert_to_double_ex(tmp);
-				x = Z_DVAL_PP(tmp);
+				if (Z_TYPE_PP(tmp) != IS_DOUBLE) {
+					zval dval;
+					dval = **tmp;
+					zval_copy_ctor(&dval);
+					convert_to_double(&dval);
+					x = Z_DVAL(dval);
+				} else {
+					x = Z_DVAL_PP(tmp);
+				}
 			} else {
 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing x position");
 				RETURN_FALSE;
 			}
 
 			if (zend_hash_find(HASH_OF(options), "y", sizeof("y"), (void **)&tmp) != FAILURE) {
-				convert_to_double_ex(tmp);
-				y = Z_DVAL_PP(tmp);
+				if (Z_TYPE_PP(tmp) != IS_DOUBLE) {
+					zval dval;
+					dval = **tmp;
+					zval_copy_ctor(&dval);
+					convert_to_double(&dval);
+					y = Z_DVAL(dval);
+				} else {
+					y = Z_DVAL_PP(tmp);
+				}
 			} else {
 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing y position");
 				RETURN_FALSE;
 			}
 			
@@ -5298,12 +5401,17 @@ PHP_FUNCTION(imageaffinematrixconcat)
 					break;
 				case IS_DOUBLE:
 					m1[i] = Z_DVAL_PP(tmp);
 					break;
 				case IS_STRING:
-					convert_to_double_ex(tmp);
-					m1[i] = Z_DVAL_PP(tmp);
+					{
+						zval dval;
+						dval = **tmp;
+						zval_copy_ctor(&dval);
+						convert_to_double(&dval);
+						m1[i] = Z_DVAL(dval);
+					}
 					break;
 				default:
 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type for element %i", i);
 					RETURN_FALSE;
 			}
@@ -5315,12 +5423,17 @@ PHP_FUNCTION(imageaffinematrixconcat)
 					break;
 				case IS_DOUBLE:
 					m2[i] = Z_DVAL_PP(tmp);
 					break;
 				case IS_STRING:
-					convert_to_double_ex(tmp);
-					m2[i] = Z_DVAL_PP(tmp);
+					{
+						zval dval;
+						dval = **tmp;
+						zval_copy_ctor(&dval);
+						convert_to_double(&dval);
+						m2[i] = Z_DVAL(dval);
+					}
 					break;
 				default:
 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type for element %i", i);
 					RETURN_FALSE;
 			}
diff --git a/ext/gd/tests/bug66356.phpt b/ext/gd/tests/bug66356.phpt
new file mode 100644
index 00000000000..f8814947164
--- /dev/null
+++ b/ext/gd/tests/bug66356.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #66356 (Heap Overflow Vulnerability in imagecrop())
+--SKIPIF--
+<?php
+	if(!extension_loaded('gd')){ die('skip gd extension not available'); }
+?>
+--FILE--
+<?php
+$img = imagecreatetruecolor(10, 10);
+$img = imagecrop($img, array("x" => "a", "y" => 0, "width" => 10, "height" => 10));
+$arr = array("x" => "a", "y" => "12b", "width" => 10, "height" => 10);
+$img = imagecrop($img, $arr);
+print_r($arr);
+?>
+--EXPECTF--
+Array
+(
+    [x] => a
+    [y] => 12b
+    [width] => 10
+    [height] => 10
+)
diff --git a/main/php_version.h b/main/php_version.h
index 8d30a367d36..d9ea4aab3cd 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -1,8 +1,8 @@
 /* automatically generated by configure */
 /* edit configure.in to change version number */
 #define PHP_MAJOR_VERSION 5
 #define PHP_MINOR_VERSION 5
-#define PHP_RELEASE_VERSION 8
+#define PHP_RELEASE_VERSION 5
 #define PHP_EXTRA_VERSION "-dev"
-#define PHP_VERSION "5.5.8-dev"
-#define PHP_VERSION_ID 50508
+#define PHP_VERSION "5.5.5-dev"
+#define PHP_VERSION_ID 50505

Vulnerable code: 		convert_to_long_ex(item);

		stylearr[index++] = Z_LVAL_PP(item);
			SEPARATE_ZVAL((var));
			convert_to_long(*var);
			points[i].x = Z_LVAL_PP(var);
			SEPARATE_ZVAL(var);
			convert_to_long(*var);
			points[i].y = Z_LVAL_PP(var);
					SEPARATE_ZVAL(var2);
					convert_to_double(*var2);
					matrix[i][j] = (float)Z_DVAL_PP(var2);
		rect.x = Z_LVAL_PP(tmp);
		rect.y = Z_LVAL_PP(tmp);
		rect.width = Z_LVAL_PP(tmp);
		rect.height = Z_LVAL_PP(tmp);
					convert_to_double_ex(zval_affine_elem);
					affine[i] = Z_DVAL_PP(zval_affine_elem);
			convert_to_long_ex(tmp);
			rect.x = Z_LVAL_PP(tmp);
			convert_to_long_ex(tmp);
			rect.y = Z_LVAL_PP(tmp);
			convert_to_long_ex(tmp);
			rect.width = Z_LVAL_PP(tmp);
			convert_to_long_ex(tmp);
			rect.height = Z_LVAL_PP(tmp);
				convert_to_double_ex(tmp);
				x = Z_DVAL_PP(tmp);
				convert_to_double_ex(tmp);
				y = Z_DVAL_PP(tmp);
					convert_to_double_ex(tmp);
					m1[i] = Z_DVAL_PP(tmp);
					convert_to_double_ex(tmp);
					m2[i] = Z_DVAL_PP(tmp);
#define PHP_RELEASE_VERSION 8
#define PHP_VERSION "5.5.8-dev"
#define PHP_VERSION_ID 50508
Fixed code:   . Fixed bug #66356 (Heap Overflow Vulnerability in imagecrop()). (Laruence)
		if (Z_TYPE_PP(item) != IS_LONG) {
			zval lval;
			lval = **item;
			zval_copy_ctor(&lval);
			convert_to_long(&lval);
			stylearr[index++] = Z_LVAL(lval);
		} else {
			stylearr[index++] = Z_LVAL_PP(item);
		}
			if (Z_TYPE_PP(var) != IS_LONG) {
				zval lval;
				lval = **var;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				points[i].x = Z_LVAL(lval);
			} else {
				points[i].x = Z_LVAL_PP(var);
			}
			if (Z_TYPE_PP(var) != IS_LONG) {
				zval lval;
				lval = **var;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				points[i].y = Z_LVAL(lval);
			} else {
				points[i].y = Z_LVAL_PP(var);
			}
					if (Z_TYPE_PP(var2) != IS_DOUBLE) {
						zval dval;
						dval = **var;
						zval_copy_ctor(&dval);
						convert_to_double(&dval);
						matrix[i][j] = (float)Z_DVAL(dval);
					} else {
						matrix[i][j] = (float)Z_DVAL_PP(var2);
					}
		if (Z_TYPE_PP(tmp) != IS_LONG) {
			zval lval;
			lval = **tmp;
			zval_copy_ctor(&lval);
			convert_to_long(&lval);
			rect.x = Z_LVAL(lval);
		} else {
			rect.x = Z_LVAL_PP(tmp);
		}
		if (Z_TYPE_PP(tmp) != IS_LONG) {
			zval lval;
			lval = **tmp;
			zval_copy_ctor(&lval);
			convert_to_long(&lval);
			rect.y = Z_LVAL(lval);
		} else {
			rect.y = Z_LVAL_PP(tmp);
		}
		if (Z_TYPE_PP(tmp) != IS_LONG) {
			zval lval;
			lval = **tmp;
			zval_copy_ctor(&lval);
			convert_to_long(&lval);
			rect.width = Z_LVAL(lval);
		} else {
			rect.width = Z_LVAL_PP(tmp);
		}
		if (Z_TYPE_PP(tmp) != IS_LONG) {
			zval lval;
			lval = **tmp;
			zval_copy_ctor(&lval);
			convert_to_long(&lval);
			rect.height = Z_LVAL(lval);
		} else {
			rect.height = Z_LVAL_PP(tmp);
		}
					{
						zval dval;
						dval = **zval_affine_elem;
						zval_copy_ctor(&dval);
						convert_to_double(&dval);
						affine[i] = Z_DVAL(dval);
					}
			if (Z_TYPE_PP(tmp) != IS_LONG) {
				zval lval;
				lval = **tmp;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				rect.x = Z_LVAL(lval);
			} else {
				rect.x = Z_LVAL_PP(tmp);
			}
			if (Z_TYPE_PP(tmp) != IS_LONG) {
				zval lval;
				lval = **tmp;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				rect.y = Z_LVAL(lval);
			} else {
				rect.y = Z_LVAL_PP(tmp);
			}
			if (Z_TYPE_PP(tmp) != IS_LONG) {
				zval lval;
				lval = **tmp;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				rect.width = Z_LVAL(lval);
			} else {
				rect.width = Z_LVAL_PP(tmp);
			}
			if (Z_TYPE_PP(tmp) != IS_LONG) {
				zval lval;
				lval = **tmp;
				zval_copy_ctor(&lval);
				convert_to_long(&lval);
				rect.height = Z_LVAL(lval);
			} else {
				rect.height = Z_LVAL_PP(tmp);
			}
				if (Z_TYPE_PP(tmp) != IS_DOUBLE) {
					zval dval;
					dval = **tmp;
					zval_copy_ctor(&dval);
					convert_to_double(&dval);
					x = Z_DVAL(dval);
				} else {
					x = Z_DVAL_PP(tmp);
				}
				if (Z_TYPE_PP(tmp) != IS_DOUBLE) {
					zval dval;
					dval = **tmp;
					zval_copy_ctor(&dval);
					convert_to_double(&dval);
					y = Z_DVAL(dval);
				} else {
					y = Z_DVAL_PP(tmp);
				}
					{
						zval dval;
						dval = **tmp;
						zval_copy_ctor(&dval);
						convert_to_double(&dval);
						m1[i] = Z_DVAL(dval);
					}
					{
						zval dval;
						dval = **tmp;
						zval_copy_ctor(&dval);
						convert_to_double(&dval);
						m2[i] = Z_DVAL(dval);
					}
--TEST--
Bug #66356 (Heap Overflow Vulnerability in imagecrop())
--SKIPIF--
<?php
	if(!extension_loaded('gd')){ die('skip gd extension not available'); }
?>
--FILE--
<?php
$img = imagecreatetruecolor(10, 10);
$img = imagecrop($img, array("x" => "a", "y" => 0, "width" => 10, "height" => 10));
$arr = array("x" => "a", "y" => "12b", "width" => 10, "height" => 10);
$img = imagecrop($img, $arr);
print_r($arr);
?>
--EXPECTF--
Array
(
    [x] => a
    [y] => 12b
    [width] => 10
    [height] => 10
)
#define PHP_RELEASE_VERSION 5
#define PHP_VERSION "5.5.5-dev"
#define PHP_VERSION_ID 50505