Merge branch 'PHP-5.5' into PHP-5.6

* PHP-5.5:
  update NEWS
  add NEWS for fixes
  Improve fix for #70172
  Fix bug #70312 - HAVAL gives wrong hashes in specific cases
  fix test
  add test
  Fix bug #70366 - use-after-free vulnerability in unserialize() with SplDoublyLinkedList
  Fix bug #70365 - use-after-free vulnerability in unserialize() with SplObjectStorage
  Fix bug #70172 - Use After Free Vulnerability in unserialize()
  Fix bug #70388 - SOAP serialize_function_call() type confusion
  Fixed bug #70350: ZipArchive::extractTo allows for directory traversal when creating directories
  Improve fix for #70385
  Fix bug #70345 (Multiple vulnerabilities related to PCRE functions)
  Fix bug #70385 (Buffer over-read in exif_read_data with TIFF IFD tag byte value of 32 bytes)
  Fix bug #70219 (Use after free vulnerability in session deserializer)
  Fix for bug #69782
  Add CVE IDs asigned (post release) to PHP 5.4.43
  Add CVE IDs asigned to #69085 (PHP 5.4.39)
  5.4.45 next

Conflicts:
	ext/pcre/php_pcre.c
	ext/standard/var_unserializer.c
	ext/standard/var_unserializer.re
	ext/zip/php_zip.c
This commit is contained in:
Stanislav Malyshev 2015-09-01 12:06:41 -07:00
commit c19d59c550
24 changed files with 970 additions and 827 deletions

View file

@ -2954,13 +2954,13 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
if (length<byte_count-1) { if (length<byte_count-1) {
/* When there are any characters after the first NUL */ /* When there are any characters after the first NUL */
ImageInfo->CopyrightPhotographer = estrdup(value_ptr); ImageInfo->CopyrightPhotographer = estrdup(value_ptr);
ImageInfo->CopyrightEditor = estrdup(value_ptr+length+1); ImageInfo->CopyrightEditor = estrndup(value_ptr+length+1, byte_count-length-1);
spprintf(&ImageInfo->Copyright, 0, "%s, %s", value_ptr, value_ptr+length+1); spprintf(&ImageInfo->Copyright, 0, "%s, %s", value_ptr, value_ptr+length+1);
/* format = TAG_FMT_UNDEFINED; this musn't be ASCII */ /* format = TAG_FMT_UNDEFINED; this musn't be ASCII */
/* but we are not supposed to change this */ /* but we are not supposed to change this */
/* keep in mind that image_info does not store editor value */ /* keep in mind that image_info does not store editor value */
} else { } else {
ImageInfo->Copyright = estrdup(value_ptr); ImageInfo->Copyright = estrndup(value_ptr, byte_count);
} }
} }
break; break;
@ -3051,10 +3051,10 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
break; break;
case TAG_MAKE: case TAG_MAKE:
ImageInfo->make = estrdup(value_ptr); ImageInfo->make = estrndup(value_ptr, byte_count);
break; break;
case TAG_MODEL: case TAG_MODEL:
ImageInfo->model = estrdup(value_ptr); ImageInfo->model = estrndup(value_ptr, byte_count);
break; break;
case TAG_MAKER_NOTE: case TAG_MAKER_NOTE:

View file

