Skip to content

Commit 747d21c

Browse files
committed
Fix bug #72785 - allowed_classes only applies to outermost unserialize()
1 parent 1928cdc commit 747d21c

File tree

6 files changed

+103
-98
lines changed

6 files changed

+103
-98
lines changed

ext/standard/php_var.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t
4545
PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash);
4646
PHPAPI int php_var_unserialize_ref(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash);
4747
PHPAPI int php_var_unserialize_intern(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash);
48-
PHPAPI int php_var_unserialize_ex(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes);
4948

5049
PHPAPI php_serialize_data_t php_var_serialize_init(void);
5150
PHPAPI void php_var_serialize_destroy(php_serialize_data_t d);
5251
PHPAPI php_unserialize_data_t php_var_unserialize_init(void);
5352
PHPAPI void php_var_unserialize_destroy(php_unserialize_data_t d);
53+
PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes);
5454

5555
#define PHP_VAR_SERIALIZE_INIT(d) \
5656
(d) = php_var_serialize_init()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Bug #72785: allowed_classes only applies to outermost unserialize()
3+
--FILE--
4+
<?php
5+
6+
// Forbidden class
7+
class A {}
8+
9+
$p = 'x:i:0;a:1:{i:0;O:1:"A":0:{}};m:a:0:{}';
10+
$s = 'C:11:"ArrayObject":' . strlen($p) . ':{' . $p . '}';
11+
var_dump(unserialize($s, ['allowed_classes' => ['ArrayObject']]));
12+
13+
?>
14+
--EXPECT--
15+
object(ArrayObject)#1 (1) {
16+
["storage":"ArrayObject":private]=>
17+
array(1) {
18+
[0]=>
19+
object(__PHP_Incomplete_Class)#2 (1) {
20+
["__PHP_Incomplete_Class_Name"]=>
21+
string(1) "A"
22+
}
23+
}
24+
}

ext/standard/tests/serialize/unserialize_error_001.phpt

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,11 @@ var_dump(unserialize($s, ["allowed_classes" => 0]));
1313
var_dump(unserialize($s, ["allowed_classes" => 1]));
1414

1515
--EXPECTF--
16-
array(3) {
17-
[0]=>
18-
object(__PHP_Incomplete_Class)#%d (2) {
19-
["__PHP_Incomplete_Class_Name"]=>
20-
string(3) "foo"
21-
["x"]=>
22-
string(3) "bar"
23-
}
24-
[1]=>
25-
int(2)
26-
[2]=>
27-
string(1) "3"
28-
}
29-
array(3) {
30-
[0]=>
31-
object(__PHP_Incomplete_Class)#%d (2) {
32-
["__PHP_Incomplete_Class_Name"]=>
33-
string(3) "foo"
34-
["x"]=>
35-
string(3) "bar"
36-
}
37-
[1]=>
38-
int(2)
39-
[2]=>
40-
string(1) "3"
41-
}
42-
array(3) {
43-
[0]=>
44-
object(foo)#%d (1) {
45-
["x"]=>
46-
string(3) "bar"
47-
}
48-
[1]=>
49-
int(2)
50-
[2]=>
51-
string(1) "3"
52-
}
16+
Warning: unserialize(): allowed_classes option should be array or boolean in %s on line %d
17+
bool(false)
18+
19+
Warning: unserialize(): allowed_classes option should be array or boolean in %s on line %d
20+
bool(false)
21+
22+
Warning: unserialize(): allowed_classes option should be array or boolean in %s on line %d
23+
bool(false)

ext/standard/var.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,12 @@ PHP_FUNCTION(unserialize)
10791079
PHP_VAR_UNSERIALIZE_INIT(var_hash);
10801080
if(options != NULL) {
10811081
classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1);
1082+
if (classes && Z_TYPE_P(classes) != IS_ARRAY && Z_TYPE_P(classes) != IS_TRUE && Z_TYPE_P(classes) != IS_FALSE) {
1083+
php_error_docref(NULL, E_WARNING, "allowed_classes option should be array or boolean");
1084+
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1085+
RETURN_FALSE;
1086+
}
1087+
10821088
if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes))) {
10831089
ALLOC_HASHTABLE(class_hash);
10841090
zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0);
@@ -1094,9 +1100,10 @@ PHP_FUNCTION(unserialize)
10941100
zend_string_release(lcname);
10951101
} ZEND_HASH_FOREACH_END();
10961102
}
1103+
php_var_unserialize_set_allowed_classes(var_hash, class_hash);
10971104
}
10981105

1099-
if (!php_var_unserialize_ex(return_value, &p, p + buf_len, &var_hash, class_hash)) {
1106+
if (!php_var_unserialize(return_value, &p, p + buf_len, &var_hash)) {
11001107
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
11011108
if (class_hash) {
11021109
zend_hash_destroy(class_hash);

0 commit comments

Comments
 (0)