Skip to content

Fix GH-15210: phpdbg_print_changed_zvals working on a real copy instead. #15229

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

Closed
wants to merge 3 commits into from

Conversation

devnexen
Copy link
Member

@devnexen devnexen commented Aug 4, 2024

No description provided.

@devnexen devnexen changed the title Fix GH-15120: phpdbg_print_changed_zvals working on a real copy instead. Fix GH-15210: phpdbg_print_changed_zvals working on a real copy instead. Aug 4, 2024
@devnexen devnexen force-pushed the gh15210 branch 2 times, most recently from 8883705 to 44cb341 Compare August 4, 2024 16:42
@devnexen devnexen marked this pull request as ready for review August 4, 2024 21:31
@devnexen devnexen requested a review from Girgias August 8, 2024 18:54
Comment on lines 3 to 4
--CREDITS--
YuanchengJiang
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really use credit sections any longer, as those were more to go around the limitations of SVN

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okidoki

Comment on lines 1171 to 1173
mem_list = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
zend_hash_init(mem_list, zend_hash_num_elements(PHPDBG_G(watchlist_mem)), NULL, NULL, false);
zend_hash_copy(mem_list, PHPDBG_G(watchlist_mem), (copy_ctor_func_t) zval_add_ref);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't totally understand why we need to duplicate the memory? Is it because the HashTable might be allocated with ZMM?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact is to avoid the hashtable corruption of the original watchpoint list, working on a copy then copy back once all is done. it fixed the issue for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would increasing the refcounter on the HashTable also fix it or not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to work if I allow cow violation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be wrong, we need a temporary hash table so that resizes don't cause problems. Increasing the refcount won't protect you against that and only papers over the real issue.

@Girgias Girgias requested a review from bwoebi August 8, 2024 22:36
Copy link
Member

@nielsdos nielsdos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right.

First, the test can be simplified to:

header_register_callback(function() { echo "sent";});
$a = [0];
$a[0] = 1;

And since it wasn't simplified, it makes me think that the root cause is not understood.

What happens is that there's a watchpoint for the $a array, and so when we modify it we trigger a break. The break then prints out the old and new values of the array element. Notice how the output says Old value: [Breaking on watchpoint $a[0]]. This happens because outputting the old value uses zend_write which will send the headers and therefore the user code is ran. This causes a re-entry into the phpdbg_print_changed_zvals function. When we then abort execution, the original PHPDBG_G(watchlist_mem) pointer still points at the backup list, so we get a double destruction in the module shutdown.

To solve this, we should remember the original allocation values. We only need one additional field for this because the backup pointer is never changed.

Furthermore, when trying some variations, I noticed that adding an additional c command after the c that was already there causes another crash. In this case this seems to happen because we re-add the same watchpoint element that is already added and get into the degenerate case where the old element is equal to the new element, causing a uaf.

Then when retesting under ASAN, I noticed that the input buffer leaked. I also noticed that phpdbg used the bailout system, and so some leaks cannot be fixed without getting rid of that.

Taking all of that into account, this is the patch I suggest: https://gist.github.com/nielsdos/f15a2f0bfc01885b3cd1f843e75500d0

Please check this and:

  1. Simplify the test like I've shown
  2. Make a test variant with 2 c commands.

Also note that even after all this fixing, there's still issues. Just try running phpdbg with tracked allocations on. This seems to happen because there's request memory allocated when setting up the watchpoints but that memory is already freed by the request allocator prior to the destruction logic for watchpoints in phpdbg. This is a different problem though.

Also running the phpdbg tests with ASAN now produces less test failures with my patch than before, but it's still very buggy and the entire sapi should be audited because damn this is all so buggy.

@devnexen
Copy link
Member Author

devnexen commented Aug 9, 2024

Ok I ll get to it in few hours. I stumbled across some of the bugs you mention even though, I might be wrong, I suppose is to cope with 3rd party extensions potential serious bugs.

Copy link
Member

@nielsdos nielsdos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well to me this makes sense, but I may be biased :P

@devnexen devnexen closed this in 9aeb676 Aug 9, 2024
nielsdos added a commit that referenced this pull request Aug 9, 2024
Similarly to other watchpoint tests, we add SKIPIFs.
These TRACKED_ALLOC issues should be investigated though [1] [2].

[1] de5c760#comments
[2] #15229 (review)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Heap use-after-free in phpdbg (zend_hash.c:57 in _zend_is_inconsistent)
3 participants