From: tandre
Operating system:
PHP version: 8.0.7
Package: *General Issues
Bug Type: Bug
Bug description:Serialization is unexpectedly allowed on anonymous classes with __serialize()
Description:
------------
Related to https://bugs.php.net/bug.php?id=69761
This may also affect internal classes that use
zend_class_serialize_deny. It may make sense to add some sort of bit
flag instead to forbid serialization in a class and all of its
subclasses.
This affects php 7.4 and newer versions. Because some libraries may be
unintentionally or intentionally relying on this (e.g. to serialize but
not unserialize), my preference would be fixing it in 8.1.
(I doubt this combination is commonly used but haven't looked into it)
- If an anonymous class extends another class then it might end up
declaring __serialize
https://wiki.php.net/rfc/custom_object_serialization
added support for
__serialize in 7.4 but did not specify behavior for anonymous classes.
The anonymous class name (with a null character followed by a unique
identifier) is typically not deterministic, so I believe that it should
be an error to serialize an anonymous class whether or not __serialize
is defined.
- Note that it is possible for a class to extend an anonymous class
through the use of class_alias on get_class($obj). Forbidding
serializing subclasses of anonymous classes is probably out of scope,
since this is extremely uncommon and would be fine if the anonymous
class had no private properties.
```
// in Zend/zend_compile.c, void zend_compile_class_decl(znode *result,
zend_ast *ast, bool toplevel)
if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) {
/* Serialization is not supported for anonymous classes */
ce->serialize = zend_class_serialize_deny;
ce->unserialize = zend_class_unserialize_deny;
}
```
It may be better to check if the bitflag is set on zend_class_entry in
(ce->ce_flags & ZEND_ACC_ANON_CLASS) when serializing and unserializing
(in ext/standard/var.c and ext/standard/var_unserializer.re)
Noticed while working on https://github.com/igbinary/igbinary/issues/251
Test script:
---------------
<?php
function check_serialize_throws($obj) {
try {
var_dump(serialize($obj));
} catch (Throwable $e) {
echo "Caught: " . $e->getMessage() . "\n";
}
}
check_serialize_throws(new class () {});
check_serialize_throws(new class () {
public function __serialize() { return []; }
public function __unserialize($value) { }
});
check_serialize_throws(new class () implements Serializable {
public function serialize() { return ''; }
public function unserialize(string $ser) { return new self(); }
});
Expected result:
----------------
All calls should result in the call to serialize throwing and "Caught:
Serialization of 'Serializable@anonymous' is not allowed" being emitted,
including on an anonymous class defining the __serialize() magic method.
Actual result:
--------------
When an anonymous class has the method __serialize, it can be
serialized.
Caught: Serialization of 'class@anonymous' is not allowed
string(46) "O:34:"class@anonymousphp shell code:1$4":0:{}"
Deprecated: The Serializable interface is deprecated. Implement
__serialize() and __unserialize() instead (or in addition, if support
for old PHP versions is necessary) in php shell code on line 1
Caught: Serialization of 'Serializable@anonymous' is not allowed
--
Edit bug report at https://bugs.php.net/bug.php?id=81111&edit=1
--
Fix committed: https://bugs.php.net/fix.php?id=81111&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=81111&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=81111&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=81111&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=81111&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=81111&r=support
Expected behavior: https://bugs.php.net/fix.php?id=81111&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=81111&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=81111&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=81111&r=globals
PHP version support discontinued: https://bugs.php.net/fix.php?id=81111&r=phptooold
Daylight Savings: https://bugs.php.net/fix.php?id=81111&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=81111&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=81111&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=81111&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=81111&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=81111&r=mysqlcfg