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

Close GH-15229
This commit is contained in:
David Carlier 2024-08-04 17:23:16 +01:00
parent a6c547d1dd
commit 9aeb6761b5
No known key found for this signature in database
GPG Key ID: D308BD11AB42D054
6 changed files with 76 additions and 3 deletions

1
NEWS
View File

@ -47,6 +47,7 @@ PHP NEWS
with libedit/readline). (Peter Kokot)
. Fixed bug GH-15268 (heap buffer overflow in phpdbg
(zend_hash_num_elements() Zend/zend_hash.h)). (nielsdos)
. Fixed bug GH-15210 use-after-free on watchpoint allocations. (nielsdos)
- Soap:
. Fixed bug #55639 (Digest autentication dont work). (nielsdos)

View File

@ -254,6 +254,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable watch_recreation; /* watch elements pending recreation of their respective watchpoints */
HashTable watch_free; /* pointers to watch for being freed */
HashTable *watchlist_mem; /* triggered watchpoints */
HashTable *original_watchlist_mem; /* the original allocation for watchlist_mem, used when watchlist_mem has changed temporarily */
HashTable *watchlist_mem_backup; /* triggered watchpoints backup table while iterating over it */
bool watchpoint_hit; /* a watchpoint was hit */
void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */

View File

@ -1551,6 +1551,8 @@ int phpdbg_interactive(bool allow_async_unsafe, char *input) /* {{{ */
ret = phpdbg_stack_execute(&stack, allow_async_unsafe);
} zend_catch {
phpdbg_stack_free(&stack);
phpdbg_destroy_input(&input);
/* TODO: should use proper unwinding instead of bailing out */
zend_bailout();
} zend_end_try();

View File

@ -516,7 +516,9 @@ phpdbg_watch_element *phpdbg_add_watch_element(phpdbg_watchpoint_t *watch, phpdb
phpdbg_watch_element *old_element;
watch = res->ptr;
if ((old_element = zend_hash_find_ptr(&watch->elements, element->str))) {
phpdbg_free_watch_element(element);
if (element != old_element) {
phpdbg_free_watch_element(element);
}
return old_element;
}
}
@ -1471,6 +1473,7 @@ void phpdbg_setup_watchpoints(void) {
/* put these on a separate page, to avoid conflicts with other memory */
PHPDBG_G(watchlist_mem) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
PHPDBG_G(original_watchlist_mem) = PHPDBG_G(watchlist_mem);
zend_hash_init(PHPDBG_G(watchlist_mem), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1);
PHPDBG_G(watchlist_mem_backup) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
zend_hash_init(PHPDBG_G(watchlist_mem_backup), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1);
@ -1517,8 +1520,8 @@ void phpdbg_destroy_watchpoints(void) {
zend_hash_destroy(&PHPDBG_G(watch_recreation));
zend_hash_destroy(&PHPDBG_G(watch_free));
zend_hash_destroy(&PHPDBG_G(watch_collisions));
zend_hash_destroy(PHPDBG_G(watchlist_mem));
free(PHPDBG_G(watchlist_mem));
zend_hash_destroy(PHPDBG_G(original_watchlist_mem));
free(PHPDBG_G(original_watchlist_mem));
zend_hash_destroy(PHPDBG_G(watchlist_mem_backup));
free(PHPDBG_G(watchlist_mem_backup));
}

View File

@ -0,0 +1,30 @@
--TEST--
GH-15210 use after free after continue
--PHPDBG--
b 4
r
w $a[0]
c
q
--FILE--
<?php
header_register_callback(function() { echo "sent";});
$a = [0];
$a[0] = 1;
?>
--EXPECTF--
[Successful compilation of %s]
prompt> [Breakpoint #0 added at %s:%d]
prompt> [Breakpoint #0 at %s:%d, hits: 1]
>00004: $a[0] = 1;
00005: ?>
00006:
prompt> [Added watchpoint #0 for $a[0]]
prompt> [Breaking on watchpoint $a[0]]
Old value: [Breaking on watchpoint $a[0]]
Old value: 0
New value: 1
>00002: header_register_callback(function() { echo "sent";});
00003: $a = [0];
00004: $a[0] = 1;
prompt> [$a[0] has been removed, removing watchpoint]

View File

@ -0,0 +1,36 @@
--TEST--
GH-15210 use after free after continue
--PHPDBG--
b 4
r
w $a[0]
c
c
q
--FILE--
<?php
header_register_callback(function() { echo "sent";});
$a = [0];
$a[0] = 1;
?>
--EXPECTF--
[Successful compilation of %s]
prompt> [Breakpoint #0 added at %s:%d]
prompt> [Breakpoint #0 at %s:%d, hits: 1]
>00004: $a[0] = 1;
00005: ?>
00006:
prompt> [Added watchpoint #0 for $a[0]]
prompt> [Breaking on watchpoint $a[0]]
Old value: [Breaking on watchpoint $a[0]]
Old value: 0
New value: 1
>00002: header_register_callback(function() { echo "sent";});
00003: $a = [0];
00004: $a[0] = 1;
prompt> sent0
New value: 1
[$a[0] has been removed, removing watchpoint]
[Script ended normally]
prompt>