-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fixed #74699 - Broken ArrayIterator unserializing #2559
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
777d06d
to
0bad408
Compare
I think the root of the problem is incorrect handling of USE_OTHER during unserialization. getIterator() returns an AI with USE_OTHER, but we don't restore it as such during unserialization. |
0bad408
to
b8cb98d
Compare
@nikic thanks a lot! it's absolutely true. just reworked my PR to handle |
@nikic any feedback on this? |
@andrewnester Not checked it closely yet, but one problem I could foresee is that this might be maliciously used to create an ArrayObject with USE_OTHER, where the inner "array" is not also an ArrayObject/ArrayIterator. We should check if something bad can happen in that case and/or prevent it. |
@nikic I improved test to include check what happens when we create an |
@andrewnester What I had in mind here is a test like this: $payload = 'x:i:33554432;O:8:"stdClass":0:{};m:a:0:{}';
$str = 'C:11:"ArrayObject":' . strlen($payload) . ':{' . $payload . '}';
$ao = unserialize($str);
var_dump($ao["foo"]); And indeed, this causes a segmentation fault. I think the proper way to fix this is to not encode the USE_OTHER flag (as it was previously), but instead use spl_array_set_array, which will correctly detect whether the flag needs to be set or not. |
Apart from fixing that segfault, doing it that way should also support ArrayObject serializations prior to the fix transparently. |
802f802
to
823d637
Compare
@nikic thanks! I reworked my PR to use |
ext/spl/spl_array.c
Outdated
} else { | ||
ZVAL_COPY(&intern->array, &array); | ||
} | ||
var_push_dtor(&var_hash, &intern->array); |
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.
This should be pushing &array
now. Alternatively and I think preferably you can declare zval *array
and write array = var_tmp_var(&var_hash)
and drop this push_dtor (the same as flags and members is handled).
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.
Doing it that way will also avoid the leaks you're currently seeing.
spl_array_set_array(object, intern, &array, 0L, 1); | ||
} else { | ||
ZVAL_COPY(&intern->array, &array); | ||
} |
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.
Two things I'm unsure about here: 1. Whether this still handles the IS_SELF case correctly (I think that might require an extra check) and 2. whether this shouldn't be using spl_array_set_array for normal objects as well. In particular that would include the check for std object properties, something that we currently don't seem to check.
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.
@nikic thanks
- I've added additional check and fix for this.
- yeah, it's good idea to use
spl_array_set_array
for normal objects as well. Just implemented it
Merged as afc2282 into 7.0+ with some additional tweaks to handle the IS_SELF case. |
I'm still having problems with this in 7.1.10. |
Fix for https://bugs.php.net/bug.php?id=74669
thanks @nikic for note: the reason why it stopped work is wrong handling of USE_OTHER flag.