Skip to content

Commit 9aeb676

Browse files
committed
Fix GH-15210: phpdbg_print_changed_zvals working on a real copy instead.
Close GH-15229
1 parent a6c547d commit 9aeb676

File tree

6 files changed

+76
-3
lines changed

6 files changed

+76
-3
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ PHP NEWS
4747
with libedit/readline). (Peter Kokot)
4848
. Fixed bug GH-15268 (heap buffer overflow in phpdbg
4949
(zend_hash_num_elements() Zend/zend_hash.h)). (nielsdos)
50+
. Fixed bug GH-15210 use-after-free on watchpoint allocations. (nielsdos)
5051

5152
- Soap:
5253
. Fixed bug #55639 (Digest autentication dont work). (nielsdos)

sapi/phpdbg/phpdbg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
254254
HashTable watch_recreation; /* watch elements pending recreation of their respective watchpoints */
255255
HashTable watch_free; /* pointers to watch for being freed */
256256
HashTable *watchlist_mem; /* triggered watchpoints */
257+
HashTable *original_watchlist_mem; /* the original allocation for watchlist_mem, used when watchlist_mem has changed temporarily */
257258
HashTable *watchlist_mem_backup; /* triggered watchpoints backup table while iterating over it */
258259
bool watchpoint_hit; /* a watchpoint was hit */
259260
void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */

sapi/phpdbg/phpdbg_prompt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,8 @@ int phpdbg_interactive(bool allow_async_unsafe, char *input) /* {{{ */
15511551
ret = phpdbg_stack_execute(&stack, allow_async_unsafe);
15521552
} zend_catch {
15531553
phpdbg_stack_free(&stack);
1554+
phpdbg_destroy_input(&input);
1555+
/* TODO: should use proper unwinding instead of bailing out */
15541556
zend_bailout();
15551557
} zend_end_try();
15561558

sapi/phpdbg/phpdbg_watch.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ phpdbg_watch_element *phpdbg_add_watch_element(phpdbg_watchpoint_t *watch, phpdb
516516
phpdbg_watch_element *old_element;
517517
watch = res->ptr;
518518
if ((old_element = zend_hash_find_ptr(&watch->elements, element->str))) {
519-
phpdbg_free_watch_element(element);
519+
if (element != old_element) {
520+
phpdbg_free_watch_element(element);
521+
}
520522
return old_element;
521523
}
522524
}
@@ -1471,6 +1473,7 @@ void phpdbg_setup_watchpoints(void) {
14711473

14721474
/* put these on a separate page, to avoid conflicts with other memory */
14731475
PHPDBG_G(watchlist_mem) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
1476+
PHPDBG_G(original_watchlist_mem) = PHPDBG_G(watchlist_mem);
14741477
zend_hash_init(PHPDBG_G(watchlist_mem), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1);
14751478
PHPDBG_G(watchlist_mem_backup) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
14761479
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) {
15171520
zend_hash_destroy(&PHPDBG_G(watch_recreation));
15181521
zend_hash_destroy(&PHPDBG_G(watch_free));
15191522
zend_hash_destroy(&PHPDBG_G(watch_collisions));
1520-
zend_hash_destroy(PHPDBG_G(watchlist_mem));
1521-
free(PHPDBG_G(watchlist_mem));
1523+
zend_hash_destroy(PHPDBG_G(original_watchlist_mem));
1524+
free(PHPDBG_G(original_watchlist_mem));
15221525
zend_hash_destroy(PHPDBG_G(watchlist_mem_backup));
15231526
free(PHPDBG_G(watchlist_mem_backup));
15241527
}

sapi/phpdbg/tests/gh15210_001.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-15210 use after free after continue
3+
--PHPDBG--
4+
b 4
5+
r
6+
w $a[0]
7+
c
8+
q
9+
--FILE--
10+
<?php
11+
header_register_callback(function() { echo "sent";});
12+
$a = [0];
13+
$a[0] = 1;
14+
?>
15+
--EXPECTF--
16+
[Successful compilation of %s]
17+
prompt> [Breakpoint #0 added at %s:%d]
18+
prompt> [Breakpoint #0 at %s:%d, hits: 1]
19+
>00004: $a[0] = 1;
20+
00005: ?>
21+
00006:
22+
prompt> [Added watchpoint #0 for $a[0]]
23+
prompt> [Breaking on watchpoint $a[0]]
24+
Old value: [Breaking on watchpoint $a[0]]
25+
Old value: 0
26+
New value: 1
27+
>00002: header_register_callback(function() { echo "sent";});
28+
00003: $a = [0];
29+
00004: $a[0] = 1;
30+
prompt> [$a[0] has been removed, removing watchpoint]

sapi/phpdbg/tests/gh15210_002.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
GH-15210 use after free after continue
3+
--PHPDBG--
4+
b 4
5+
r
6+
w $a[0]
7+
c
8+
c
9+
q
10+
--FILE--
11+
<?php
12+
header_register_callback(function() { echo "sent";});
13+
$a = [0];
14+
$a[0] = 1;
15+
?>
16+
--EXPECTF--
17+
[Successful compilation of %s]
18+
prompt> [Breakpoint #0 added at %s:%d]
19+
prompt> [Breakpoint #0 at %s:%d, hits: 1]
20+
>00004: $a[0] = 1;
21+
00005: ?>
22+
00006:
23+
prompt> [Added watchpoint #0 for $a[0]]
24+
prompt> [Breaking on watchpoint $a[0]]
25+
Old value: [Breaking on watchpoint $a[0]]
26+
Old value: 0
27+
New value: 1
28+
>00002: header_register_callback(function() { echo "sent";});
29+
00003: $a = [0];
30+
00004: $a[0] = 1;
31+
prompt> sent0
32+
New value: 1
33+
34+
[$a[0] has been removed, removing watchpoint]
35+
[Script ended normally]
36+
prompt>

0 commit comments

Comments
 (0)