Commit 1a428e528f9 for php.net
commit 1a428e528f9c67d67e0b6bff5b036e04f9f9203e
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sun Apr 12 13:51:30 2026 -0400
Fix GH-21731: Random\Engine\Xoshiro256StarStar::__unserialize() accepts all-zero state (#21732)
The constructor rejects a seed that would leave the internal state
all zero, because xoshiro256** with zero state produces 0 on every
call forever. The unserialize callback didn't check the same
invariant. A caller feeding a crafted serialized payload through
__unserialize() ended up with a live engine that returned 0 from
every operation.
Match the constructor: reject the all-zero state from the unserialize
callback too. The Mt19937-aliased __unserialize() wrapper turns the
false return into the standard "Invalid serialization data" exception.
Closes GH-21731
diff --git a/NEWS b/NEWS
index 07653ef6a37..24846881de9 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,10 @@ PHP NEWS
- OpenSSL:
. Fix a bunch of memory leaks and crashes on edge cases. (ndossche)
+- Random:
+ . Fixed bug GH-21731 (Random\Engine\Xoshiro256StarStar::__unserialize()
+ accepts all-zero state). (iliaal)
+
- SPL:
. Fixed bug GH-21499 (RecursiveArrayIterator getChildren UAF after parent
free). (Girgias)
diff --git a/ext/random/engine_xoshiro256starstar.c b/ext/random/engine_xoshiro256starstar.c
index 1a054362f06..12db8198978 100644
--- a/ext/random/engine_xoshiro256starstar.c
+++ b/ext/random/engine_xoshiro256starstar.c
@@ -151,6 +151,10 @@ static bool unserialize(void *state, HashTable *data)
}
}
+ if (UNEXPECTED(s->state[0] == 0 && s->state[1] == 0 && s->state[2] == 0 && s->state[3] == 0)) {
+ return false;
+ }
+
return true;
}
diff --git a/ext/random/tests/02_engine/xoshiro256starstar_unserialize_zero_state.phpt b/ext/random/tests/02_engine/xoshiro256starstar_unserialize_zero_state.phpt
new file mode 100644
index 00000000000..6ebcd03e857
--- /dev/null
+++ b/ext/random/tests/02_engine/xoshiro256starstar_unserialize_zero_state.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-21731: Xoshiro256StarStar::__unserialize() must reject the all-zero state
+--FILE--
+<?php
+
+try {
+ var_dump(unserialize('O:32:"Random\Engine\Xoshiro256StarStar":2:{i:0;a:0:{}i:1;a:4:{i:0;s:16:"0000000000000000";i:1;s:16:"0000000000000000";i:2;s:16:"0000000000000000";i:3;s:16:"0000000000000000";}}'));
+} catch (\Exception $e) {
+ echo $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+Invalid serialization data for Random\Engine\Xoshiro256StarStar object