diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 53561476f2..ed632acd01 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -1043,3 +1043,91 @@ function PMA_sanitizeMySQLHost($name) return $name; } + +/** + * Safe unserializer wrapper + * + * It does not unserialize data containing objects + * + * @param string $data Data to unserialize + * + * @return mixed + */ +function PMA_safeUnserialize($data) +{ + if (! is_string($data)) { + return null; + } + + /* validate serialized data */ + $length = strlen($data); + $depth = 0; + for ($i = 0; $i < $length; $i++) { + $value = $data[$i]; + + switch ($value) + { + case '}': + /* end of array */ + if ($depth <= 0) { + return null; + } + $depth--; + break; + case 's': + /* string */ + // parse sting length + $strlen = intval($data[$i + 2]); + // string start + $i = strpos($data, ':', $i + 2); + if ($i === false) { + return null; + } + // skip string, quotes and ; + $i += 2 + $strlen + 1; + if ($data[$i] != ';') { + return null; + } + break; + + case 'b': + case 'i': + case 'd': + /* bool, integer or double */ + // skip value to sepearator + $i = strpos($data, ';', $i); + if ($i === false) { + return null; + } + break; + case 'a': + /* array */ + // find array start + $i = strpos($data, '{', $i); + if ($i === false) { + return null; + } + // remember nesting + $depth++; + break; + case 'N': + /* null */ + // skip to end + $i = strpos($data, ';', $i); + if ($i === false) { + return null; + } + break; + default: + /* any other elements are not wanted */ + return null; + } + } + + // check unterminated arrays + if ($depth > 0) { + return null; + } + + return unserialize($data); +} diff --git a/libraries/tracking.lib.php b/libraries/tracking.lib.php index 40e49d47f4..4100110cb9 100644 --- a/libraries/tracking.lib.php +++ b/libraries/tracking.lib.php @@ -865,7 +865,10 @@ function PMA_getHtmlForSchemaSnapshot($url_query) ); // Unserialize snapshot - $temp = unserialize($data['schema_snapshot']); + $temp = PMA_safeUnserialize($data['schema_snapshot']); + if ($temp === null) { + $temp = array('COLUMNS' => array(), 'INDEXES' => array()); + } $columns = $temp['COLUMNS']; $indexes = $temp['INDEXES']; $html .= PMA_getHtmlForColumns($columns); diff --git a/test/libraries/core/PMA_safeUnserialize_test.php b/test/libraries/core/PMA_safeUnserialize_test.php new file mode 100644 index 0000000000..f2710c0792 --- /dev/null +++ b/test/libraries/core/PMA_safeUnserialize_test.php @@ -0,0 +1,55 @@ +assertEquals( + $expected, + PMA_safeUnserialize($data) + ); + } + + /** + * Test data provider + * + * @return array + */ + function provideMySQLHosts() + { + return array( + array('s:6:"foobar";', 'foobar'), + array('foobar', null), + array('b:0;', false), + array('O:1:"a":1:{s:5:"value";s:3:"100";}', null), + array('O:8:"stdClass":1:{s:5:"field";O:8:"stdClass":0:{}}', null), + array(serialize(array(1, 2, 3)), array(1, 2, 3)), + array(serialize('string""'), 'string""'), + array(serialize(array('foo' => 'bar')), array('foo' => 'bar')), + array(serialize(array('1', new stdClass(), '2')), null), + ); + } + +} +