]> granicus.if.org Git - php/commitdiff
fix SplObjectStorage unserialization (CVE-2010-2225)
authorStanislav Malyshev <stas@php.net>
Tue, 29 Jun 2010 00:58:31 +0000 (00:58 +0000)
committerStanislav Malyshev <stas@php.net>
Tue, 29 Jun 2010 00:58:31 +0000 (00:58 +0000)
ext/spl/spl_observer.c
ext/spl/tests/SplObjectStorage_unserialize_bad.phpt [new file with mode: 0644]
ext/spl/tests/SplObjectStorage_unserialize_nested.phpt [new file with mode: 0644]
ext/standard/php_var.h
ext/standard/var_unserializer.c
ext/standard/var_unserializer.re

index 4b62f9e1e6ef7636f4a342c58b1777a549043c9d..4cff175fa21a1ec3e01f713c1ae66b358c7e9f39 100755 (executable)
@@ -728,15 +728,26 @@ SPL_METHOD(SplObjectStorage, unserialize)
        zval_ptr_dtor(&pcount);
                
        while(count-- > 0) {
+               spl_SplObjectStorageElement *pelement;
+               char *hash;
+               int hash_len;
+               
                if (*p != ';') {
                        goto outexcept;
                }
                ++p;
+               if(*p != 'O' && *p != 'C' && *p != 'r') {
+                       goto outexcept;
+               }
                ALLOC_INIT_ZVAL(pentry);
                if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
                        zval_ptr_dtor(&pentry);
                        goto outexcept;
                }
+               if(Z_TYPE_P(pentry) != IS_OBJECT) {
+                       zval_ptr_dtor(&pentry);
+                       goto outexcept;
+               }
                ALLOC_INIT_ZVAL(pinf);
                if (*p == ',') { /* new version has inf */
                        ++p;
@@ -745,6 +756,23 @@ SPL_METHOD(SplObjectStorage, unserialize)
                                goto outexcept;
                        }
                }
+
+               hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC);
+               if (!hash) {
+                       zval_ptr_dtor(&pentry);
+                       zval_ptr_dtor(&pinf);
+                       goto outexcept;
+               }
+               pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+               spl_object_storage_free_hash(intern, hash);
+               if(pelement) {
+                       if(pelement->inf) {
+                               var_push_dtor(&var_hash, &pelement->inf);
+                       }
+                       if(pelement->obj) {
+                               var_push_dtor(&var_hash, &pelement->obj);
+                       }
+               } 
                spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC);
                zval_ptr_dtor(&pentry);
                zval_ptr_dtor(&pinf);
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt
new file mode 100644 (file)
index 0000000..00cd67b
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+SPL: Test that serialized blob contains unique elements (CVE-2010-2225)
+--FILE--
+<?php
+
+$badblobs = array(
+'x:i:2;i:0;,i:1;;i:0;,i:2;;m:a:0:{}',
+'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};R:1;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}',
+'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};r:1;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}',
+);
+foreach($badblobs as $blob) {
+try {
+  $so = new SplObjectStorage();
+  $so->unserialize($blob);
+  var_dump($so);
+} catch(UnexpectedValueException $e) {
+       echo $e->getMessage()."\n";
+}
+}
+--EXPECTF--
+Error at offset 6 of 34 bytes
+Error at offset 46 of 89 bytes
+object(SplObjectStorage)#2 (1) {
+  ["storage":"SplObjectStorage":private]=>
+  array(2) {
+    ["%s"]=>
+    array(2) {
+      ["obj"]=>
+      object(stdClass)#3 (0) {
+      }
+      ["inf"]=>
+      int(1)
+    }
+    ["%s"]=>
+    array(2) {
+      ["obj"]=>
+      object(stdClass)#1 (0) {
+      }
+      ["inf"]=>
+      object(stdClass)#3 (0) {
+      }
+    }
+  }
+}
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt
new file mode 100644 (file)
index 0000000..e96a82a
--- /dev/null
@@ -0,0 +1,47 @@
+--TEST--
+SPL: Test unserializing tested & linked storage
+--FILE--
+<?php
+$o = new StdClass();
+$a = new StdClass();
+
+$o->a = $a;
+
+$so = new SplObjectStorage();
+
+$so[$o] = 1;
+$so[$a] = 2;
+
+$s = serialize($so);
+echo $s."\n";
+
+$so1 = unserialize($s);
+var_dump($so1);
+
+--EXPECTF--
+C:16:"SplObjectStorage":76:{x:i:2;O:8:"stdClass":1:{s:1:"a";O:8:"stdClass":0:{}},i:1;;r:4;,i:2;;m:a:0:{}}
+object(SplObjectStorage)#4 (1) {
+  ["storage":"SplObjectStorage":private]=>
+  array(2) {
+    ["%s"]=>
+    array(2) {
+      ["obj"]=>
+      object(stdClass)#5 (1) {
+        ["a"]=>
+        object(stdClass)#6 (0) {
+        }
+      }
+      ["inf"]=>
+      int(1)
+    }
+    ["%s"]=>
+    array(2) {
+      ["obj"]=>
+      object(stdClass)#6 (0) {
+      }
+      ["inf"]=>
+      int(2)
+    }
+  }
+}
+
index e74680c548523450abddab1525028e2f1528b60c..ce4db5bdf49b1686f3967962c1c786e6b633ba2f 100644 (file)
@@ -100,6 +100,7 @@ do { \
 } while (0)
 
 PHPAPI void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval);
+PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval **val);
 PHPAPI void var_destroy(php_unserialize_data_t *var_hash);
 
 #define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \
index a33187b9f86700758543b150857b7c3e5a5fb6ac..28a90083d46ed1a22474c4b631a6adbb94e7e22e 100644 (file)
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Mon Jun 14 12:03:55 2010 */
+/* Generated by re2c 0.13.5 on Mon Jun 28 13:40:53 2010 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
@@ -59,7 +59,7 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
        var_hash->data[var_hash->used_slots++] = *rval;
 }
 
-static inline void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
+PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
 {
        var_entries *var_hash = (*var_hashx)->first_dtor, *prev = NULL;
 #if 0
index 089ffcae9f00084c5dcdcdf3e4e557d8cd7d1279..1498d27680e47acbb6acd31987942f13c929e6a4 100644 (file)
@@ -57,7 +57,7 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
        var_hash->data[var_hash->used_slots++] = *rval;
 }
 
-static inline void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
+PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
 {
        var_entries *var_hash = (*var_hashx)->first_dtor, *prev = NULL;
 #if 0