-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix bug 81111: Prevent serialization of anonymous classes #7176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ss entry serialize function.
The patch seems like it should prevent serialization. --- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -17,6 +17,7 @@
#include "php.h"
#include "ext/standard/php_var.h"
#include "php_incomplete_class.h"
+#include "zend_interfaces.h"
#include "zend_portability.h"
/* {{{ reference-handling for unserializer: var_* */
@@ -756,12 +757,16 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
#ifdef PHP_WIN32
# pragma optimize("", off)
#endif
-static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool has_unserialize)
+static inline int object_common(UNSERIALIZE_PARAMETER, zend_class_entry *ce, zend_long elements, bool has_unserialize)
{
HashTable *ht;
bool has_wakeup;
if (has_unserialize) {
+ if (UNEXPECTED(ce->unserialize == zend_class_unserialize_deny)) {
+ zend_class_unserialize_deny(rval, ce, (const unsigned char *)"", 0, (zend_unserialize_data *)var_hash);
+ return 0;
+ }
zval ary, *tmp;
if (elements >= HT_MAX_SIZE) {
@@ -1315,7 +1320,7 @@ object ":" uiv ":" ["] {
}
zend_string_release_ex(class_name, 0);
- return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
+ return object_common(UNSERIALIZE_PASSTHRU, ce, elements, has_unserialize);
}
"E:" uiv ":" ["] { php > echo serialize(new SplFileInfo('.'));
Warning: Uncaught Exception: Serialization of 'SplFileInfo' is not allowed in php shell code:1
Stack trace:
#0 php shell code(1): serialize(Object(SplFileInfo))
#1 {main}
thrown in php shell code on line 1
php > class Y extends SplFileInfo { public function __serialize() { return []; } public function __unserialize($data) { $this->data = $data; } }
php > echo serialize(new Y('.'));
O:1:"Y":0:{}
php > var_dump(unserialize('O:1:"Y":0:{}'));
object(Y)#2 (2) {
["data"]=>
array(0) {
}
["pathName":"SplFileInfo":private]=>
string(0) ""
} |
Thanks, I hadn't tracked down the unserialize side because I wasn't sure if blocking on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch is OK for me. I'm not completely sure how it it's going to work after removing Serializable
interface. (It's already deprecated in 8.1).
I think, it way be easier to check ZEND_ACC_ANON_CLASS flag.
@nikic please take a look
It's also possible to disable declaration of __serialize/__unserialize methods for anonymous classes in first place (in compiler). |
@dstogov this may lead to problems with anonymous classes extending ones that already declare those methods. There should be no problem with doing this, as long as these objects aren't actually serialized. One may use serialization in one scenario and anonymous class in another, it shouldn't be a problem. |
Wasn't |
I assume the
It was added before
I'd also considered doing that but things like creating anonymous classes extending classes that (1) extend Serializable, or (2) implement __serialize and __unserialize would break. Ignoring
|
php > class Y extends SplFileInfo { public function __serialize() { return []; } public function __unserialize($data) { $this->data = $data; } }
php > echo serialize(new Y('.'));
O:1:"Y":0:{}
php > var_dump(unserialize('O:1:"Y":0:{}'));
object(Y)#2 (2) {
["data"]=>
array(0) {
}
["pathName":"SplFileInfo":private]=>
string(0) ""
} |
@TysonAndre Something that is a bit confusing about checking for var_dump(unserialize('O:15:"ReflectionClass":0:{}')); provides a warning and notice and returns false from class Something extends ReflectionClass {
public function __serialize() { return []; }
public function __unserialize($value) { return new self(''); }
}
var_dump(unserialize('O:9:"Something":0:{}')); would throw an exception. |
Just to note that Nikita and I discussed this briefly when it was reported. We consider it worth while implementing that now, rather than putting a band aid on this, only to have to change it later. I don't have time to do this right now myself. |
@krakjoe when that does get solved, the same fix would need to be made for SplFileInfo The feature freeze is in 5 days - @dstogov already approved this, and I was waiting for feedback from @nikic (e.g. I doubt many projects would be affected by this, but do any of the top composer packages combine __serialize/__unserialize with anonymous classes (not from inheritance, not to throw)? I can't imagine that being done since the name would change) |
I've opened #7249 for the alternative approach. |
Closing this in favor of #7249. |
This is a pretty basic solution for preventing
__serialize
on anonymous classes for bug 81111.It's probably not very elegant though...
This has the side effect of ignoring
__serialize
for classes that extend internal classes that usezend_class_serialize_deny
. For example,That seems like its better than allowing serialization. However, using
__unserialize
for a class that extends an internal class is still possible: