Skip to content

Commit

Permalink
Fix #49649 - Handle property visibility changes on unserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
pmmaga authored and krakjoe committed Jul 10, 2017
1 parent cfacf84 commit 7cb5bdf
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 7 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ PHP NEWS
. Fixed bug #74819 (wddx_deserialize() heap out-of-bound read via
php_parse_date()). (Derick)
. Fixed bug #74878 (Data race in ZTS builds). (Nikita)
. Fixed bug #49649 (unserialize() doesn't handle changes in property
visibility). (pmmaga)

- Date:
. Fixed bug #74852 (property_exists returns true on unknown DateInterval
Expand Down
45 changes: 45 additions & 0 deletions ext/standard/tests/serialize/bug49649.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
--TEST--
Bug #49649 (unserialize() doesn't handle changes in property visibility) - to public
--FILE--
<?php

/**
*class Foo
*{
* private $private = 1;
*
* protected $protected = 2;
*
* public $public = 3;
*
* public $notThere = 'old';
* }
*
* echo base64_encode(serialize(new Foo()));
*
* The class above represents the serialized, base64_encoded string below.
*/
$serialized = 'TzozOiJGb28iOjQ6e3M6MTI6IgBGb28AcHJpdmF0ZSI7aToxO3M6MTI6IgAqAHByb3RlY3RlZCI7aToyO3M6NjoicHVibGljIjtpOjM7czo4OiJub3RUaGVyZSI7czozOiJvbGQiO30';

class Foo
{
public $public = null;

public $protected = null;

public $private = null;
}

$class = unserialize(base64_decode($serialized));
var_dump($class);
--EXPECT--
object(Foo)#1 (4) {
["public"]=>
int(3)
["protected"]=>
int(2)
["private"]=>
int(1)
["notThere"]=>
string(3) "old"
}
45 changes: 45 additions & 0 deletions ext/standard/tests/serialize/bug49649_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
--TEST--
Bug #49649 (unserialize() doesn't handle changes in property visibility) - to protected
--FILE--
<?php

/**
*class Foo
*{
* private $private = 1;
*
* protected $protected = 2;
*
* public $public = 3;
*
* public $notThere = 'old';
* }
*
* echo base64_encode(serialize(new Foo()));
*
* The class above represents the serialized, base64_encoded string below.
*/
$serialized = 'TzozOiJGb28iOjQ6e3M6MTI6IgBGb28AcHJpdmF0ZSI7aToxO3M6MTI6IgAqAHByb3RlY3RlZCI7aToyO3M6NjoicHVibGljIjtpOjM7czo4OiJub3RUaGVyZSI7czozOiJvbGQiO30';

class Foo
{
protected $public = null;

protected $protected = null;

protected $private = null;
}

$class = unserialize(base64_decode($serialized));
var_dump($class);
--EXPECT--
object(Foo)#1 (4) {
["public":protected]=>
int(3)
["protected":protected]=>
int(2)
["private":protected]=>
int(1)
["notThere"]=>
string(3) "old"
}
45 changes: 45 additions & 0 deletions ext/standard/tests/serialize/bug49649_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
--TEST--
Bug #49649 (unserialize() doesn't handle changes in property visibility) - to private
--FILE--
<?php

/**
*class Foo
*{
* private $private = 1;
*
* protected $protected = 2;
*
* public $public = 3;
*
* public $notThere = 'old';
* }
*
* echo base64_encode(serialize(new Foo()));
*
* The class above represents the serialized, base64_encoded string below.
*/
$serialized = 'TzozOiJGb28iOjQ6e3M6MTI6IgBGb28AcHJpdmF0ZSI7aToxO3M6MTI6IgAqAHByb3RlY3RlZCI7aToyO3M6NjoicHVibGljIjtpOjM7czo4OiJub3RUaGVyZSI7czozOiJvbGQiO30';

class Foo
{
private $public = null;

private $protected = null;

private $private = null;
}

$class = unserialize(base64_decode($serialized));
var_dump($class);
--EXPECT--
object(Foo)#1 (4) {
["public":"Foo":private]=>
int(3)
["protected":"Foo":private]=>
int(2)
["private":"Foo":private]=>
int(1)
["notThere"]=>
string(3) "old"
}
58 changes: 51 additions & 7 deletions ext/standard/var_unserializer.re
Original file line number Diff line number Diff line change
Expand Up @@ -427,14 +427,58 @@ numeric_key:
} else {
if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
string_key:
if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
if (Z_TYPE_P(old_data) == IS_INDIRECT) {
old_data = Z_INDIRECT_P(old_data);
{
zend_property_info *existing_propinfo;
zend_string *new_key, *unmangled;
const char *unmangled_class = NULL;
const char *unmangled_prop;
size_t unmangled_prop_len;

if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
zval_dtor(&key);
return 0;
}

unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0);
if (Z_TYPE_P(rval) == IS_OBJECT
&& ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL)
&& (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) {
if (existing_propinfo->flags & ZEND_ACC_PROTECTED) {
new_key = zend_mangle_property_name(
"*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS);
zend_string_release(unmangled);
} else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) {
if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) {
new_key = zend_mangle_property_name(
unmangled_class, strlen(unmangled_class),
ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS);
} else {
new_key = zend_mangle_property_name(
ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name),
ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS);
}
zend_string_release(unmangled);
} else {
ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC);
new_key = unmangled;
}
zend_string_release(Z_STR(key));
Z_STR(key) = new_key;
} else {
zend_string_release(unmangled);
}

if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
if (Z_TYPE_P(old_data) == IS_INDIRECT) {
old_data = Z_INDIRECT_P(old_data);
}
var_push_dtor(var_hash, old_data);
data = zend_hash_update_ind(ht, Z_STR(key), &d);
} else {
data = zend_hash_add_new(ht, Z_STR(key), &d);
}
var_push_dtor(var_hash, old_data);
data = zend_hash_update_ind(ht, Z_STR(key), &d);
} else {
data = zend_hash_add_new(ht, Z_STR(key), &d);
}
} else if (Z_TYPE(key) == IS_LONG) {
/* object properties should include no integers */
Expand Down

0 comments on commit 7cb5bdf

Please sign in to comment.