Skip to content

Commit 115ee49

Browse files
committed
Fix #77177: Serializing or unserializing COM objects crashes
Firstly, we avoid returning NULL from the get_property handler, but instead return an empty HashTable, which already prevents the crashes. Secondly, since (de-)serialization obviously makes no sense for COM, DOTNET and VARIANT objects (at least with the current implementation), we prohibit it right away.
1 parent f2de4d1 commit 115ee49

File tree

5 files changed

+74
-1
lines changed

5 files changed

+74
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ PHP NEWS
66
. Fixed bug #71041 (zend_signal_startup() needs ZEND_API).
77
(Valentin V. Bartenev)
88

9+
- COM:
10+
. Fixed bug #77177 (Serializing or unserializing COM objects crashes). (cmb)
11+
912
- Sockets:
1013
. Fixed bug #77136 (Unsupported IPV6_RECVPKTINFO constants on macOS).
1114
(Mizunashi Mana)

ext/com_dotnet/com_extension.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "php_com_dotnet.h"
3131
#include "php_com_dotnet_internal.h"
3232
#include "Zend/zend_exceptions.h"
33+
#include "Zend/zend_interfaces.h"
3334

3435
ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
3536
static PHP_GINIT_FUNCTION(com_dotnet);
@@ -354,6 +355,8 @@ PHP_MINIT_FUNCTION(com_dotnet)
354355
{
355356
zend_class_entry ce, *tmp;
356357

358+
zend_hash_init(&com_dotnet_object_properties, 0, NULL, NULL, 0);
359+
357360
php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
358361
php_com_persist_minit(INIT_FUNC_ARGS_PASSTHRU);
359362

@@ -372,11 +375,15 @@ PHP_MINIT_FUNCTION(com_dotnet)
372375
ce.create_object = php_com_object_new;
373376
php_com_variant_class_entry = zend_register_internal_class(&ce);
374377
php_com_variant_class_entry->get_iterator = php_com_iter_get;
378+
php_com_variant_class_entry->serialize = zend_class_serialize_deny;
379+
php_com_variant_class_entry->unserialize = zend_class_unserialize_deny;
375380

376381
INIT_CLASS_ENTRY(ce, "com", NULL);
377382
ce.create_object = php_com_object_new;
378383
tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
379384
tmp->get_iterator = php_com_iter_get;
385+
tmp->serialize = zend_class_serialize_deny;
386+
tmp->unserialize = zend_class_unserialize_deny;
380387

381388
zend_ts_hash_init(&php_com_typelibraries, 0, NULL, php_com_typelibrary_dtor, 1);
382389

@@ -385,6 +392,8 @@ PHP_MINIT_FUNCTION(com_dotnet)
385392
ce.create_object = php_com_object_new;
386393
tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
387394
tmp->get_iterator = php_com_iter_get;
395+
tmp->serialize = zend_class_serialize_deny;
396+
tmp->unserialize = zend_class_unserialize_deny;
388397
#endif
389398

390399
REGISTER_INI_ENTRIES();

ext/com_dotnet/com_handlers.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "php_com_dotnet_internal.h"
3030
#include "Zend/zend_exceptions.h"
3131

32+
const HashTable com_dotnet_object_properties;
33+
3234
static zval *com_property_read(zval *object, zval *member, int type, void **cahce_slot, zval *rv)
3335
{
3436
php_com_dotnet_object *obj;
@@ -231,7 +233,7 @@ static HashTable *com_properties_get(zval *object)
231233
* infinite recursion when the hash is displayed via var_dump().
232234
* Perhaps it is best to leave it un-implemented.
233235
*/
234-
return NULL;
236+
return &com_dotnet_object_properties;
235237
}
236238

237239
static void function_dtor(zval *zv)

ext/com_dotnet/php_com_dotnet_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
#include "zend_ts_hash.h"
3333

34+
extern const HashTable com_dotnet_object_properties;
35+
3436
typedef struct _php_com_dotnet_object {
3537
zend_object zo;
3638

ext/com_dotnet/tests/bug77177.phpt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
Bug #77177 (Serializing or unserializing COM objects crashes)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('com_dotnet')) die('skip com_dotnet extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
$com = new COM("WScript.Shell");
10+
$dotnet = new DOTNET("mscorlib", "System.Collections.Stack");
11+
$variant = new VARIANT;
12+
foreach ([$com, $dotnet, $variant] as $object) {
13+
try {
14+
serialize($object);
15+
} catch (Exception $ex) {
16+
echo "Exception: {$ex->getMessage()}\n";
17+
}
18+
}
19+
20+
$strings = ['C:3:"com":0:{}', 'C:6:"dotnet":0:{}', 'C:7:"variant":0:{}'];
21+
foreach ($strings as $string) {
22+
try {
23+
unserialize($string);
24+
} catch (Exception $ex) {
25+
echo "Exception: {$ex->getMessage()}\n";
26+
}
27+
}
28+
29+
$strings = ['O:3:"com":0:{}', 'O:6:"dotnet":0:{}', 'O:7:"variant":0:{}'];
30+
foreach ($strings as $string) {
31+
var_dump(unserialize($string));
32+
}
33+
?>
34+
===DONE===
35+
--EXPECTF--
36+
Exception: Serialization of 'com' is not allowed
37+
Exception: Serialization of 'dotnet' is not allowed
38+
Exception: Serialization of 'variant' is not allowed
39+
Exception: Unserialization of 'com' is not allowed
40+
Exception: Unserialization of 'dotnet' is not allowed
41+
Exception: Unserialization of 'variant' is not allowed
42+
43+
Warning: Erroneous data format for unserializing 'com' in %s on line %d
44+
45+
Notice: unserialize(): Error at offset 13 of 14 bytes in %s on line %d
46+
bool(false)
47+
48+
Warning: Erroneous data format for unserializing 'dotnet' in %s on line %d
49+
50+
Notice: unserialize(): Error at offset 16 of 17 bytes in %s on line %d
51+
bool(false)
52+
53+
Warning: Erroneous data format for unserializing 'variant' in %s on line %d
54+
55+
Notice: unserialize(): Error at offset 17 of 18 bytes in %s on line %d
56+
bool(false)
57+
===DONE===

0 commit comments

Comments
 (0)