@ -336,7 +336,7 @@ PHP_HASH_API void PHP_HAVAL128Final(unsigned char *digest, PHP_HAVAL_CTX * conte
/* Pad out to 118 mod 128. /* Pad out to 118 mod 128.
*/ */
index = (unsigned int) ((context->count[0] >> 3) & 0x3f); index = (unsigned int) ((context->count[0] >> 3) & 0x7f);
padLen = (index < 118) ? (118 - index) : (246 - index); padLen = (index < 118) ? (118 - index) : (246 - index);
PHP_HAVALUpdate(context, PADDING, padLen); PHP_HAVALUpdate(context, PADDING, padLen);
@ -390,7 +390,7 @@ PHP_HASH_API void PHP_HAVAL160Final(unsigned char *digest, PHP_HAVAL_CTX * conte
/* Pad out to 118 mod 128. /* Pad out to 118 mod 128.
*/ */
index = (unsigned int) ((context->count[0] >> 3) & 0x3f); index = (unsigned int) ((context->count[0] >> 3) & 0x7f);
padLen = (index < 118) ? (118 - index) : (246 - index); padLen = (index < 118) ? (118 - index) : (246 - index);
PHP_HAVALUpdate(context, PADDING, padLen); PHP_HAVALUpdate(context, PADDING, padLen);
@ -444,7 +444,7 @@ PHP_HASH_API void PHP_HAVAL192Final(unsigned char *digest, PHP_HAVAL_CTX * conte
/* Pad out to 118 mod 128. /* Pad out to 118 mod 128.
*/ */
index = (unsigned int) ((context->count[0] >> 3) & 0x3f); index = (unsigned int) ((context->count[0] >> 3) & 0x7f);
padLen = (index < 118) ? (118 - index) : (246 - index); padLen = (index < 118) ? (118 - index) : (246 - index);
PHP_HAVALUpdate(context, PADDING, padLen); PHP_HAVALUpdate(context, PADDING, padLen);
@ -484,7 +484,7 @@ PHP_HASH_API void PHP_HAVAL224Final(unsigned char *digest, PHP_HAVAL_CTX * conte
/* Pad out to 118 mod 128. /* Pad out to 118 mod 128.
*/ */
index = (unsigned int) ((context->count[0] >> 3) & 0x3f); index = (unsigned int) ((context->count[0] >> 3) & 0x7f);
padLen = (index < 118) ? (118 - index) : (246 - index); padLen = (index < 118) ? (118 - index) : (246 - index);
PHP_HAVALUpdate(context, PADDING, padLen); PHP_HAVALUpdate(context, PADDING, padLen);
@ -525,7 +525,7 @@ PHP_HASH_API void PHP_HAVAL256Final(unsigned char *digest, PHP_HAVAL_CTX * conte
/* Pad out to 118 mod 128. /* Pad out to 118 mod 128.
*/ */
index = (unsigned int) ((context->count[0] >> 3) & 0x3f); index = (unsigned int) ((context->count[0] >> 3) & 0x7f);
padLen = (index < 118) ? (118 - index) : (246 - index); padLen = (index < 118) ? (118 - index) : (246 - index);
PHP_HAVALUpdate(context, PADDING, padLen); PHP_HAVALUpdate(context, PADDING, padLen);

View file

@ -0,0 +1,18 @@
--TEST--
Bug #70312 HAVAL gives wrong hashes in specific cases
--SKIPIF--
<?php if(!extension_loaded("hash")) print "skip"; ?>
--FILE--
<?php
var_dump(hash('haval128,5', '1234567890123456789012345678901234567890123456789012345678901234'));
var_dump(hash('haval160,5', '1234567890123456789012345678901234567890123456789012345678901234'));
var_dump(hash('haval192,5', '1234567890123456789012345678901234567890123456789012345678901234'));
var_dump(hash('haval224,5', '1234567890123456789012345678901234567890123456789012345678901234'));
var_dump(hash('haval256,5', '1234567890123456789012345678901234567890123456789012345678901234'));
?>
--EXPECTF--
string(32) "f3f0d23819b87228b4b70ee350afaa9d"
string(40) "aded6485e137f11d7292212ba3fa961714df0564"
string(48) "e53da2b16269fe732e9a898a96707a9f28404d7333b02286"
string(56) "c574fb307f0817b514b9bb2e7c4bfaffb7ad667aca3c8b523fefcf10"
string(64) "fb73c19300b14d5cb393d929bf005e6c2d459a4c9c009e9813af1d2d3637ee8f"

View file

@ -709,7 +709,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec
/* If subpatterns array has been passed, fill it in with values. */ /* If subpatterns array has been passed, fill it in with values. */
if (subpats != NULL) { if (subpats != NULL) {
/* Try to get the list of substrings and display a warning if failed. */ /* Try to get the list of substrings and display a warning if failed. */
if (pcre_get_substring_list(subject, offsets, count, &stringlist) < 0) { if ((offsets[1] - offsets[0] < 0) || pcre_get_substring_list(subject, offsets, count, &stringlist) < 0) {
efree(subpat_names); efree(subpat_names);
efree(offsets); efree(offsets);
if (match_sets) efree(match_sets); if (match_sets) efree(match_sets);
@ -1170,7 +1170,7 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
piece = subject + start_offset; piece = subject + start_offset;
if (count > 0 && (limit == -1 || limit > 0)) { if (count > 0 && (offsets[1] - offsets[0] >= 0) && (limit == -1 || limit > 0)) {
if (replace_count) { if (replace_count) {
++*replace_count; ++*replace_count;
} }
@ -1627,7 +1627,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, char *subject, int subjec
} }
/* If something matched */ /* If something matched */
if (count > 0) { if (count > 0 && (offsets[1] - offsets[0] >= 0)) {
if (!no_empty || &subject[offsets[0]] != last_match) { if (!no_empty || &subject[offsets[0]] != last_match) {
if (offset_capture) { if (offset_capture) {

View file

@ -0,0 +1,24 @@
--TEST--
Bug #70345 (Multiple vulnerabilities related to PCRE functions)
--FILE--
<?php
$regex = '/(?=xyz\K)/';
$subject = "aaaaxyzaaaa";
$v = preg_split($regex, $subject);
print_r($v);
$regex = '/(a(?=xyz\K))/';
$subject = "aaaaxyzaaaa";
preg_match($regex, $subject, $matches);
var_dump($matches);
--EXPECTF--
Array
(
[0] => aaaaxyzaaaa
)
Warning: preg_match(): Get subpatterns list failed in %s on line %d
array(0) {
}

View file

@ -216,16 +216,18 @@ static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */
} }
/* }}} */ /* }}} */
static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ static int php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */
{ {
if (!PS(serializer)) { if (!PS(serializer)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
return; return FAILURE;
} }
if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) {
php_session_destroy(TSRMLS_C); php_session_destroy(TSRMLS_C);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed");
return FAILURE;
} }
return SUCCESS;
} }
/* }}} */ /* }}} */
@ -947,8 +949,11 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
ALLOC_INIT_ZVAL(current); ALLOC_INIT_ZVAL(current);
if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC);
} else {
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return FAILURE;
} }
zval_ptr_dtor(&current); var_push_dtor_no_addref(&var_hash, &current);
} }
PS_ADD_VARL(name, namelen); PS_ADD_VARL(name, namelen);
efree(name); efree(name);
@ -1039,8 +1044,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
ALLOC_INIT_ZVAL(current); ALLOC_INIT_ZVAL(current);
if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC);
} else {
var_push_dtor_no_addref(&var_hash, &current);
efree(name);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return FAILURE;
} }
zval_ptr_dtor(&current); var_push_dtor_no_addref(&var_hash, &current);
} }
PS_ADD_VARL(name, namelen); PS_ADD_VARL(name, namelen);
skip: skip:
@ -2063,9 +2073,7 @@ static PHP_FUNCTION(session_decode)
return; return;
} }
php_session_decode(str, str_len TSRMLS_CC); RETVAL_BOOL(php_session_decode(str, str_len TSRMLS_CC) == SUCCESS);
RETURN_TRUE;
} }
/* }}} */ /* }}} */

View file

@ -53,563 +53,247 @@ array(0) {
} }
-- Iteration 4 -- -- Iteration 4 --
bool(true)
array(1) { Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d
["foo"]=> bool(false)
NULL array(0) {
} }
-- Iteration 5 -- -- Iteration 5 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 6 -- -- Iteration 6 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 7 -- -- Iteration 7 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 8 -- -- Iteration 8 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 9 -- -- Iteration 9 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 10 -- -- Iteration 10 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 11 -- -- Iteration 11 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 12 -- -- Iteration 12 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 13 -- -- Iteration 13 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 14 -- -- Iteration 14 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 15 -- -- Iteration 15 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 16 -- -- Iteration 16 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 17 -- -- Iteration 17 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 18 -- -- Iteration 18 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 19 -- -- Iteration 19 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 20 -- -- Iteration 20 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 21 -- -- Iteration 21 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 22 -- -- Iteration 22 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 23 -- -- Iteration 23 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 24 -- -- Iteration 24 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 25 -- -- Iteration 25 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 26 -- -- Iteration 26 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 27 -- -- Iteration 27 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 28 -- -- Iteration 28 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 29 -- -- Iteration 29 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 30 -- -- Iteration 30 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 31 -- -- Iteration 31 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 32 -- -- Iteration 32 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 33 -- -- Iteration 33 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
NULL
} }
-- Iteration 34 -- -- Iteration 34 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 35 -- -- Iteration 35 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 36 -- -- Iteration 36 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 37 -- -- Iteration 37 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 38 -- -- Iteration 38 --
bool(true) bool(false)
array(1) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 39 -- -- Iteration 39 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
NULL
} }
-- Iteration 40 -- -- Iteration 40 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
NULL
} }
-- Iteration 41 -- -- Iteration 41 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
NULL
} }
-- Iteration 42 -- -- Iteration 42 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
NULL
} }
-- Iteration 43 -- -- Iteration 43 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 44 -- -- Iteration 44 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 45 -- -- Iteration 45 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 46 -- -- Iteration 46 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 47 -- -- Iteration 47 --
bool(true) bool(false)
array(2) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
} }
-- Iteration 48 -- -- Iteration 48 --
bool(true) bool(false)
array(3) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["blah"]=>
NULL
} }
-- Iteration 49 -- -- Iteration 49 --
bool(true) bool(false)
array(3) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["blah"]=>
NULL
} }
-- Iteration 50 -- -- Iteration 50 --
bool(true) bool(false)
array(3) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["blah"]=>
NULL
} }
-- Iteration 51 -- -- Iteration 51 --
bool(true) bool(false)
array(3) { array(0) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["guff"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
["blah"]=>
NULL
} }
bool(true)
Done
Warning: session_destroy(): Trying to destroy uninitialized session in %s/session_decode_error2.php on line %d
bool(false)
Done

View file

@ -49,7 +49,7 @@ array(3) {
} }
Warning: session_decode(): Unknown session.serialize_handler. Failed to decode session object in %s on line %d Warning: session_decode(): Unknown session.serialize_handler. Failed to decode session object in %s on line %d
bool(true) bool(false)
array(3) { array(3) {
["foo"]=> ["foo"]=>
int(1234567890) int(1234567890)

View file

@ -2921,8 +2921,10 @@ PHP_METHOD(SoapClient, __call)
} }
zend_hash_internal_pointer_reset(default_headers); zend_hash_internal_pointer_reset(default_headers);
while (zend_hash_get_current_data(default_headers, (void**)&tmp) == SUCCESS) { while (zend_hash_get_current_data(default_headers, (void**)&tmp) == SUCCESS) {
Z_ADDREF_PP(tmp); if(Z_TYPE_PP(tmp) == IS_OBJECT) {
zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL); Z_ADDREF_PP(tmp);
zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL);
}
zend_hash_move_forward(default_headers); zend_hash_move_forward(default_headers);
} }
} else { } else {
@ -4346,11 +4348,18 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
if (head) { if (head) {
zval** header; zval** header;
zend_hash_internal_pointer_reset(soap_headers); for(zend_hash_internal_pointer_reset(soap_headers);
while (zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS) { zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS;
HashTable *ht = Z_OBJPROP_PP(header); zend_hash_move_forward(soap_headers)
) {
HashTable *ht;
zval **name, **ns, **tmp; zval **name, **ns, **tmp;
if (Z_TYPE_PP(header) != IS_OBJECT) {
continue;
}
ht = Z_OBJPROP_PP(header);
if (zend_hash_find(ht, "name", sizeof("name"), (void**)&name) == SUCCESS && if (zend_hash_find(ht, "name", sizeof("name"), (void**)&name) == SUCCESS &&
Z_TYPE_PP(name) == IS_STRING && Z_TYPE_PP(name) == IS_STRING &&
zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&ns) == SUCCESS && zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&ns) == SUCCESS &&
@ -4389,7 +4398,6 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
xmlSetNs(h, nsptr); xmlSetNs(h, nsptr);
set_soap_header_attributes(h, ht, version); set_soap_header_attributes(h, ht, version);
} }
zend_hash_move_forward(soap_headers);
} }
} }

View file

@ -0,0 +1,17 @@
--TEST--
Bug #70388 (SOAP serialize_function_call() type confusion / RCE)
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
$dummy = unserialize('O:10:"SoapClient":3:{s:3:"uri";s:1:"X";s:8:"location";s:22:"http://localhost/a.xml";s:17:"__default_headers";a:1:{i:1;s:1337:"'.str_repeat("X", 1337).'";}}');
try {
var_dump($dummy->notexisting());
} catch(Exception $e) {
var_dump($e->getMessage());
var_dump(get_class($e));
}
?>
--EXPECTF--
string(%d) "%s"
string(9) "SoapFault"

View file

@ -1219,6 +1219,7 @@ SPL_METHOD(SplDoublyLinkedList, unserialize)
zval_ptr_dtor(&elem); zval_ptr_dtor(&elem);
goto error; goto error;
} }
var_push_dtor(&var_hash, &elem);
spl_ptr_llist_push(intern->llist, elem TSRMLS_CC); spl_ptr_llist_push(intern->llist, elem TSRMLS_CC);
} }

View file

@ -859,6 +859,7 @@ SPL_METHOD(SplObjectStorage, unserialize)
zval_ptr_dtor(&pentry); zval_ptr_dtor(&pentry);
goto outexcept; goto outexcept;
} }
var_push_dtor(&var_hash, &pentry);
if(Z_TYPE_P(pentry) != IS_OBJECT) { if(Z_TYPE_P(pentry) != IS_OBJECT) {
zval_ptr_dtor(&pentry); zval_ptr_dtor(&pentry);
goto outexcept; goto outexcept;
@ -870,6 +871,7 @@ SPL_METHOD(SplObjectStorage, unserialize)
zval_ptr_dtor(&pinf); zval_ptr_dtor(&pinf);
goto outexcept; goto outexcept;
} }
var_push_dtor(&var_hash, &pinf);
} }
hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC); hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC);

View file

@ -0,0 +1,50 @@
--TEST--
SPL: Bug #70155 Use After Free Vulnerability in unserialize() with SPLArrayObject
--FILE--
<?php
$inner = 'x:i:0;O:12:"DateInterval":1:{s:1:"y";i:3;};m:a:1:{i:0;R:2;}';
$exploit = 'C:11:"ArrayObject":'.strlen($inner).':{'.$inner.'}';
$data = unserialize($exploit);
var_dump($data);
?>
===DONE===
--EXPECTF--
object(ArrayObject)#1 (2) {
[0]=>
int(0)
["storage":"ArrayObject":private]=>
object(DateInterval)#2 (15) {
["y"]=>
int(3)
["m"]=>
int(-1)
["d"]=>
int(-1)
["h"]=>
int(-1)
["i"]=>
int(-1)
["s"]=>
int(-1)
["weekday"]=>
int(-1)
["weekday_behavior"]=>
int(-1)
["first_last_day_of"]=>
int(-1)
["invert"]=>
int(0)
["days"]=>
int(-1)
["special_type"]=>
int(0)
["special_amount"]=>
int(-1)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
}
===DONE===

View file

@ -0,0 +1,50 @@
--TEST--
SPL: Bug #70365 use-after-free vulnerability in unserialize() with SplObjectStorage
--FILE--
<?php
class obj {
var $ryat;
function __wakeup() {
$this->ryat = 1;
}
}
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
$inner = 'x:i:1;O:8:"stdClass":0:{},i:1;;m:a:0:{}';
$exploit = 'a:5:{i:0;i:1;i:1;C:16:"SplObjectStorage":'.strlen($inner).':{'.$inner.'}i:2;O:3:"obj":1:{s:4:"ryat";R:3;}i:3;R:6;i:4;s:'.strlen($fakezval).':"'.$fakezval.'";}';
$data = unserialize($exploit);
var_dump($data);
function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
--EXPECTF--
array(5) {
[0]=>
int(1)
[1]=>
&int(1)
[2]=>
object(obj)#%d (1) {
["ryat"]=>
&int(1)
}
[3]=>
int(1)
[4]=>
string(24) "%s"
}

View file

@ -0,0 +1,54 @@
--TEST--
SPL: Bug #70366 use-after-free vulnerability in unserialize() with SplDoublyLinkedList
--FILE--
<?php
class obj {
var $ryat;
function __wakeup() {
$this->ryat = 1;
}
}
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
$inner = 'i:1234;:i:1;';
$exploit = 'a:5:{i:0;i:1;i:1;C:19:"SplDoublyLinkedList":'.strlen($inner).':{'.$inner.'}i:2;O:3:"obj":1:{s:4:"ryat";R:3;}i:3;a:1:{i:0;R:5;}i:4;s:'.strlen($fakezval).':"'.$fakezval.'";}';
$data = unserialize($exploit);
var_dump($data);
function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
?>
--EXPECTF--
array(5) {
[0]=>
int(1)
[1]=>
&int(1)
[2]=>
object(obj)#%d (1) {
["ryat"]=>
&int(1)
}
[3]=>
array(1) {
[0]=>
int(1)
}
[4]=>
string(24) "%s"
}

View file

