diff options
28 files changed, 748 insertions, 347 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 0796ee9488..8f288a726b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1243,26 +1243,35 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) { zval *prop, tmp; zend_string *key; + zend_long h; zend_property_info *property_info; - ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) { - property_info = zend_get_property_info(object->ce, key, 1); - if (property_info != ZEND_WRONG_PROPERTY_INFO && - property_info && - (property_info->flags & ZEND_ACC_STATIC) == 0) { - zval *slot = OBJ_PROP(object, property_info->offset); - zval_ptr_dtor(slot); - ZVAL_COPY_VALUE(slot, prop); - zval_add_ref(slot); - if (object->properties) { - ZVAL_INDIRECT(&tmp, slot); - zend_hash_update(object->properties, key, &tmp); + ZEND_HASH_FOREACH_KEY_VAL(properties, h, key, prop) { + if(key) { + property_info = zend_get_property_info(object->ce, key, 1); + if (property_info != ZEND_WRONG_PROPERTY_INFO && + property_info && + (property_info->flags & ZEND_ACC_STATIC) == 0) { + zval *slot = OBJ_PROP(object, property_info->offset); + zval_ptr_dtor(slot); + ZVAL_COPY_VALUE(slot, prop); + zval_add_ref(slot); + if (object->properties) { + ZVAL_INDIRECT(&tmp, slot); + zend_hash_update(object->properties, key, &tmp); + } + } else { + if (!object->properties) { + rebuild_object_properties(object); + } + prop = zend_hash_update(object->properties, key, prop); + zval_add_ref(prop); } } else { if (!object->properties) { rebuild_object_properties(object); } - prop = zend_hash_update(object->properties, key, prop); + prop = zend_hash_index_update(object->properties, h, prop); zval_add_ref(prop); } } ZEND_HASH_FOREACH_END(); diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 8bda4ff046..a3f7d40585 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -2945,13 +2945,13 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha if (length<byte_count-1) { /* When there are any characters after the first NUL */ 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); /* format = TAG_FMT_UNDEFINED; this musn't be ASCII */ /* but we are not supposed to change this */ /* keep in mind that image_info does not store editor value */ } else { - ImageInfo->Copyright = estrdup(value_ptr); + ImageInfo->Copyright = estrndup(value_ptr, byte_count); } } break; @@ -3042,10 +3042,10 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha break; case TAG_MAKE: - ImageInfo->make = estrdup(value_ptr); + ImageInfo->make = estrndup(value_ptr, byte_count); break; case TAG_MODEL: - ImageInfo->model = estrdup(value_ptr); + ImageInfo->model = estrndup(value_ptr, byte_count); break; case TAG_MAKER_NOTE: diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 0cac3dee4c..191afddc54 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -585,44 +585,42 @@ static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned ch { mpz_ptr gmpnum; const unsigned char *p, *max; - zval zv; + zval *zv; int retval = FAILURE; php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data; - ZVAL_UNDEF(&zv); PHP_VAR_UNSERIALIZE_INIT(unserialize_data); gmp_create(object, &gmpnum); p = buf; max = buf + buf_len; - if (!php_var_unserialize(&zv, &p, max, &unserialize_data) - || Z_TYPE(zv) != IS_STRING - || convert_to_gmp(gmpnum, &zv, 10) == FAILURE + zv = var_tmp_var(&unserialize_data); + if (!php_var_unserialize(zv, &p, max, &unserialize_data) + || Z_TYPE_P(zv) != IS_STRING + || convert_to_gmp(gmpnum, zv, 10) == FAILURE ) { zend_throw_exception(NULL, "Could not unserialize number", 0); goto exit; } - zval_dtor(&zv); - ZVAL_UNDEF(&zv); - if (!php_var_unserialize(&zv, &p, max, &unserialize_data) - || Z_TYPE(zv) != IS_ARRAY + zv = var_tmp_var(&unserialize_data); + if (!php_var_unserialize(zv, &p, max, &unserialize_data) + || Z_TYPE_P(zv) != IS_ARRAY ) { zend_throw_exception(NULL, "Could not unserialize properties", 0); goto exit; } - if (zend_hash_num_elements(Z_ARRVAL(zv)) != 0) { + if (zend_hash_num_elements(Z_ARRVAL_P(zv)) != 0) { zend_hash_copy( - zend_std_get_properties(object), Z_ARRVAL(zv), + zend_std_get_properties(object), Z_ARRVAL_P(zv), (copy_ctor_func_t) zval_add_ref ); } retval = SUCCESS; exit: - zval_dtor(&zv); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); return retval; } diff --git a/ext/gmp/tests/bug70284.phpt b/ext/gmp/tests/bug70284.phpt new file mode 100644 index 0000000000..58fc50cf2d --- /dev/null +++ b/ext/gmp/tests/bug70284.phpt @@ -0,0 +1,50 @@ +--TEST-- +Bug #70284 (Use after free vulnerability in unserialize() with GMP) +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +$inner = 'r:2;a:1:{i:0;a:1:{i:0;r:4;}}'; +$exploit = 'a:2:{i:0;s:1:"1";i:1;C:3:"GMP":'.strlen($inner).':{'.$inner.'}}'; + +$data = unserialize($exploit); + +$fakezval = ptr2str(1122334455); +$fakezval .= ptr2str(0); +$fakezval .= "\x00\x00\x00\x00"; +$fakezval .= "\x01"; +$fakezval .= "\x00"; +$fakezval .= "\x00\x00"; + +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]=> + string(1) "1" + [1]=> + object(GMP)#%d (2) { + [0]=> + array(1) { + [0]=> + string(1) "1" + } + ["num"]=> + string(1) "1" + } +} diff --git a/ext/hash/hash_haval.c b/ext/hash/hash_haval.c index 321999f099..e5fc5bdf5d 100644 --- a/ext/hash/hash_haval.c +++ b/ext/hash/hash_haval.c @@ -336,7 +336,7 @@ PHP_HASH_API void PHP_HAVAL128Final(unsigned char *digest, PHP_HAVAL_CTX * conte /* 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); 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. */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3f); + index = (unsigned int) ((context->count[0] >> 3) & 0x7f); padLen = (index < 118) ? (118 - index) : (246 - index); 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. */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3f); + index = (unsigned int) ((context->count[0] >> 3) & 0x7f); padLen = (index < 118) ? (118 - index) : (246 - index); 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. */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3f); + index = (unsigned int) ((context->count[0] >> 3) & 0x7f); padLen = (index < 118) ? (118 - index) : (246 - index); 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. */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3f); + index = (unsigned int) ((context->count[0] >> 3) & 0x7f); padLen = (index < 118) ? (118 - index) : (246 - index); PHP_HAVALUpdate(context, PADDING, padLen); diff --git a/ext/hash/tests/bug70312.phpt b/ext/hash/tests/bug70312.phpt new file mode 100644 index 0000000000..5ded1ac5a5 --- /dev/null +++ b/ext/hash/tests/bug70312.phpt @@ -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"
\ No newline at end of file diff --git a/ext/hash/tests/hash_file_basic1.phpt b/ext/hash/tests/hash_file_basic1.phpt index 339d237f06..9a2bc01016 100644 --- a/ext/hash/tests/hash_file_basic1.phpt +++ b/ext/hash/tests/hash_file_basic1.phpt @@ -64,7 +64,7 @@ unlink($file); adler32: ff87222e crc32: 61664d33 gost: d9e65f0c0c2ef944e4f8a01f4a46365c4f33a2853756878182a7f03e1490a4cd -haval128,3: 8bb81269aca8b7f87829020d76a4e841 +haval128,3: c25962b13383c3ed9f13817c8f2ae7d6 md2: 70f791c0d8fa9edd7d08e32fcba8c354 md4: a9d034b16bb290c57a645afd6f14cd3b md5: 704bf818448f5bbb94061332d2c889aa diff --git a/ext/hash/tests/hash_hmac_basic.phpt b/ext/hash/tests/hash_hmac_basic.phpt index 9631aa52c0..a0a49533d5 100644 --- a/ext/hash/tests/hash_hmac_basic.phpt +++ b/ext/hash/tests/hash_hmac_basic.phpt @@ -45,7 +45,7 @@ echo "sha256(raw): " . bin2hex(hash_hmac('sha256', $content, $key, TRUE)) . "\n" adler32: 12c803f7 crc32: 96859101 gost: a4a3c80bdf3f8665bf07376a34dc9c1b11af7c813f4928f62e39f0c0dc564dad -haval128,3: 82cd0f4bd36729b5c80c33efa8c13ac5 +haval128,3: 4d1318607f0406bd1b7bd50907772672 md2: 6d111dab563025e4cb5f4425c991fa12 md4: 10cdbfe843000c623f8b8da0d5d20b0b md5: 2a632783e2812cf23de100d7d6a463ae diff --git a/ext/hash/tests/hash_hmac_file_basic.phpt b/ext/hash/tests/hash_hmac_file_basic.phpt index 858d673275..5c18fd6a2d 100644 --- a/ext/hash/tests/hash_hmac_file_basic.phpt +++ b/ext/hash/tests/hash_hmac_file_basic.phpt @@ -73,7 +73,7 @@ unlink($file); adler32: 0f8c02f9 crc32: f2a60b9c gost: 94c39a40d5db852a8dc3d24e37eebf2d53e3d711457c59cd02b614f792a9d918 -haval128,3: e8fcff647f1a675acb429130fb94a17e +haval128,3: f1cea637451097d790354a86de3f54a3 md2: a685475e600314bb549ab4f33c3b27cb md4: cbc6bff781f48f57378d3effa27553e4 md5: 8bddf39dd1c566c27acc7fa85ec36acf diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 55ca8fa70e..3ec6e625a0 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -758,7 +758,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 (subpats != NULL) { /* 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) { if (subpat_names) { efree(subpat_names); } @@ -1177,7 +1177,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su piece = subject + start_offset; /* if (EXPECTED(count > 0 && (limit == -1 || limit > 0))) */ - if (EXPECTED(count > 0 && limit)) { + if (EXPECTED(count > 0 && (offsets[1] - offsets[0] >= 0) && limit)) { if (UNEXPECTED(replace_count)) { ++*replace_count; } @@ -1799,7 +1799,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, char *subject, int subjec } /* If something matched */ - if (count > 0) { + if (count > 0 && (offsets[1] - offsets[0] >= 0)) { if (!no_empty || &subject[offsets[0]] != last_match) { if (offset_capture) { diff --git a/ext/pcre/tests/bug70345.phpt b/ext/pcre/tests/bug70345.phpt new file mode 100644 index 0000000000..0947ba3daa --- /dev/null +++ b/ext/pcre/tests/bug70345.phpt @@ -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) { +} diff --git a/ext/session/session.c b/ext/session/session.c index ef17b86bad..f2e1f7cda4 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -64,6 +64,7 @@ PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps) static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); +static void php_session_track_init(void); /* SessionHandler class */ zend_class_entry *php_session_class_entry; @@ -138,6 +139,7 @@ static inline void php_rshutdown_session_globals(void) /* {{{ */ static int php_session_destroy(void) /* {{{ */ { int retval = SUCCESS; + zend_string *var_name; if (PS(session_status) != php_session_active) { php_error_docref(NULL, E_WARNING, "Trying to destroy uninitialized session"); @@ -235,6 +237,7 @@ static int php_session_decode(zend_string *data) /* {{{ */ } if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) { php_session_destroy(); + php_session_track_init(); php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed"); return FAILURE; } @@ -952,6 +955,8 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ var_replace(&var_hash, ¤t, zv); } else { zval_ptr_dtor(¤t); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return FAILURE; } } PS_ADD_VARL(name); @@ -1042,6 +1047,8 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ var_replace(&var_hash, ¤t, zv); } else { zval_ptr_dtor(¤t); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return FAILURE; } } PS_ADD_VARL(name); @@ -2169,8 +2176,7 @@ static PHP_FUNCTION(session_decode) } if (php_session_decode(str) == FAILURE) { - /* FIXME: session_decode() should return FALSE */ - /* RETURN_FALSE; */ + RETURN_FALSE; } RETURN_TRUE; } diff --git a/ext/session/tests/session_decode_error2.phpt b/ext/session/tests/session_decode_error2.phpt index 4160f87855..30be58765f 100644 --- a/ext/session/tests/session_decode_error2.phpt +++ b/ext/session/tests/session_decode_error2.phpt @@ -18,6 +18,7 @@ $data = "foo|a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}guff|R:1;blah|R:1;"; var_dump(session_start()); for($index = 0; $index < strlen($data); $index++) { + if(session_status() != PHP_SESSION_ACTIVE) { session_start(); } echo "\n-- Iteration $index --\n"; $encoded = substr($data, 0, $index); var_dump(session_decode($encoded)); @@ -53,213 +54,213 @@ array(0) { } -- Iteration 4 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 5 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 6 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 7 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 8 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 9 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 10 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 11 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 12 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 13 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 14 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 15 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 16 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 17 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 18 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 19 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 20 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 21 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 22 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 23 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 24 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 25 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 26 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 27 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 28 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 29 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 30 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 31 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 32 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 33 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 34 -- @@ -333,67 +334,31 @@ array(1) { } -- Iteration 39 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 40 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 41 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 42 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 43 -- @@ -512,104 +477,33 @@ array(2) { } -- Iteration 48 -- -bool(true) -array(3) { - ["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 + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 49 -- -bool(true) -array(3) { - ["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 + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 50 -- -bool(true) -array(3) { - ["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 + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 51 -- -bool(true) -array(3) { - ["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 + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -bool(true) -Done +Warning: session_destroy(): Trying to destroy uninitialized session in %s/session_decode_error2.php on line %d +bool(false) +Done diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 3c4a86c01e..d2b1d30ddf 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -1505,7 +1505,7 @@ static void _soap_server_exception(soapServicePtr service, sdlFunctionPtr functi add_soap_fault_ex(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL); } soap_server_fault_ex(function, &exception_object, NULL); - } + } } /* }}} */ @@ -2924,8 +2924,10 @@ PHP_METHOD(SoapClient, __call) free_soap_headers = 1; } ZEND_HASH_FOREACH_VAL(default_headers, tmp) { - Z_ADDREF_P(tmp); - zend_hash_next_index_insert(soap_headers, tmp); + if(Z_TYPE_P(tmp) == IS_OBJECT) { + Z_ADDREF_P(tmp); + zend_hash_next_index_insert(soap_headers, tmp); + } } ZEND_HASH_FOREACH_END(); } else { soap_headers = Z_ARRVAL_P(tmp); @@ -4332,9 +4334,14 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function zval* header; ZEND_HASH_FOREACH_VAL(soap_headers, header) { - HashTable *ht = Z_OBJPROP_P(header); + HashTable *ht; zval *name, *ns, *tmp; + if (Z_TYPE_P(header) != IS_OBJECT) { + continue; + } + + ht = Z_OBJPROP_P(header); if ((name = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL && Z_TYPE_P(name) == IS_STRING && (ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL && diff --git a/ext/soap/tests/bug70388.phpt b/ext/soap/tests/bug70388.phpt new file mode 100644 index 0000000000..49a8efc0ff --- /dev/null +++ b/ext/soap/tests/bug70388.phpt @@ -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"
\ No newline at end of file diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 210bcdff6e..d7976f3b2c 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -1210,6 +1210,7 @@ SPL_METHOD(SplDoublyLinkedList, unserialize) if (!php_var_unserialize(elem, &p, s + buf_len, &var_hash)) { goto error; } + var_push_dtor(&var_hash, elem); spl_ptr_llist_push(intern->llist, elem); } diff --git a/ext/spl/tests/bug70155.phpt b/ext/spl/tests/bug70155.phpt new file mode 100644 index 0000000000..1730a1a587 --- /dev/null +++ b/ext/spl/tests/bug70155.phpt @@ -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=== diff --git a/ext/spl/tests/bug70365.phpt b/ext/spl/tests/bug70365.phpt new file mode 100644 index 0000000000..c18110e3ca --- /dev/null +++ b/ext/spl/tests/bug70365.phpt @@ -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" +} diff --git a/ext/spl/tests/bug70366.phpt b/ext/spl/tests/bug70366.phpt new file mode 100644 index 0000000000..c9aa584ae2 --- /dev/null +++ b/ext/spl/tests/bug70366.phpt @@ -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" +}
\ No newline at end of file diff --git a/ext/standard/tests/serialize/bug70172.phpt b/ext/standard/tests/serialize/bug70172.phpt new file mode 100644 index 0000000000..0a4aa4be16 --- /dev/null +++ b/ext/standard/tests/serialize/bug70172.phpt @@ -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) + } +}
\ No newline at end of file diff --git a/ext/standard/tests/serialize/bug70172_2.phpt b/ext/standard/tests/serialize/bug70172_2.phpt new file mode 100644 index 0000000000..1fc97a980e --- /dev/null +++ b/ext/standard/tests/serialize/bug70172_2.phpt @@ -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) + } + } + } +}
\ No newline at end of file diff --git a/ext/standard/tests/serialize/bug70219.phpt b/ext/standard/tests/serialize/bug70219.phpt new file mode 100644 index 0000000000..da2a0f2206 --- /dev/null +++ b/ext/standard/tests/serialize/bug70219.phpt @@ -0,0 +1,40 @@ +--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(1) { + ["data"]=> + NULL + } +} diff --git a/ext/standard/var.c b/ext/standard/var.c index 40b5acb041..8b0f8893c5 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1045,6 +1045,7 @@ PHP_FUNCTION(unserialize) php_unserialize_data_t var_hash; zval *options = NULL, *classes = NULL; HashTable *class_hash = NULL; + zval *old_rval = return_value; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &options) == FAILURE) { RETURN_FALSE; diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 046db564ac..43e82d2ded 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.7.5 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -103,9 +103,15 @@ PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx) #if 0 PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rval) { - var_dtor_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 - 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 if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { @@ -183,6 +189,9 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) while (var_dtor_hash) { for (i = 0; i < var_dtor_hash->used_slots; i++) { +#if VAR_ENTRIES_DBG + fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i])); +#endif zval_ptr_dtor(&var_dtor_hash->data[i]); } next = var_dtor_hash->next; @@ -263,7 +272,7 @@ static inline int unserialize_allowed_class(zend_string *class_name, HashTable * #define YYMARKER marker -#line 271 "ext/standard/var_unserializer.re" +#line 280 "ext/standard/var_unserializer.re" @@ -530,7 +539,7 @@ PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) start = cursor; -#line 534 "ext/standard/var_unserializer.c" +#line 543 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -590,9 +599,9 @@ yy2: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 881 "ext/standard/var_unserializer.re" +#line 893 "ext/standard/var_unserializer.re" { return 0; } -#line 596 "ext/standard/var_unserializer.c" +#line 605 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -635,13 +644,13 @@ yy13: goto yy3; yy14: ++YYCURSOR; -#line 875 "ext/standard/var_unserializer.re" +#line 887 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 645 "ext/standard/var_unserializer.c" +#line 654 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -667,11 +676,12 @@ yy20: if (yybm[0+yych] & 128) { goto yy20; } - if (yych != ':') goto yy18; + if (yych <= '/') goto yy18; + if (yych >= ';') goto yy18; yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 730 "ext/standard/var_unserializer.re" +#line 741 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; zend_long elements; @@ -686,6 +696,7 @@ yy20: zval retval; zval args[1]; + if (!var_hash) return 0; if (*start == 'C') { custom_object = 1; } @@ -816,7 +827,7 @@ yy20: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 820 "ext/standard/var_unserializer.c" +#line 831 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -841,15 +852,16 @@ yy27: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 722 "ext/standard/var_unserializer.re" +#line 732 "ext/standard/var_unserializer.re" { + if (!var_hash) return 0; //??? INIT_PZVAL(rval); return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 853 "ext/standard/var_unserializer.c" +#line 865 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -870,11 +882,12 @@ yy34: yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 701 "ext/standard/var_unserializer.re" +#line 710 "ext/standard/var_unserializer.re" { zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ *p = YYCURSOR; + if (!var_hash) return 0; if (elements < 0) { return 0; @@ -891,7 +904,7 @@ yy34: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 895 "ext/standard/var_unserializer.c" +#line 908 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -912,7 +925,7 @@ yy41: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 673 "ext/standard/var_unserializer.re" +#line 682 "ext/standard/var_unserializer.re" { size_t len, maxlen; zend_string *str; @@ -940,7 +953,7 @@ yy41: ZVAL_STR(rval, str); return 1; } -#line 944 "ext/standard/var_unserializer.c" +#line 957 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -961,7 +974,7 @@ yy48: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 646 "ext/standard/var_unserializer.re" +#line 655 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -988,7 +1001,7 @@ yy48: ZVAL_STRINGL(rval, str, len); return 1; } -#line 992 "ext/standard/var_unserializer.c" +#line 1005 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1076,7 +1089,7 @@ yy61: } yy63: ++YYCURSOR; -#line 637 "ext/standard/var_unserializer.re" +#line 646 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 use_double: @@ -1085,7 +1098,7 @@ use_double: ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1089 "ext/standard/var_unserializer.c" +#line 1102 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1144,7 +1157,7 @@ yy73: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 621 "ext/standard/var_unserializer.re" +#line 630 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1160,7 +1173,7 @@ yy73: return 1; } -#line 1164 "ext/standard/var_unserializer.c" +#line 1177 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1187,7 +1200,7 @@ yy79: if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 595 "ext/standard/var_unserializer.re" +#line 604 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1213,7 +1226,7 @@ yy79: ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1217 "ext/standard/var_unserializer.c" +#line 1230 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1221,22 +1234,22 @@ yy83: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 589 "ext/standard/var_unserializer.re" +#line 598 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1231 "ext/standard/var_unserializer.c" +#line 1244 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 583 "ext/standard/var_unserializer.re" +#line 592 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 1240 "ext/standard/var_unserializer.c" +#line 1253 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1259,7 +1272,7 @@ yy91: if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 560 "ext/standard/var_unserializer.re" +#line 569 "ext/standard/var_unserializer.re" { zend_long id; @@ -1282,7 +1295,7 @@ yy91: return 1; } -#line 1286 "ext/standard/var_unserializer.c" +#line 1299 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1305,7 +1318,7 @@ yy97: if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 538 "ext/standard/var_unserializer.re" +#line 547 "ext/standard/var_unserializer.re" { zend_long id; @@ -1327,9 +1340,9 @@ yy97: return 1; } -#line 1331 "ext/standard/var_unserializer.c" +#line 1344 "ext/standard/var_unserializer.c" } -#line 883 "ext/standard/var_unserializer.re" +#line 895 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index be6a12f630..35c46c0f75 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -101,9 +101,15 @@ PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx) #if 0 PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rval) { - var_dtor_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 - 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 if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { @@ -181,6 +187,9 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) while (var_dtor_hash) { for (i = 0; i < var_dtor_hash->used_slots; i++) { +#if VAR_ENTRIES_DBG + fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i])); +#endif zval_ptr_dtor(&var_dtor_hash->data[i]); } next = var_dtor_hash->next; @@ -702,6 +711,7 @@ use_double: zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ *p = YYCURSOR; + if (!var_hash) return 0; if (elements < 0) { return 0; @@ -720,6 +730,7 @@ use_double: } "o:" iv ":" ["] { + if (!var_hash) return 0; //??? INIT_PZVAL(rval); @@ -741,6 +752,7 @@ object ":" uiv ":" ["] { zval retval; zval args[1]; + if (!var_hash) return 0; if (*start == 'C') { custom_object = 1; } diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 51102fbc34..ee52336c4e 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -218,7 +218,9 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t if (error == 1) { for (i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); - xmlXPathFreeObject(obj); + if (obj) { + xmlXPathFreeObject(obj); + } } return; } diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index dd2414dce2..a723a187db 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -171,7 +171,7 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil /* it is a directory only, see #40228 */ 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; } else { memcpy(file_dirname, path_cleaned, path_cleaned_len); diff --git a/ext/zip/tests/bug70350.phpt b/ext/zip/tests/bug70350.phpt new file mode 100644 index 0000000000..d81de65a32 --- /dev/null +++ b/ext/zip/tests/bug70350.phpt @@ -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) |