From bc76b3fca973b3a4548dc339a980d3b714417c55 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:22:03 +0200 Subject: [PATCH] Improve __unserialize() hardening for SplHeap/SplPriorityQueue It was possible to make the heap accept unserialize data when the heap was corrupted or under modification. This adds the necessary check to prevent that from happening. Also, the exception check at the bottom is pointless, spl_heap_unserialize_internal_state() already returns FAILURE on exception. If it *is* necessary, it should be documented why. Closes GH-20109. --- NEWS | 1 + ext/spl/spl_heap.c | 8 ++--- ...lize_under_corruption_or_modification.phpt | 30 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt diff --git a/NEWS b/NEWS index dd60fe29a5b..ee76f00c414 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ PHP NEWS - SPL: . Fixed bug GH-20101 (SplHeap/SplPriorityQueue serialization exposes INDIRECTs). (nielsdos) + . Improve __unserialize() hardening for SplHeap/SplPriorityQueue. (nielsdos) 09 Oct 2025, PHP 8.5.0RC2 diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 254fbde7b3f..5d36266393b 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -1257,6 +1257,10 @@ PHP_METHOD(SplHeap, __unserialize) Z_PARAM_ARRAY_HT(data) ZEND_PARSE_PARAMETERS_END(); + if (UNEXPECTED(spl_heap_consistency_validations(intern, true) != SUCCESS)) { + RETURN_THROWS(); + } + if (zend_hash_num_elements(data) != 2) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name)); RETURN_THROWS(); @@ -1285,10 +1289,6 @@ PHP_METHOD(SplHeap, __unserialize) RETURN_THROWS(); } - if (EG(exception)) { - RETURN_THROWS(); - } - if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) { RETURN_THROWS(); } diff --git a/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt b/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt new file mode 100644 index 00000000000..2e54be09ad1 --- /dev/null +++ b/ext/spl/tests/heap_unserialize_under_corruption_or_modification.phpt @@ -0,0 +1,30 @@ +--TEST-- +SplHeap should not accept unserialize data when it is corrupted or under modification +--FILE-- +__unserialize($array); + return $a < $b ? -1 : ($a == $b ? 0 : 1); + } +} + +$heap = new SplMaxHeap; +$heap->insert(1); +$array = $heap->__serialize(); + +$heap = new MyHeap; +$heap->insert(0); +try { + $heap->insert(2); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Heap cannot be changed when it is already being modified.