Skip to content
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

Closed
wants to merge 2 commits into from

Conversation

TysonAndre
Copy link
Contributor

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)

@dshafik
Copy link
Contributor

dshafik commented Aug 31, 2016

Seems @nikic already merged this into 7.1: #2070 (comment)

Please confirm and close if so :)

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
@TysonAndre
Copy link
Contributor Author

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).

@nikic
Copy link
Member

nikic commented Aug 31, 2016

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 ObjWithWakeup;ArrayObject;Ref;.

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).

@TysonAndre
Copy link
Contributor Author

TysonAndre commented Aug 31, 2016

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?

I assume by nested unserialize, you mean internal functions defining foo_ce->unserialize = foo_unserialize. Anything else? (Internal classes such as DateTime might also define __wakeup with the syntax PHP_METHOD(DateTime, __wakeup)

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.

  • Instead, I might be able to assume that internal classes don't define dynamic params in object props on __wakeup, and assume bug reports would be filed

static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER);would need to be changed tostatic int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, php_wakeup_data *data)`

using a sequence like ObjWithWakeup;ArrayObject;Ref;.

I haven't seen that bug report for ArrayObject, are you able to link that or example code?

@nikic
Copy link
Member

nikic commented Aug 31, 2016

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 new ArrayObject between the two objects in https://github.com/php/php-src/pull/2050/files#diff-135a455a26203243ea45bfccd93d0b5cR25

@smalyshev smalyshev added the Bug label Sep 5, 2016
@krakjoe
Copy link
Member

krakjoe commented Jan 3, 2017

@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 ?

@nikic
Copy link
Member

nikic commented Jan 3, 2017

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.

@weltling
Copy link
Contributor

weltling commented Jan 3, 2017

ACK, i'll be waiting for the other __wakeup patch as well, to include for the RC as recommmended by Stas.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants