]> granicus.if.org Git - php/commitdiff
Fix #77177: Serializing or unserializing COM objects crashes
authorChristoph M. Becker <cmbecker69@gmx.de>
Fri, 23 Nov 2018 15:32:33 +0000 (16:32 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Fri, 23 Nov 2018 15:32:33 +0000 (16:32 +0100)
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.

NEWS
ext/com_dotnet/com_extension.c
ext/com_dotnet/com_handlers.c
ext/com_dotnet/php_com_dotnet_internal.h
ext/com_dotnet/tests/bug77177.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index d02ae5c15b5ca310f66a8c064f2d4126d7d91367..ff727d535958456c4a62af9705fae4f033b1c8c8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@ PHP                                                                        NEWS
   . Fixed bug #71041 (zend_signal_startup() needs ZEND_API).
     (Valentin V. Bartenev)
 
+- COM:
+  . Fixed bug #77177 (Serializing or unserializing COM objects crashes). (cmb)
+
 - Sockets:
   . Fixed bug #77136 (Unsupported IPV6_RECVPKTINFO constants on macOS).
     (Mizunashi Mana)
index 3b26cf1eb8090f4faf4e6308699fe80de856f432..859738647d03e3f06a79808f27ebed4ae2ace264 100644 (file)
@@ -30,6 +30,7 @@
 #include "php_com_dotnet.h"
 #include "php_com_dotnet_internal.h"
 #include "Zend/zend_exceptions.h"
+#include "Zend/zend_interfaces.h"
 
 ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
 static PHP_GINIT_FUNCTION(com_dotnet);
@@ -354,6 +355,8 @@ PHP_MINIT_FUNCTION(com_dotnet)
 {
        zend_class_entry ce, *tmp;
 
+       zend_hash_init(&com_dotnet_object_properties, 0, NULL, NULL, 0);
+
        php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
        php_com_persist_minit(INIT_FUNC_ARGS_PASSTHRU);
 
@@ -372,11 +375,15 @@ PHP_MINIT_FUNCTION(com_dotnet)
        ce.create_object = php_com_object_new;
        php_com_variant_class_entry = zend_register_internal_class(&ce);
        php_com_variant_class_entry->get_iterator = php_com_iter_get;
+       php_com_variant_class_entry->serialize = zend_class_serialize_deny;
+       php_com_variant_class_entry->unserialize = zend_class_unserialize_deny;
 
        INIT_CLASS_ENTRY(ce, "com", NULL);
        ce.create_object = php_com_object_new;
        tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
        tmp->get_iterator = php_com_iter_get;
+       tmp->serialize = zend_class_serialize_deny;
+       tmp->unserialize = zend_class_unserialize_deny;
 
        zend_ts_hash_init(&php_com_typelibraries, 0, NULL, php_com_typelibrary_dtor, 1);
 
@@ -385,6 +392,8 @@ PHP_MINIT_FUNCTION(com_dotnet)
        ce.create_object = php_com_object_new;
        tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
        tmp->get_iterator = php_com_iter_get;
+       tmp->serialize = zend_class_serialize_deny;
+       tmp->unserialize = zend_class_unserialize_deny;
 #endif
 
        REGISTER_INI_ENTRIES();
index fd9cdf22b095d6cfea253a8e74ac12c3a08cf5a3..1fc6c04c9a062c90a18b99d8c1153be05cffe538 100644 (file)
@@ -29,6 +29,8 @@
 #include "php_com_dotnet_internal.h"
 #include "Zend/zend_exceptions.h"
 
+const HashTable com_dotnet_object_properties;
+
 static zval *com_property_read(zval *object, zval *member, int type, void **cahce_slot, zval *rv)
 {
        php_com_dotnet_object *obj;
@@ -231,7 +233,7 @@ static HashTable *com_properties_get(zval *object)
         * infinite recursion when the hash is displayed via var_dump().
         * Perhaps it is best to leave it un-implemented.
         */
-       return NULL;
+       return &com_dotnet_object_properties;
 }
 
 static void function_dtor(zval *zv)
index 506a14b5425eba3364f2a99b965dbf09605742a6..f6147b2e818ca05b24222d06453e4f7bc91a506f 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "zend_ts_hash.h"
 
+extern const HashTable com_dotnet_object_properties;
+
 typedef struct _php_com_dotnet_object {
        zend_object zo;
 
diff --git a/ext/com_dotnet/tests/bug77177.phpt b/ext/com_dotnet/tests/bug77177.phpt
new file mode 100644 (file)
index 0000000..9013582
--- /dev/null
@@ -0,0 +1,57 @@
+--TEST--
+Bug #77177 (Serializing or unserializing COM objects crashes)
+--SKIPIF--
+<?php
+if (!extension_loaded('com_dotnet')) die('skip com_dotnet extension not available');
+?>
+--FILE--
+<?php
+$com = new COM("WScript.Shell");
+$dotnet = new DOTNET("mscorlib", "System.Collections.Stack");
+$variant = new VARIANT;
+foreach ([$com, $dotnet, $variant] as $object) {
+    try {
+        serialize($object);
+    } catch (Exception $ex) {
+        echo "Exception: {$ex->getMessage()}\n";
+    }
+}
+
+$strings = ['C:3:"com":0:{}', 'C:6:"dotnet":0:{}', 'C:7:"variant":0:{}'];
+foreach ($strings as $string) {
+    try {
+        unserialize($string);
+    } catch (Exception $ex) {
+        echo "Exception: {$ex->getMessage()}\n";
+    }
+}
+
+$strings = ['O:3:"com":0:{}', 'O:6:"dotnet":0:{}', 'O:7:"variant":0:{}'];
+foreach ($strings as $string) {
+    var_dump(unserialize($string));
+}
+?>
+===DONE===
+--EXPECTF--
+Exception: Serialization of 'com' is not allowed
+Exception: Serialization of 'dotnet' is not allowed
+Exception: Serialization of 'variant' is not allowed
+Exception: Unserialization of 'com' is not allowed
+Exception: Unserialization of 'dotnet' is not allowed
+Exception: Unserialization of 'variant' is not allowed
+
+Warning: Erroneous data format for unserializing 'com' in %s on line %d
+
+Notice: unserialize(): Error at offset 13 of 14 bytes in %s on line %d
+bool(false)
+
+Warning: Erroneous data format for unserializing 'dotnet' in %s on line %d
+
+Notice: unserialize(): Error at offset 16 of 17 bytes in %s on line %d
+bool(false)
+
+Warning: Erroneous data format for unserializing 'variant' in %s on line %d
+
+Notice: unserialize(): Error at offset 17 of 18 bytes in %s on line %d
+bool(false)
+===DONE===