Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

secured unserialize #908

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ext/standard/php_var.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t
PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC);
PHPAPI int php_var_unserialize_ref(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC);
PHPAPI int php_var_unserialize_intern(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC);
PHPAPI int php_var_unserialize_ex(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes TSRMLS_DC);

#define PHP_VAR_SERIALIZE_INIT(d) \
do { \
Expand Down
6 changes: 3 additions & 3 deletions ext/standard/tests/serialize/serialization_error_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var_dump( unserialize() );

//Test serialize with one more than the expected number of arguments
var_dump( serialize(1,2) );
var_dump( unserialize(1,2) );
var_dump( unserialize(1,2,3) );

echo "Done";
?>
Expand All @@ -31,12 +31,12 @@ echo "Done";
Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16
NULL

Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17
Warning: unserialize() expects at least 1 parameter, 0 given in %s on line 17
bool(false)

Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20
NULL

Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21
Warning: unserialize() expects at most 2 parameters, 3 given in %s on line 21
bool(false)
Done
88 changes: 88 additions & 0 deletions ext/standard/tests/serialize/unserialize_classes.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
--TEST--
Test unserialize() with second parameter
--FILE--
<?php
class foo {
public $x = "bar";
}
$z = array(new foo(), 2, "3");
$s = serialize($z);

var_dump(unserialize($s));
var_dump(unserialize($s, ["allowed_classes" => false]));
var_dump(unserialize($s, ["allowed_classes" => true]));
var_dump(unserialize($s, ["allowed_classes" => ["bar"]]));
var_dump(unserialize($s, ["allowed_classes" => ["FOO"]]));
var_dump(unserialize($s, ["allowed_classes" => ["bar", "foO"]]));

--EXPECTF--
array(3) {
[0]=>
object(foo)#%d (1) {
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
array(3) {
[0]=>
object(__PHP_Incomplete_Class)#%d (2) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "foo"
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
array(3) {
[0]=>
object(foo)#%d (1) {
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
array(3) {
[0]=>
object(__PHP_Incomplete_Class)#%d (2) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "foo"
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
array(3) {
[0]=>
object(foo)#%d (1) {
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
array(3) {
[0]=>
object(foo)#%d (1) {
["x"]=>
string(3) "bar"
}
[1]=>
int(2)
[2]=>
string(1) "3"
}
36 changes: 33 additions & 3 deletions ext/standard/var.c
Original file line number Diff line number Diff line change
Expand Up @@ -990,16 +990,18 @@ PHP_FUNCTION(serialize)
}
/* }}} */

/* {{{ proto mixed unserialize(string variable_representation)
/* {{{ proto mixed unserialize(string variable_representation[, bool|array allowed_classes])
Takes a string representation of variable and recreates it */
PHP_FUNCTION(unserialize)
{
char *buf = NULL;
size_t buf_len;
const unsigned char *p;
php_unserialize_data_t var_hash;
zval *options = NULL, *classes = NULL;
HashTable *class_hash = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &buf, &buf_len, &options) == FAILURE) {
RETURN_FALSE;
}

Expand All @@ -1009,15 +1011,43 @@ PHP_FUNCTION(unserialize)

p = (const unsigned char*) buf;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
if (!php_var_unserialize(return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) {
if(options != NULL) {
classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1);
if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes TSRMLS_CC))) {
ALLOC_HASHTABLE(class_hash);
zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0);
}
if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) {
zval *entry;
zend_string *lcname;

ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) {
convert_to_string_ex(entry);
lcname = zend_string_alloc(Z_STRLEN_P(entry), 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(entry), Z_STRLEN_P(entry));
zend_hash_add_empty_element(class_hash, lcname);
zend_string_release(lcname);
} ZEND_HASH_FOREACH_END();
}
}

if (!php_var_unserialize_ex(return_value, &p, p + buf_len, &var_hash, class_hash TSRMLS_CC)) {
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if(class_hash) {
zend_hash_destroy(class_hash);
FREE_HASHTABLE(class_hash);
}
zval_dtor(return_value);
if (!EG(exception)) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %d bytes", (zend_long)((char*)p - buf), buf_len);
}
RETURN_FALSE;
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if(class_hash) {
zend_hash_destroy(class_hash);
FREE_HASHTABLE(class_hash);
}
}
/* }}} */

Expand Down
Loading