php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #21957 returnless __sleep mangles session data
Submitted: 2003-01-29 23:19 UTC Modified: 2003-08-10 22:22 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: rkelly at whitley dot unimelb dot edu dot au Assigned:
Status: Closed Package: Session related
PHP Version: 4.3.1-dev OS: Linux (Debian/Testing)
Private report: No CVE-ID:
 [2003-01-29 23:19 UTC] rkelly at whitley dot unimelb dot edu dot au
While there were a few bugs filed relating to _sleep and serialization and sessions, none seemed to deal with the behavior described below.  A few talk about Apache crashing under similar circumstances - there is not crash, just a lot of unexpected behavior.
My appologies if this is a duplicate...


If the return statement if left out of the definition of __sleep in a class, it appears that the serialization of this class is then an empty string.

This seems fair enough, but it can cause strange behavior when attempting to store the Object in a Session.  For simple data structures it's not a problem, but for more complex ones the session data string becomes mangled to the point where other (unrelated) session objects are affected.

Consider the following simple script, in which the careless author has forgotten to include the return statement for __sleep:

<?PHP
                                                                                                                   
                                                                                                                   
class Test
{
  var $a;
  var $b;
                                                                                                                   
  function Test()
  {
    $this->a = 7;
    $this->b = 2;
  }
                                                                                                                   
  function __sleep()
  {
    $this->b = 0;
  }
}
                                                                                                                   
                                                                                                                   
session_start();
                                                                                                                   
echo 'Session at start of request:<br />';
echo '<pre>';
print_r($_SESSION);
echo '</pre><br />';
                                                                                                                   
$t['one'] = 'this is a test string';
$t['two'] = new Test();
$_SESSION['test'] = $t;
$_SESSION['test2'] = "this is another test string";
                                                                                                                   
echo 'Serialised session variable:<br />';
echo '-->'.serialize($_SESSION['test']).'<--';
echo '<br /><br />';
                                                                                                                   
echo 'Session at end of request:<br />';
echo '<pre>';
print_r($_SESSION);
echo '</pre><br />';
                                                                                                                   
                                                                                                                   
?>


After clearing the session cookie (or starting a new browser session) the original output of the page is as would be expected:


Session at start of request:

Array
(
)


Serialised session variable:
-->a:2:{s:3:"one";s:21:"this is a test string";s:3:"two";}<--

Session at end of request:

Array
(
    [test] => Array
        (
            [one] => this is a test string
            [two] => test Object
                (
                    [a] => 7
                    [b] => 0
                )

        )

    [test2] => this is another test string
)


The values in $_SESSION are fine.  One can see the problem with the serialized version of the session variable quite clearly - while the array supposedly contains 2 elements, there is no information on how to reconstruct the second one.  Thus, this string cannot be unserialized.

Re-loading the page (so that the session data is read from the stored, serialised data) produces the following output:

Session at start of request:

Array
(
    [test] => 
    [}test2] => this is another test string
)


Serialised session variable:
-->a:2:{s:3:"one";s:21:"this is a test string";s:3:"two";}<--

Session at end of request:

Array
(
    [test] => Array
        (
            [one] => this is a test string
            [two] => test Object
                (
                    [a] => 7
                    [b] => 0
                )

        )

    [}test2] => this is another test string
    [test2] => this is another test string
)


Notice the mangling of the session variables.  For good measure, re-load the page once more to produce:

Session at start of request:

Array
(
    [test] => 
    [}}test2] => this is another test string
    [test2] => this is another test string
)


Serialised session variable:
-->a:2:{s:3:"one";s:21:"this is a test string";s:3:"two";}<--

Session at end of request:

Array
(
    [test] => Array
        (
            [one] => this is a test string
            [two] => test Object
                (
                    [a] => 7
                    [b] => 0
                )

        )

    [}}test2] => this is another test string
    [test2] => this is another test string
)


Further requests continue to add '}' characters to the strange session variable.  With more complicated data structures (such as the one I originally discovered this behavior in) the results of the mangling can be much more bizzare and more serious.  Particularly worrying is that the unrelated variable 'test2' was lost from the session on the first re-load.  It is only restored in later requests because it is explicitly set each time and is now guarded by the other phantom variable.


Adding a proper return statement to __sleep fixes the problem.


While the obvious solution is 'make sure there is a return statement inside __sleep', I'm concerned about the potential for mangling session data because sessions are so often related to security.  Especially if untrusted objects were being stored in session data, this could potentially cause serious problems (at least, I imagine so).
At the very least, causing unexpected changes to session data is difficult to deal with as a programmer - especially if you were not the author of the offending class, since no indication of the problem is given.

Perhaps objects with an empty serialisation could be treated as null?  Or, perhaps the return value of __sleep could default to an empty array?  Or perhaps leaving it out could trigger a warning?  Just suggestions...

If you need any more info, please feel free to contact me.


  Ryan


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-02-03 08:09 UTC] sniper@php.net
Same result with latest CVS of PHP_4_3 branch.
There is an error message given:

"Notice: serialize() [function.serialize]: __sleep should return an array only containing the names of instance-variables to serialize."

But it should propably store NULL there instead of mangling the object totally.


 [2003-08-10 22:22 UTC] iliaa@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sat Apr 19 12:01:52 2014 UTC