summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2010-06-29 00:58:31 +0000
committerStanislav Malyshev <stas@php.net>2010-06-29 00:58:31 +0000
commit865f85718fae288c2a2023c537000c9d1a9356ed (patch)
tree5ad4682779a4d637f16d60f904671268823a07e4
parent9c60bd8df723db75c62ec147610151c867a55f6f (diff)
downloadphp-git-865f85718fae288c2a2023c537000c9d1a9356ed.tar.gz
fix SplObjectStorage unserialization (CVE-2010-2225)
-rw-r--r--NEWS2
-rwxr-xr-xext/spl/spl_observer.c20
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_bad.phpt45
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_nested.phpt47
-rw-r--r--ext/standard/php_var.h1
-rw-r--r--ext/standard/var_unserializer.c4
-rw-r--r--ext/standard/var_unserializer.re2
7 files changed, 118 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 0b7755c52c..9a2e8897fe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2010, PHP 5.3.3 RC2
+- Fixed SplObjectStorage unserialization problems (CVE-2010-2225). (Stas)
+
- Implemented FR #51295 (SQLite3::busyTimeout not existing). (Mark)
- Fixed the mail.log ini setting when no filename was given. (Johannes)
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
index 7676d03c56..4b1dd1fa3e 100755
--- a/ext/spl/spl_observer.c
+++ b/ext/spl/spl_observer.c
@@ -115,6 +115,7 @@ static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{
zval_ptr_dtor(&element->inf);
} /* }}} */
+
spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
{
spl_SplObjectStorageElement *element;
@@ -632,15 +633,24 @@ SPL_METHOD(SplObjectStorage, unserialize)
zval_ptr_dtor(&pcount);
while(count-- > 0) {
+ spl_SplObjectStorageElement *pelement;
+
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;
@@ -649,6 +659,16 @@ SPL_METHOD(SplObjectStorage, unserialize)
goto outexcept;
}
}
+
+ pelement = spl_object_storage_get(intern, pentry TSRMLS_CC);
+ 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, 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
index 0000000000..9e3f3605b7
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt
@@ -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)#4 (0) {
+ }
+ }
+ }
+}
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt
new file mode 100644
index 0000000000..56e83f805d
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt
@@ -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:2;,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)
+ }
+ }
+}
+
diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h
index ed03e3f2eb..60c7782de6 100644
--- a/ext/standard/php_var.h
+++ b/ext/standard/php_var.h
@@ -60,6 +60,7 @@ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsig
var_destroy(&(var_hash))
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) \
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 1ed2710f1f..bd5d43b29d 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Mon Apr 12 10:11:22 2010 */
+/* Generated by re2c 0.13.5 on Fri Jun 25 15:36:31 2010 */
#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+
@@ -56,7 +56,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;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 689fd90cd6..43c230f527 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -54,7 +54,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;