Skip to content
Permalink
Browse files Browse the repository at this point in the history
Fix bug #73331 - do not try to serialize/unserialize objects wddx can…
… not handle

Proper soltion would be to call serialize/unserialize and deal with the result,
but this requires more work that should be done by wddx maintainer (not me).
  • Loading branch information
smalyshev committed Oct 24, 2016
1 parent 6558559 commit 6045de6
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 34 deletions.
1 change: 1 addition & 0 deletions ext/pdo/pdo_stmt.c
Expand Up @@ -2338,6 +2338,7 @@ void pdo_stmt_init(TSRMLS_D)
pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
pdo_row_ce->create_object = pdo_row_new;
pdo_row_ce->serialize = pdo_row_serialize;
pdo_row_ce->unserialize = zend_class_unserialize_deny;
}

static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
Expand Down
4 changes: 3 additions & 1 deletion ext/wddx/tests/bug45901.phpt
Expand Up @@ -14,5 +14,7 @@ echo wddx_serialize_value($xml, 'Variables') . "\n";
echo "DONE";
?>
--EXPECTF--
<wddxPacket version='1.0'><header><comment>Variables</comment></header><data><struct><var name='php_class_name'><string>SimpleXMLElement</string></var><var name='test'><struct><var name='php_class_name'><string>SimpleXMLElement</string></var></struct></var></struct></data></wddxPacket>

Warning: wddx_serialize_value(): Class SimpleXMLElement can not be serialized in %sbug45901.php on line %d
<wddxPacket version='1.0'><header><comment>Variables</comment></header><data></data></wddxPacket>
DONE
2 changes: 1 addition & 1 deletion ext/wddx/tests/bug72790.phpt
@@ -1,5 +1,5 @@
--TEST--
Bug 72790: wddx_deserialize null dereference with invalid xml
Bug #72790: wddx_deserialize null dereference with invalid xml
--SKIPIF--
<?php
if (!extension_loaded('wddx')) {
Expand Down
15 changes: 15 additions & 0 deletions ext/wddx/tests/bug73331.phpt
@@ -0,0 +1,15 @@
--TEST--
Bug #73331 (NULL Pointer Dereference in WDDX Packet Deserialization with PDORow)
--SKIPIF--
<?php if (!extension_loaded("wddx") || !extension_loaded("pdo")) print "skip"; ?>
--FILE--
<?php

$wddx = "<wddxPacket version='1.0'><header/><data><struct><var name='php_class_name'><string>PDORow</string></var></struct></data></wddxPacket>";
var_dump(wddx_deserialize($wddx));
?>
--EXPECTF--

Warning: wddx_deserialize(): Class pdorow can not be unserialized in %s73331.php on line %d
NULL

67 changes: 35 additions & 32 deletions ext/wddx/wddx.c
Expand Up @@ -471,21 +471,26 @@ static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
ulong idx;
char tmp_buf[WDDX_BUF_LEN];
HashTable *objhash, *sleephash;
zend_class_entry *ce;
PHP_CLASS_ATTRIBUTES;
TSRMLS_FETCH();

PHP_SET_CLASS_ATTRIBUTES(obj);
ce = Z_OBJCE_P(obj);
if (!ce || ce->serialize || ce->unserialize) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s can not be serialized", class_name);
PHP_CLEANUP_CLASS_ATTRIBUTES();
return;
}

MAKE_STD_ZVAL(fname);
ZVAL_STRING(fname, "__sleep", 1);

/*
* We try to call __sleep() method on object. It's supposed to return an
* array of property names to be serialized.
*/
if (call_user_function_ex(CG(function_table), &obj, fname, &retval, 0, 0, 1, NULL TSRMLS_CC) == SUCCESS) {
if (retval && (sleephash = HASH_OF(retval))) {
PHP_CLASS_ATTRIBUTES;

PHP_SET_CLASS_ATTRIBUTES(obj);

php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
php_wddx_add_chunk(packet, tmp_buf);
Expand All @@ -494,8 +499,6 @@ static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
php_wddx_add_chunk_static(packet, WDDX_STRING_E);
php_wddx_add_chunk_static(packet, WDDX_VAR_E);

PHP_CLEANUP_CLASS_ATTRIBUTES();

objhash = HASH_OF(obj);

for (zend_hash_internal_pointer_reset(sleephash);
Expand All @@ -516,10 +519,6 @@ static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
} else {
uint key_len;

PHP_CLASS_ATTRIBUTES;

PHP_SET_CLASS_ATTRIBUTES(obj);

php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
php_wddx_add_chunk(packet, tmp_buf);
Expand All @@ -528,8 +527,6 @@ static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
php_wddx_add_chunk_static(packet, WDDX_STRING_E);
php_wddx_add_chunk_static(packet, WDDX_VAR_E);

PHP_CLEANUP_CLASS_ATTRIBUTES();

objhash = HASH_OF(obj);
for (zend_hash_internal_pointer_reset(objhash);
zend_hash_get_current_data(objhash, (void**)&ent) == SUCCESS;
Expand All @@ -551,6 +548,8 @@ static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
}

PHP_CLEANUP_CLASS_ATTRIBUTES();

zval_dtor(fname);
FREE_ZVAL(fname);

Expand Down Expand Up @@ -1012,26 +1011,30 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
pce = &PHP_IC_ENTRY;
}

/* Initialize target object */
MAKE_STD_ZVAL(obj);
object_init_ex(obj, *pce);

/* Merge current hashtable with object's default properties */
zend_hash_merge(Z_OBJPROP_P(obj),
Z_ARRVAL_P(ent2->data),
(void (*)(void *)) zval_add_ref,
(void *) &tmp, sizeof(zval *), 0);

if (incomplete_class) {
php_store_class_name(obj, Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
if (pce != &PHP_IC_ENTRY && ((*pce)->serialize || (*pce)->unserialize)) {
ent2->data = NULL;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s can not be unserialized", Z_STRVAL_P(ent1->data));
} else {
/* Initialize target object */
MAKE_STD_ZVAL(obj);
object_init_ex(obj, *pce);

/* Merge current hashtable with object's default properties */
zend_hash_merge(Z_OBJPROP_P(obj),
Z_ARRVAL_P(ent2->data),
(void (*)(void *)) zval_add_ref,
(void *) &tmp, sizeof(zval *), 0);

if (incomplete_class) {
php_store_class_name(obj, Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
}

/* Clean up old array entry */
zval_ptr_dtor(&ent2->data);

/* Set stack entry to point to the newly created object */
ent2->data = obj;
}

/* Clean up old array entry */
zval_ptr_dtor(&ent2->data);

/* Set stack entry to point to the newly created object */
ent2->data = obj;

/* Clean up class name var entry */
zval_ptr_dtor(&ent1->data);
} else if (Z_TYPE_P(ent2->data) == IS_OBJECT) {
Expand Down

0 comments on commit 6045de6

Please sign in to comment.