-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Fix #81992: SplFixedArray::setSize() causes use-after-free #11959
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
Upon resizing, the elements are destroyed from lower index to higher index. When an element refers to an object with a destructor, it can refer to a lower (i.e. already destroyed) element, causing a uaf. Set refcounted zvals to NULL after destroying them to avoid a uaf.
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.
Nice solution!
@@ -188,15 +189,15 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) | |||
if (size == 0) { | |||
spl_fixedarray_dtor(array); | |||
array->elements = NULL; | |||
array->size = 0; |
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.
Shouldn't this be set before spl_fixedarray_dtor
to avoid the same issue on deallocation of the whole array? Edit: Ah, we're using size
in there. Thinking about it, we might even do other shenanigans like modify the array in the destructor of released objects...
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.
I'll have a closer look, I'm currently fixing the case of calling resize within resize, still causing uaf :/ I think I have a solution for that though.
I'll have a deeper look at your comment after that.
I've pushed a working fix for the resize UAF. My solution is the following: |
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.
LGTM, I tried to abuse it in various ways but was unable to do so.
@iluuu1994 as usual, thanks a lot for the sanity check ^^ ! |
Upon resizing, the elements are destroyed from lower index to higher index. When an element refers to an object with a destructor, it can refer to a lower (i.e. already destroyed) element, causing a uaf. Set refcounted zvals to NULL after destroying them to avoid a uaf. Closes phpGH-11959.
Upon resizing, the elements are destroyed from lower index to higher index. When an element contains an object with a destructor, that destructor can access a lower (i.e. already destroyed) element, causing a uaf. Set refcounted zvals to NULL after destroying them to avoid a uaf.
Alternative solution I thought about: Maybe it's possible to do it in two passes. First run all destructors and then destroy everything. But I don't know off the top of my head if the engine supports that (in an easy way). It seems complicated, and would also be technically a BC break because the destructors see still alive data that they might've expected to be destroyed.
The solution in this PR is BC-preserving because it previously just crashed instead of doing anything useful.