@ -0,0 +1,54 @@
--TEST--
Bug #70172 - Use After Free Vulnerability in unserialize()
--XFAIL--
Memory leak on debug build, needs fix.
--FILE--
<?php
class obj implements Serializable {
var $data;
function serialize() {
return serialize($this->data);
}
function unserialize($data) {
$this->data = unserialize($data);
}
}
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
$inner = 'r:2;';
$exploit = 'a:2:{i:0;i:1;i:1;C:3:"obj":'.strlen($inner).':{'.$inner.'}}';
$data = unserialize($exploit);
for ($i = 0; $i < 5; $i++) {
$v[$i] = $fakezval.$i;
}
var_dump($data);
function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
?>
--EXPECTF--
array(2) {
[0]=>
int(1)
[1]=>
object(obj)#%d (1) {
["data"]=>
int(1)
}
}

View file

@ -0,0 +1,68 @@
--TEST--
Bug #70172 - Use After Free Vulnerability in unserialize()
--FILE--
<?php
class obj implements Serializable {
var $data;
function serialize() {
return serialize($this->data);
}
function unserialize($data) {
$this->data = unserialize($data);
}
}
class obj2 {
var $ryat;
function __wakeup() {
$this->ryat = 1;
}
}
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
$inner = 'r:2;';
$exploit = 'a:2:{i:0;O:4:"obj2":1:{s:4:"ryat";C:3:"obj":'.strlen($inner).':{'.$inner.'}}i:1;a:1:{i:0;a:1:{i:0;R:4;}}}';
$data = unserialize($exploit);
for ($i = 0; $i < 5; $i++) {
$v[$i] = $fakezval.$i;
}
var_dump($data);
function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
?>
--EXPECTF--
array(2) {
[0]=>
object(obj2)#%d (1) {
["ryat"]=>
int(1)
}
[1]=>
array(1) {
[0]=>
array(1) {
[0]=>
object(obj2)#%d (1) {
["ryat"]=>
int(1)
}
}
}
}

View file

@ -0,0 +1,38 @@
--TEST--
Bug #70219 Use after free vulnerability in session deserializer
--FILE--
<?php
class obj implements Serializable {
var $data;
function serialize() {
return serialize($this->data);
}
function unserialize($data) {
session_start();
session_decode($data);
}
}
$inner = 'ryat|a:1:{i:0;a:1:{i:1;';
$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}';
$data = unserialize($exploit);
for ($i = 0; $i < 5; $i++) {
$v[$i] = 'hi'.$i;
}
var_dump($data);
?>
--EXPECTF--
Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s on line %d
array(2) {
[0]=>
object(obj)#%d (1) {
["data"]=>
NULL
}
[1]=>
array(0) {
}
}

View file

@ -948,6 +948,8 @@ PHP_FUNCTION(unserialize)
int buf_len; int buf_len;
const unsigned char *p; const unsigned char *p;
php_unserialize_data_t var_hash; php_unserialize_data_t var_hash;
int oldlevel;
zval *old_rval = return_value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
@ -967,6 +969,20 @@ PHP_FUNCTION(unserialize)
} }
RETURN_FALSE; RETURN_FALSE;
} }
if (return_value != old_rval) {
/*
* Terrible hack due to the fact that executor passes us zval *,
* but unserialize with r/R wants to replace it with another zval *
*/
zval_dtor(old_rval);
*old_rval = *return_value;
zval_copy_ctor(old_rval);
var_push_dtor_no_addref(&var_hash, &return_value);
/* FIXME: old_rval is not freed in some scenarios, see bug #70172
var_push_dtor_no_addref(&var_hash, &old_rval); */
} else {
var_push_dtor(&var_hash, &return_value);
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash); PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
} }
/* }}} */ /* }}} */

View file

@ -68,7 +68,7 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
var_hash = (*var_hashx)->last_dtor; var_hash = (*var_hashx)->last_dtor;
#if VAR_ENTRIES_DBG #if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval)); fprintf(stderr, "var_push_dtor(%p, %ld): %d\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif #endif
if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
@ -91,9 +91,15 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval)
{ {
var_entries *var_hash = (*var_hashx)->last_dtor; var_entries *var_hash;
if (!var_hashx || !*var_hashx) {
return;
}
var_hash = (*var_hashx)->last_dtor;
#if VAR_ENTRIES_DBG #if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); fprintf(stderr, "var_push_dtor_no_addref(%p, %ld): %d (%d)\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval));
#endif #endif
if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
@ -172,6 +178,9 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
while (var_hash) { while (var_hash) {
for (i = 0; i < var_hash->used_slots; i++) { for (i = 0; i < var_hash->used_slots; i++) {
#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_hash->data[i], Z_REFCOUNT_P(var_hash->data[i]));
#endif
zval_ptr_dtor(&var_hash->data[i]); zval_ptr_dtor(&var_hash->data[i]);
} }
next = var_hash->next; next = var_hash->next;
@ -232,7 +241,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen
#define YYMARKER marker #define YYMARKER marker
#line 240 "ext/standard/var_unserializer.re" #line 249 "ext/standard/var_unserializer.re"
@ -303,23 +312,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
ALLOC_INIT_ZVAL(key); ALLOC_INIT_ZVAL(key);
if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key);
return 0; return 0;
} }
if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key);
return 0; return 0;
} }
ALLOC_INIT_ZVAL(data); ALLOC_INIT_ZVAL(data);
if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key); var_push_dtor_no_addref(var_hash, &data);
zval_ptr_dtor(&data);
return 0; return 0;
} }
@ -348,9 +354,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
sizeof data, NULL); sizeof data, NULL);
} }
var_push_dtor(var_hash, &data); var_push_dtor(var_hash, &data);
var_push_dtor_no_addref(var_hash, &key);
zval_dtor(key);
FREE_ZVAL(key);
if (elements && *(*p-1) != ';' && *(*p-1) != '}') { if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
(*p)--; (*p)--;
@ -478,7 +482,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
#line 482 "ext/standard/var_unserializer.c" #line 486 "ext/standard/var_unserializer.c"
{ {
YYCTYPE yych; YYCTYPE yych;
static const unsigned char yybm[] = { static const unsigned char yybm[] = {
@ -538,9 +542,9 @@ yy2:
yych = *(YYMARKER = ++YYCURSOR); yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy95; if (yych == ':') goto yy95;
yy3: yy3:
#line 833 "ext/standard/var_unserializer.re" #line 840 "ext/standard/var_unserializer.re"
{ return 0; } { return 0; }
#line 544 "ext/standard/var_unserializer.c" #line 548 "ext/standard/var_unserializer.c"
yy4: yy4:
yych = *(YYMARKER = ++YYCURSOR); yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy89; if (yych == ':') goto yy89;
@ -583,13 +587,13 @@ yy13:
goto yy3; goto yy3;
yy14: yy14:
++YYCURSOR; ++YYCURSOR;
#line 827 "ext/standard/var_unserializer.re" #line 834 "ext/standard/var_unserializer.re"
{ {
/* this is the case where we have less data than planned */ /* this is the case where we have less data than planned */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
return 0; /* not sure if it should be 0 or 1 here? */ return 0; /* not sure if it should be 0 or 1 here? */
} }
#line 593 "ext/standard/var_unserializer.c" #line 597 "ext/standard/var_unserializer.c"
yy16: yy16:
yych = *++YYCURSOR; yych = *++YYCURSOR;
goto yy3; goto yy3;
@ -620,7 +624,7 @@ yy20:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != '"') goto yy18; if (yych != '"') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 681 "ext/standard/var_unserializer.re" #line 687 "ext/standard/var_unserializer.re"
{ {
size_t len, len2, len3, maxlen; size_t len, len2, len3, maxlen;
long elements; long elements;
@ -636,6 +640,7 @@ yy20:
zval **args[1]; zval **args[1];
zval *arg_func_name; zval *arg_func_name;
if (!var_hash) return 0;
if (*start == 'C') { if (*start == 'C') {
custom_object = 1; custom_object = 1;
} }
@ -766,7 +771,7 @@ yy20:
return object_common2(UNSERIALIZE_PASSTHRU, elements); return object_common2(UNSERIALIZE_PASSTHRU, elements);
} }
#line 770 "ext/standard/var_unserializer.c" #line 775 "ext/standard/var_unserializer.c"
yy25: yy25:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= ',') { if (yych <= ',') {
@ -791,15 +796,16 @@ yy27:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != '"') goto yy18; if (yych != '"') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 673 "ext/standard/var_unserializer.re" #line 678 "ext/standard/var_unserializer.re"
{ {
if (!var_hash) return 0;
INIT_PZVAL(*rval); INIT_PZVAL(*rval);
return object_common2(UNSERIALIZE_PASSTHRU, return object_common2(UNSERIALIZE_PASSTHRU,
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
} }
#line 803 "ext/standard/var_unserializer.c" #line 809 "ext/standard/var_unserializer.c"
yy32: yy32:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych == '+') goto yy33; if (yych == '+') goto yy33;
@ -820,11 +826,12 @@ yy34:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != '{') goto yy18; if (yych != '{') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 653 "ext/standard/var_unserializer.re" #line 657 "ext/standard/var_unserializer.re"
{ {
long elements = parse_iv(start + 2); long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */ /* use iv() not uiv() in order to check data range */
*p = YYCURSOR; *p = YYCURSOR;
if (!var_hash) return 0;
if (elements < 0) { if (elements < 0) {
return 0; return 0;
@ -840,7 +847,7 @@ yy34:
return finish_nested_data(UNSERIALIZE_PASSTHRU); return finish_nested_data(UNSERIALIZE_PASSTHRU);
} }
#line 844 "ext/standard/var_unserializer.c" #line 851 "ext/standard/var_unserializer.c"
yy39: yy39:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych == '+') goto yy40; if (yych == '+') goto yy40;
@ -861,7 +868,7 @@ yy41:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != '"') goto yy18; if (yych != '"') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 624 "ext/standard/var_unserializer.re" #line 628 "ext/standard/var_unserializer.re"
{ {
size_t len, maxlen; size_t len, maxlen;
char *str; char *str;
@ -890,7 +897,7 @@ yy41:
ZVAL_STRINGL(*rval, str, len, 0); ZVAL_STRINGL(*rval, str, len, 0);
return 1; return 1;
} }
#line 894 "ext/standard/var_unserializer.c" #line 901 "ext/standard/var_unserializer.c"
yy46: yy46:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych == '+') goto yy47; if (yych == '+') goto yy47;
@ -911,7 +918,7 @@ yy48:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != '"') goto yy18; if (yych != '"') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 596 "ext/standard/var_unserializer.re" #line 600 "ext/standard/var_unserializer.re"
{ {
size_t len, maxlen; size_t len, maxlen;
char *str; char *str;
@ -939,7 +946,7 @@ yy48:
ZVAL_STRINGL(*rval, str, len, 1); ZVAL_STRINGL(*rval, str, len, 1);
return 1; return 1;
} }
#line 943 "ext/standard/var_unserializer.c" #line 950 "ext/standard/var_unserializer.c"
yy53: yy53:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= '/') { if (yych <= '/') {
@ -1027,7 +1034,7 @@ yy61:
} }
yy63: yy63:
++YYCURSOR; ++YYCURSOR;
#line 586 "ext/standard/var_unserializer.re" #line 590 "ext/standard/var_unserializer.re"
{ {
#if SIZEOF_LONG == 4 #if SIZEOF_LONG == 4
use_double: use_double:
@ -1037,7 +1044,7 @@ use_double:
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
return 1; return 1;
} }
#line 1041 "ext/standard/var_unserializer.c" #line 1048 "ext/standard/var_unserializer.c"
yy65: yy65:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= ',') { if (yych <= ',') {
@ -1096,7 +1103,7 @@ yy73:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != ';') goto yy18; if (yych != ';') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 571 "ext/standard/var_unserializer.re" #line 575 "ext/standard/var_unserializer.re"
{ {
*p = YYCURSOR; *p = YYCURSOR;
INIT_PZVAL(*rval); INIT_PZVAL(*rval);
@ -1111,7 +1118,7 @@ yy73:
return 1; return 1;
} }
#line 1115 "ext/standard/var_unserializer.c" #line 1122 "ext/standard/var_unserializer.c"
yy76: yy76:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych == 'N') goto yy73; if (yych == 'N') goto yy73;
@ -1138,7 +1145,7 @@ yy79:
if (yych <= '9') goto yy79; if (yych <= '9') goto yy79;
if (yych != ';') goto yy18; if (yych != ';') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 544 "ext/standard/var_unserializer.re" #line 548 "ext/standard/var_unserializer.re"
{ {
#if SIZEOF_LONG == 4 #if SIZEOF_LONG == 4
int digits = YYCURSOR - start - 3; int digits = YYCURSOR - start - 3;
@ -1165,7 +1172,7 @@ yy79:
ZVAL_LONG(*rval, parse_iv(start + 2)); ZVAL_LONG(*rval, parse_iv(start + 2));
return 1; return 1;
} }
#line 1169 "ext/standard/var_unserializer.c" #line 1176 "ext/standard/var_unserializer.c"
yy83: yy83:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= '/') goto yy18; if (yych <= '/') goto yy18;
@ -1173,24 +1180,24 @@ yy83:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych != ';') goto yy18; if (yych != ';') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 537 "ext/standard/var_unserializer.re" #line 541 "ext/standard/var_unserializer.re"
{ {
*p = YYCURSOR; *p = YYCURSOR;
INIT_PZVAL(*rval); INIT_PZVAL(*rval);
ZVAL_BOOL(*rval, parse_iv(start + 2)); ZVAL_BOOL(*rval, parse_iv(start + 2));
return 1; return 1;
} }
#line 1184 "ext/standard/var_unserializer.c" #line 1191 "ext/standard/var_unserializer.c"
yy87: yy87:
++YYCURSOR; ++YYCURSOR;
#line 530 "ext/standard/var_unserializer.re" #line 534 "ext/standard/var_unserializer.re"
{ {
*p = YYCURSOR; *p = YYCURSOR;
INIT_PZVAL(*rval); INIT_PZVAL(*rval);
ZVAL_NULL(*rval); ZVAL_NULL(*rval);
return 1; return 1;
} }
#line 1194 "ext/standard/var_unserializer.c" #line 1201 "ext/standard/var_unserializer.c"
yy89: yy89:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= ',') { if (yych <= ',') {
@ -1213,7 +1220,7 @@ yy91:
if (yych <= '9') goto yy91; if (yych <= '9') goto yy91;
if (yych != ';') goto yy18; if (yych != ';') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 507 "ext/standard/var_unserializer.re" #line 511 "ext/standard/var_unserializer.re"
{ {
long id; long id;
@ -1236,7 +1243,7 @@ yy91:
return 1; return 1;
} }
#line 1240 "ext/standard/var_unserializer.c" #line 1247 "ext/standard/var_unserializer.c"
yy95: yy95:
yych = *++YYCURSOR; yych = *++YYCURSOR;
if (yych <= ',') { if (yych <= ',') {
@ -1259,7 +1266,7 @@ yy97:
if (yych <= '9') goto yy97; if (yych <= '9') goto yy97;
if (yych != ';') goto yy18; if (yych != ';') goto yy18;
++YYCURSOR; ++YYCURSOR;
#line 486 "ext/standard/var_unserializer.re" #line 490 "ext/standard/var_unserializer.re"
{ {
long id; long id;
@ -1272,7 +1279,7 @@ yy97:
} }
if (*rval != NULL) { if (*rval != NULL) {
zval_ptr_dtor(rval); var_push_dtor_no_addref(var_hash, rval);
} }
*rval = *rval_ref; *rval = *rval_ref;
Z_ADDREF_PP(rval); Z_ADDREF_PP(rval);
@ -1280,9 +1287,9 @@ yy97:
return 1; return 1;
} }
#line 1284 "ext/standard/var_unserializer.c" #line 1291 "ext/standard/var_unserializer.c"
} }
#line 835 "ext/standard/var_unserializer.re" #line 842 "ext/standard/var_unserializer.re"
return 0; return 0;

View file

@ -66,7 +66,7 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
var_hash = (*var_hashx)->last_dtor; var_hash = (*var_hashx)->last_dtor;
#if VAR_ENTRIES_DBG #if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval)); fprintf(stderr, "var_push_dtor(%p, %ld): %d\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif #endif
if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
@ -89,9 +89,15 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval)
{ {
var_entries *var_hash = (*var_hashx)->last_dtor; var_entries *var_hash;
if (!var_hashx || !*var_hashx) {
return;
}
var_hash = (*var_hashx)->last_dtor;
#if VAR_ENTRIES_DBG #if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); fprintf(stderr, "var_push_dtor_no_addref(%p, %ld): %d (%d)\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval));
#endif #endif
if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
@ -170,6 +176,9 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
while (var_hash) { while (var_hash) {
for (i = 0; i < var_hash->used_slots; i++) { for (i = 0; i < var_hash->used_slots; i++) {
#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_hash->data[i], Z_REFCOUNT_P(var_hash->data[i]));
#endif
zval_ptr_dtor(&var_hash->data[i]); zval_ptr_dtor(&var_hash->data[i]);
} }
next = var_hash->next; next = var_hash->next;
@ -307,23 +316,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
ALLOC_INIT_ZVAL(key); ALLOC_INIT_ZVAL(key);
if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key);
return 0; return 0;
} }
if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key);
return 0; return 0;
} }
ALLOC_INIT_ZVAL(data); ALLOC_INIT_ZVAL(data);
if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
zval_dtor(key); var_push_dtor_no_addref(var_hash, &key);
FREE_ZVAL(key); var_push_dtor_no_addref(var_hash, &data);
zval_ptr_dtor(&data);
return 0; return 0;
} }
@ -352,9 +358,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
sizeof data, NULL); sizeof data, NULL);
} }
var_push_dtor(var_hash, &data); var_push_dtor(var_hash, &data);
var_push_dtor_no_addref(var_hash, &key);
zval_dtor(key);
FREE_ZVAL(key);
if (elements && *(*p-1) != ';' && *(*p-1) != '}') { if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
(*p)--; (*p)--;
@ -495,7 +499,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
} }
if (*rval != NULL) { if (*rval != NULL) {
zval_ptr_dtor(rval); var_push_dtor_no_addref(var_hash, rval);
} }
*rval = *rval_ref; *rval = *rval_ref;
Z_ADDREF_PP(rval); Z_ADDREF_PP(rval);
@ -654,6 +658,7 @@ use_double:
long elements = parse_iv(start + 2); long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */ /* use iv() not uiv() in order to check data range */
*p = YYCURSOR; *p = YYCURSOR;
if (!var_hash) return 0;
if (elements < 0) { if (elements < 0) {
return 0; return 0;
@ -671,6 +676,7 @@ use_double:
} }
"o:" iv ":" ["] { "o:" iv ":" ["] {
if (!var_hash) return 0;
INIT_PZVAL(*rval); INIT_PZVAL(*rval);
@ -693,6 +699,7 @@ object ":" uiv ":" ["] {
zval **args[1]; zval **args[1];
zval *arg_func_name; zval *arg_func_name;
if (!var_hash) return 0;
if (*start == 'C') { if (*start == 'C') {
custom_object = 1; custom_object = 1;
} }

View file

@ -223,7 +223,9 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
if (error == 1) { if (error == 1) {
for (i = nargs - 1; i >= 0; i--) { for (i = nargs - 1; i >= 0; i--) {
obj = valuePop(ctxt); obj = valuePop(ctxt);
xmlXPathFreeObject(obj); if (obj) {
xmlXPathFreeObject(obj);
}
} }
return; return;
} }
@ -302,9 +304,11 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
fci.function_table = EG(function_table); fci.function_table = EG(function_table);
obj = valuePop(ctxt); obj = valuePop(ctxt);
if (obj->stringval == NULL) { if (obj == NULL || obj->stringval == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string"); if (obj) {
xmlXPathFreeObject(obj); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string");
xmlXPathFreeObject(obj);
}
valuePush(ctxt, xmlXPathNewString("")); valuePush(ctxt, xmlXPathNewString(""));
if (fci.param_count > 0) { if (fci.param_count > 0) {
for (i = 0; i < nargs - 1; i++) { for (i = 0; i < nargs - 1; i++) {

View file

@ -200,7 +200,7 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil
/* it is a directory only, see #40228 */ /* it is a directory only, see #40228 */
if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) { if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) {
len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file); len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, path_cleaned);
is_dir_only = 1; is_dir_only = 1;
} else { } else {
memcpy(file_dirname, path_cleaned, path_cleaned_len); memcpy(file_dirname, path_cleaned, path_cleaned_len);

View file

@ -0,0 +1,33 @@
--TEST--
Bug #70350 (ZipArchive::extractTo allows for directory traversal when creating directories)
--SKIPIF--
<?php
if(!extension_loaded('zip')) die('skip');
?>
--FILE--
<?php
$dir = dirname(__FILE__)."/bug70350";
mkdir($dir);
$archive = new ZipArchive();
$archive->open("$dir/a.zip",ZipArchive::CREATE);
$archive->addEmptyDir("../down2/");
$archive->close();
$archive2 = new ZipArchive();
$archive2->open("$dir/a.zip");
$archive2->extractTo($dir);
$archive2->close();
var_dump(file_exists("$dir/down2/"));
var_dump(file_exists("../down2/"));
?>
--CLEAN--
<?php
$dir = dirname(__FILE__)."/bug70350";
rmdir("$dir/down2");
unlink("$dir/a.zip");
rmdir($dir);
?>
--EXPECT--
bool(true)
bool(false)