From 8820a103609a793314c651e2e07847f880fdbd50 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 16 Oct 2024 19:44:28 +0200 Subject: [PATCH] Fix uaf in SplDoublyLinkedList::offsetSet() Write to the new offset before calling the destructor of the previous value. Fixes GH-16464 Closes GH-16466 --- NEWS | 2 ++ ext/spl/spl_dllist.c | 4 +++- ext/spl/tests/gh16464.phpt | 29 +++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 ext/spl/tests/gh16464.phpt diff --git a/NEWS b/NEWS index be48244e19c..217b7e07be3 100644 --- a/NEWS +++ b/NEWS @@ -68,6 +68,8 @@ PHP NEWS - SPL: . Fixed bug GH-16337 (Use-after-free in SplHeap). (nielsdos) + . Fixed bug GH-16464 (Use-after-free in SplDoublyLinkedList::offsetSet()). + (ilutov) - Standard: . Fixed bug GH-16293 (Failed assertion when throwing in assert() callback with diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 186b9a34c7e..6592efc4e5e 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -737,8 +737,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetSet) if (element != NULL) { /* the element is replaced, delref the old one as in * SplDoublyLinkedList::pop() */ - zval_ptr_dtor(&element->data); + zval garbage; + ZVAL_COPY_VALUE(&garbage, &element->data); ZVAL_COPY(&element->data, value); + zval_ptr_dtor(&garbage); } else { zval_ptr_dtor(value); zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset"); diff --git a/ext/spl/tests/gh16464.phpt b/ext/spl/tests/gh16464.phpt new file mode 100644 index 00000000000..7b3b1e80e6f --- /dev/null +++ b/ext/spl/tests/gh16464.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-16464: Use-after-free in SplDoublyLinkedList::offsetSet() when modifying list in destructor of overwritten object +--FILE-- +pop()); + } +} + +$list = new SplDoublyLinkedList; +$list->add(0, new C); +$list[0] = 42; +var_dump($list); + +?> +--EXPECTF-- +int(42) +object(SplDoublyLinkedList)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(0) + ["dllist":"SplDoublyLinkedList":private]=> + array(0) { + } +}