CVE-2016-10159: Integer Overflow or Wraparound (CWE-190)
value: Integer overflow in the phar_parse_pharfile function in ext/phar/phar.c in PHP before 5.6.30 and 7.0.x before 7.0.15 allows remote attackers to cause a denial of service (memory consumption or application crash) via a truncated manifest entry in a PHAR archive.
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: 7.5
Published: 2017-01-24T21:59Z
Repository: https://github.com/php/php-src
Language: C
Files changed: ext/phar/phar.c, ext/phar/tests/bug73764.phpt
Commit date: 2016-12-30 15:39:48 -0800
Commit message: Fix int overflows in phar (bug #73764)

Diff: diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 14b80e175ed..532b4c3169a 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -1053,11 +1053,11 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
 	entry.phar = mydata;
 	entry.fp_type = PHAR_FP;
 	entry.is_persistent = mydata->is_persistent;
 
 	for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
-		if (buffer + 4 > endbuffer) {
+		if (buffer + 24 > endbuffer) {
 			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
 		}
 
 		PHAR_GET_32(buffer, entry.filename_len);
 
@@ -1067,11 +1067,11 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
 
 		if (entry.is_persistent) {
 			entry.manifest_pos = manifest_index;
 		}
 
-		if (entry.filename_len + 20 > endbuffer - buffer) {
+		if (entry.filename_len > endbuffer - buffer - 20) {
 			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
 		}
 
 		if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
 			entry.is_dir = 1;
diff --git a/ext/phar/tests/bug73764.phar b/ext/phar/tests/bug73764.phar
new file mode 100644
index 00000000000..89a5ff65426
Binary files /dev/null and b/ext/phar/tests/bug73764.phar differ
diff --git a/ext/phar/tests/bug73764.phpt b/ext/phar/tests/bug73764.phpt
new file mode 100644
index 00000000000..cab314a7317
--- /dev/null
+++ b/ext/phar/tests/bug73764.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar: PHP bug #73764: Crash while loading hostile phar archive
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+chdir(__DIR__);
+try {
+$p = Phar::LoadPhar('bug73764.phar', 'alias.phar');
+echo "OK\n";
+} catch(PharException $e) {
+	echo $e->getMessage();
+}
+?>
+--EXPECTF--
+internal corruption of phar "%sbug73764.phar" (truncated manifest entry)
\ No newline at end of file

Vulnerable code: 		if (buffer + 4 > endbuffer) {
		if (entry.filename_len + 20 > endbuffer - buffer) {
Fixed code: 		if (buffer + 24 > endbuffer) {
		if (entry.filename_len > endbuffer - buffer - 20) {
--TEST--
Phar: PHP bug #73764: Crash while loading hostile phar archive
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
chdir(__DIR__);
try {
$p = Phar::LoadPhar('bug73764.phar', 'alias.phar');
echo "OK\n";
} catch(PharException $e) {
	echo $e->getMessage();
}
?>
--EXPECTF--
internal corruption of phar "%sbug73764.phar" (truncated manifest entry)