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
(against 7.1) Fix bug 72610 by deferring __wakeup: fixes unserialize read after free of property table #2050
Conversation
Seems @nikic already merged this into 7.1: #2070 (comment) Please confirm and close if so :) |
d8322cc
to
0c3e35f
Compare
The PHP source code for all versions of php 7 was keeping **pointers** to object properties, not copies of the object properties. There are two ways to fix this. This PR chooses the second. So does HHVM. - Keep copies of **all** zvals instead of pointers to zvals while unserializing, increment reference counts. - Defer calls to __wakeup until the very end. This requires copying only the objects of classes implementing __wakeup. hhvm handles __wakeup this way. https://github.com/facebook/hhvm/blob/2d5f00afbb033aec0cbc51cbe3a897af79cdcb28/hphp/runtime/base/variable-unserializer.cpp#L333 https://github.com/facebook/hhvm/blob/2d5f00afbb033aec0cbc51cbe3a897af79cdcb28/hphp/runtime/base/variable-unserializer.cpp#L965 Make the publicly exposed APIs var_unserialize and var_unserialize_ex perform this finalization at the very end. Many extensions use var_unserialize to unserialize data (e.g. ext/session, or extensions outside of php-src), and this change is made in a way that shouldn't break them. - Move the inner zval deserialization code into a static method, so that they won't accidentally be called and miss a call to __wakeup. - Fix merge conflicts with php#2070
Test adding a lot of unique dynamic properties in __wakeup Print the values before and after serialization. And modify another test of serialization - It referred to a value that was deleted in __wakeup, so it used to be converted to UNDEF. This conversion to UNDEF is no longer necessary, since we create the copy/reference *before* __wakeup is called
0c3e35f
to
56fabb4
Compare
Fixed merge conflicts. This PR is still applicable, but I didn't notice #2070 being created or merged. The two XFAIL tests in ext/standard/tests/serializer are still failing (currently crashing). |
The implementation currently will wake up all queued objects on completion of nested unserialize, including those not part of the nested unserialize. I assume this done, because the nested unserialize may contain references to those objects and a woken-up state may be subsequently assumed? Independently of the exact set of objects that are woken up, any Serializable object can still be used to cause the same memory unsafety (without anything nefarious in the unserialize handler itself) using a sequence like This could be avoided by delaying the wakeups until the very end (unserialize data destruction) -- however, this does change the call sequence. I'm wondering if it might still be preferable, as the behavior difference should be insignificant (just like none of the core Serializable handlers would care). |
I assume by nested unserialize, you mean internal functions defining Nested unserializing behavior as currently written in this PR was an oversight... there's probably no catch-all way if internal classes define their own unserialize() function.
static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER);
I haven't seen that bug report for ArrayObject, are you able to link that or example code? |
By nested unserialize I mean Serializable::unserialize() calling unserialize(), which runs in the same unserialization context (shared unserialize data). That includes a number of internal classes, but can also be specified in userland. Generally, ::unserialize() is affected in the same way as __wakeup, but I don't think there is a good way to resolve that, as those calls cannot be delayed. My concern is with the case where ::unserialize() does not do anything nefarious itself, but simply triggers wakeups in a nested unserialize (at least with the current patch). ArrayObject is an example of a class using Serializable. For an example of this problem, simply insert a |
@nikic this has merge conflicts, also, I am unsure if this is the patch I'm told exists by Stas, or is that another one ? |
The patch Stas mentioned is a different one, although based on the same general idea. As it should be landing soon, I'm closing this PR and #2004. I'll write back once the patch lands. |
ACK, i'll be waiting for the other __wakeup patch as well, to include for the RC as recommmended by Stas. Thanks. |
Same as what used to be #2004 , but against php 7.1. Further changes will be made against #2004 to preserve the ABI.
This changes the ABI, but 7.1 is still in beta. See #2004 (comment)