From 61c680a58e20a49e61a527e1d8b3aae8030c31d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 30 Jul 2022 11:59:39 +0200 Subject: [PATCH 1/9] Add Random\Random{Error,Exception} and Random\BrokenRandomEngineError --- ext/random/php_random.h | 4 +++ ext/random/random.c | 14 +++++++++++ ext/random/random.stub.php | 21 ++++++++++++++++ ext/random/random_arginfo.h | 50 ++++++++++++++++++++++++++++++++++++- 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/ext/random/php_random.h b/ext/random/php_random.h index 6c369c5086de5..cc05a03c86932 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -260,6 +260,10 @@ typedef struct _php_random_randomizer { extern PHPAPI zend_class_entry *random_ce_Random_Engine; extern PHPAPI zend_class_entry *random_ce_Random_CryptoSafeEngine; +extern PHPAPI zend_class_entry *random_ce_Random_RandomError; +extern PHPAPI zend_class_entry *random_ce_Random_BrokenRandomEngineError; +extern PHPAPI zend_class_entry *random_ce_Random_RandomException; + extern PHPAPI zend_class_entry *random_ce_Random_Engine_PcgOneseq128XslRr64; extern PHPAPI zend_class_entry *random_ce_Random_Engine_Mt19937; extern PHPAPI zend_class_entry *random_ce_Random_Engine_Xoshiro256StarStar; diff --git a/ext/random/random.c b/ext/random/random.c index ec9877544844e..0d9f46e06a479 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -74,8 +74,13 @@ PHPAPI zend_class_entry *random_ce_Random_Engine_Mt19937; PHPAPI zend_class_entry *random_ce_Random_Engine_PcgOneseq128XslRr64; PHPAPI zend_class_entry *random_ce_Random_Engine_Xoshiro256StarStar; PHPAPI zend_class_entry *random_ce_Random_Engine_Secure; + PHPAPI zend_class_entry *random_ce_Random_Randomizer; +PHPAPI zend_class_entry *random_ce_Random_RandomError; +PHPAPI zend_class_entry *random_ce_Random_BrokenRandomEngineError; +PHPAPI zend_class_entry *random_ce_Random_RandomException; + static zend_object_handlers random_engine_mt19937_object_handlers; static zend_object_handlers random_engine_pcgoneseq128xslrr64_object_handlers; static zend_object_handlers random_engine_xoshiro256starstar_object_handlers; @@ -832,6 +837,15 @@ PHP_MINIT_FUNCTION(random) /* Random\CryptoSafeEngine */ random_ce_Random_CryptoSafeEngine = register_class_Random_CryptoSafeEngine(random_ce_Random_Engine); + /* Random\RandomError */ + random_ce_Random_RandomError = register_class_Random_RandomError(zend_ce_error); + + /* Random\BrokenRandomEngineError */ + random_ce_Random_BrokenRandomEngineError = register_class_Random_BrokenRandomEngineError(random_ce_Random_RandomError); + + /* Random\RandomException */ + random_ce_Random_RandomException = register_class_Random_RandomException(zend_ce_exception); + /* Random\Engine\Mt19937 */ random_ce_Random_Engine_Mt19937 = register_class_Random_Engine_Mt19937(random_ce_Random_Engine); random_ce_Random_Engine_Mt19937->create_object = php_random_engine_mt19937_new; diff --git a/ext/random/random.stub.php b/ext/random/random.stub.php index 754087f3ce4e0..0a178f2657dc2 100644 --- a/ext/random/random.stub.php +++ b/ext/random/random.stub.php @@ -147,4 +147,25 @@ public function __serialize(): array {} public function __unserialize(array $data): void {} } + + /** + * @strict-properties + */ + class RandomError extends \Error + { + } + + /** + * @strict-properties + */ + class BrokenRandomEngineError extends RandomError + { + } + + /** + * @strict-properties + */ + class RandomException extends \Exception + { + } } diff --git a/ext/random/random_arginfo.h b/ext/random/random_arginfo.h index 3aaf4fcc1fad4..440e77c62ef45 100644 --- a/ext/random/random_arginfo.h +++ b/ext/random/random_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 82403b033dfd476695c4e11e0b01a3c984896f62 */ + * Stub hash: 6cc9022516ce23c2e95af30606db43e9fc28e38a */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_lcg_value, 0, 0, IS_DOUBLE, 0) ZEND_END_ARG_INFO() @@ -217,6 +217,21 @@ static const zend_function_entry class_Random_Randomizer_methods[] = { ZEND_FE_END }; + +static const zend_function_entry class_Random_RandomError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_Random_BrokenRandomEngineError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_Random_RandomException_methods[] = { + ZEND_FE_END +}; + static void register_random_symbols(int module_number) { REGISTER_LONG_CONSTANT("MT_RAND_MT19937", MT_RAND_MT19937, CONST_CS | CONST_PERSISTENT); @@ -309,3 +324,36 @@ static zend_class_entry *register_class_Random_Randomizer(void) return class_entry; } + +static zend_class_entry *register_class_Random_RandomError(zend_class_entry *class_entry_Error) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Random", "RandomError", class_Random_RandomError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Error); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_Random_BrokenRandomEngineError(zend_class_entry *class_entry_Random_RandomError) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Random", "BrokenRandomEngineError", class_Random_BrokenRandomEngineError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Random_RandomError); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_Random_RandomException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Random", "RandomException", class_Random_RandomException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} From 6ef107134b6a3cd923d68b60f9117a8c8dfe9926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 30 Jul 2022 12:02:11 +0200 Subject: [PATCH 2/9] Throw BrokenRandomEngineError --- ext/random/engine_user.c | 2 +- ext/random/random.c | 4 ++-- ext/random/tests/03_randomizer/user_unsafe.phpt | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ext/random/engine_user.c b/ext/random/engine_user.c index 149e572dcb772..b45924d3bb7da 100644 --- a/ext/random/engine_user.c +++ b/ext/random/engine_user.c @@ -49,7 +49,7 @@ static uint64_t generate(php_random_status *status) result += ((uint64_t) (unsigned char) Z_STRVAL(retval)[i]) << (8 * i); } } else { - zend_throw_error(NULL, "A random engine must return a non-empty string"); + zend_throw_error(random_ce_Random_BrokenRandomEngineError, "A random engine must return a non-empty string"); return 0; } diff --git a/ext/random/random.c b/ext/random/random.c index 0d9f46e06a479..f2876024ad4d1 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -126,7 +126,7 @@ static inline uint32_t rand_range32(const php_random_algo *algo, php_random_stat while (UNEXPECTED(result > limit)) { /* If the requirements cannot be met in a cycles, return fail */ if (++count > RANDOM_RANGE_ATTEMPTS) { - zend_throw_error(NULL, "Failed to generate an acceptable random number in %d attempts", RANDOM_RANGE_ATTEMPTS); + zend_throw_error(random_ce_Random_BrokenRandomEngineError, "Failed to generate an acceptable random number in %d attempts", RANDOM_RANGE_ATTEMPTS); return 0; } @@ -182,7 +182,7 @@ static inline uint64_t rand_range64(const php_random_algo *algo, php_random_stat while (UNEXPECTED(result > limit)) { /* If the requirements cannot be met in a cycles, return fail */ if (++count > RANDOM_RANGE_ATTEMPTS) { - zend_throw_error(NULL, "Failed to generate an acceptable random number in %d attempts", RANDOM_RANGE_ATTEMPTS); + zend_throw_error(random_ce_Random_BrokenRandomEngineError, "Failed to generate an acceptable random number in %d attempts", RANDOM_RANGE_ATTEMPTS); return 0; } diff --git a/ext/random/tests/03_randomizer/user_unsafe.phpt b/ext/random/tests/03_randomizer/user_unsafe.phpt index e95a15840057d..6e6a8151fdf11 100644 --- a/ext/random/tests/03_randomizer/user_unsafe.phpt +++ b/ext/random/tests/03_randomizer/user_unsafe.phpt @@ -74,35 +74,35 @@ foreach ([ EmptyStringEngine ===================== -Error: A random engine must return a non-empty string in %s:%d +Random\BrokenRandomEngineError: A random engine must return a non-empty string in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->getInt(0, 123) #1 {main} ------- -Error: A random engine must return a non-empty string in %s:%d +Random\BrokenRandomEngineError: A random engine must return a non-empty string in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->nextInt() #1 {main} ------- -Error: A random engine must return a non-empty string in %s:%d +Random\BrokenRandomEngineError: A random engine must return a non-empty string in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->getBytes(1) #1 {main} ------- -Error: A random engine must return a non-empty string in %s:%d +Random\BrokenRandomEngineError: A random engine must return a non-empty string in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->shuffleArray(Array) #1 {main} ------- -Error: A random engine must return a non-empty string in %s:%d +Random\BrokenRandomEngineError: A random engine must return a non-empty string in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->shuffleBytes('foobar') #1 {main} @@ -111,7 +111,7 @@ Stack trace: HeavilyBiasedEngine ===================== -Error: Failed to generate an acceptable random number in 50 attempts in %s:%d +Random\BrokenRandomEngineError: Failed to generate an acceptable random number in 50 attempts in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->getInt(0, 123) #1 {main} @@ -126,14 +126,14 @@ string(2) "ff" ------- -Error: Failed to generate an acceptable random number in 50 attempts in %s:%d +Random\BrokenRandomEngineError: Failed to generate an acceptable random number in 50 attempts in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->shuffleArray(Array) #1 {main} ------- -Error: Failed to generate an acceptable random number in 50 attempts in %s:%d +Random\BrokenRandomEngineError: Failed to generate an acceptable random number in 50 attempts in %s:%d Stack trace: #0 %s(%d): Random\Randomizer->shuffleBytes('foobar') #1 {main} From db53776f113cf24f63d4aaa5af672c926e9c97ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 1 Aug 2022 20:34:51 +0200 Subject: [PATCH 3/9] Throw RandomException on seeding failure --- ext/random/engine_mt19937.c | 3 +-- ext/random/engine_pcgoneseq128xslrr64.c | 3 +-- ext/random/engine_xoshiro256starstar.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index bfddc96545803..d7d355b90d6b4 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -30,7 +30,6 @@ #include "php.h" #include "php_random.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" /* @@ -280,7 +279,7 @@ PHP_METHOD(Random_Engine_Mt19937, __construct) if (seed_is_null) { /* MT19937 has a very large state, uses CSPRNG for seeding only */ if (php_random_bytes_throw(&seed, sizeof(zend_long)) == FAILURE) { - zend_throw_exception(spl_ce_RuntimeException, "Failed to generate a random seed", 0); + zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0); RETURN_THROWS(); } } diff --git a/ext/random/engine_pcgoneseq128xslrr64.c b/ext/random/engine_pcgoneseq128xslrr64.c index 40e9e3d653252..41bbdad98a422 100644 --- a/ext/random/engine_pcgoneseq128xslrr64.c +++ b/ext/random/engine_pcgoneseq128xslrr64.c @@ -23,7 +23,6 @@ #include "php.h" #include "php_random.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" static inline void step(php_random_status_state_pcgoneseq128xslrr64 *s) @@ -149,7 +148,7 @@ PHP_METHOD(Random_Engine_PcgOneseq128XslRr64, __construct) if (seed_is_null) { if (php_random_bytes_throw(&state->state, sizeof(php_random_uint128_t)) == FAILURE) { - zend_throw_exception(spl_ce_RuntimeException, "Failed to generate a random seed", 0); + zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0); RETURN_THROWS(); } } else { diff --git a/ext/random/engine_xoshiro256starstar.c b/ext/random/engine_xoshiro256starstar.c index f964146b2e68a..1e48f3470da13 100644 --- a/ext/random/engine_xoshiro256starstar.c +++ b/ext/random/engine_xoshiro256starstar.c @@ -24,7 +24,6 @@ #include "php.h" #include "php_random.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" static inline uint64_t splitmix64(uint64_t *seed) @@ -207,7 +206,7 @@ PHP_METHOD(Random_Engine_Xoshiro256StarStar, __construct) if (seed_is_null) { if (php_random_bytes_throw(&state->state, 32) == FAILURE) { - zend_throw_exception(spl_ce_RuntimeException, "Failed to generate a random seed", 0); + zend_throw_exception(random_ce_Random_RandomException, "Failed to generate a random seed", 0); RETURN_THROWS(); } } else { From e304d97fed6b0d2e045af7bc4f5f6b5868e51144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 1 Aug 2022 20:35:45 +0200 Subject: [PATCH 4/9] Throw RandomException when CSPRNG fails --- ext/random/random.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/random/random.c b/ext/random/random.c index f2876024ad4d1..73619d9e80cf7 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -475,7 +475,7 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) /* Defer to CryptGenRandom on Windows */ if (php_win32_get_random_bytes(bytes, size) == FAILURE) { if (should_throw) { - zend_throw_exception(zend_ce_exception, "Failed to retrieve randomness from the operating system (BCryptGenRandom)", 0); + zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (BCryptGenRandom)", 0); } return FAILURE; } @@ -488,7 +488,7 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) */ if (CCRandomGenerateBytes(bytes, size) != kCCSuccess) { if (should_throw) { - zend_throw_exception(zend_ce_exception, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)", 0); + zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)", 0); } return FAILURE; } @@ -553,9 +553,9 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) if (fd < 0) { if (should_throw) { if (errno != 0) { - zend_throw_exception_ex(zend_ce_exception, 0, "Cannot open /dev/urandom: %s", strerror(errno)); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom: %s", strerror(errno)); } else { - zend_throw_exception_ex(zend_ce_exception, 0, "Cannot open /dev/urandom"); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom"); } } return FAILURE; @@ -573,9 +573,9 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) close(fd); if (should_throw) { if (errno != 0) { - zend_throw_exception_ex(zend_ce_exception, 0, "Error reading from /dev/urandom: %s", strerror(errno)); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom: %s", strerror(errno)); } else { - zend_throw_exception_ex(zend_ce_exception, 0, "Error reading from /dev/urandom"); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom"); } } return FAILURE; @@ -594,9 +594,9 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) if (read_bytes < size) { if (should_throw) { if (errno != 0) { - zend_throw_exception_ex(zend_ce_exception, 0, "Could not gather sufficient random data: %s", strerror(errno)); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data: %s", strerror(errno)); } else { - zend_throw_exception_ex(zend_ce_exception, 0, "Could not gather sufficient random data"); + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data"); } } return FAILURE; From c4e0e36a6ca7e6155bf1bee2d94ce58c1378d1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 2 Aug 2022 17:51:50 +0200 Subject: [PATCH 5/9] Remove unused include from ext/random/engine_combinedlcg.c --- ext/random/engine_combinedlcg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/random/engine_combinedlcg.c b/ext/random/engine_combinedlcg.c index 527ff168e8ccf..2fa26860ec2ce 100644 --- a/ext/random/engine_combinedlcg.c +++ b/ext/random/engine_combinedlcg.c @@ -22,7 +22,6 @@ #include "php.h" #include "php_random.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" /* From 0a321eb94148eb0f20b149402a59e7c7d3f18a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 2 Aug 2022 17:52:13 +0200 Subject: [PATCH 6/9] Remove unused include from ext/random/engine_secure.c --- ext/random/engine_secure.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/random/engine_secure.c b/ext/random/engine_secure.c index d6c9faa067679..8cc5d9cb6f249 100644 --- a/ext/random/engine_secure.c +++ b/ext/random/engine_secure.c @@ -22,7 +22,6 @@ #include "php.h" #include "php_random.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" static uint64_t generate(php_random_status *status) From 75db12abbb6a1c1ef2568cdfb4b15dc8abac3da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 2 Aug 2022 17:52:41 +0200 Subject: [PATCH 7/9] Remove unused include from ext/random/random.c --- ext/random/random.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/random/random.c b/ext/random/random.c index 73619d9e80cf7..ba25e5c04f041 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -26,7 +26,6 @@ #include "php.h" -#include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" #include "php_random.h" From ff4ea322d780334de237a147ee451148db0c3cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 1 Aug 2022 21:02:56 +0200 Subject: [PATCH 8/9] [ci skip] Add ext/random Exception hierarchy to NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 613470d2a0e4a..934dc2791097b 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ PHP NEWS PcgOneseq128XslRr64::__construct()). (timwolla) . Removed redundant RuntimeExceptions from Randomizer methods. The exceptions thrown by the engines will be exposed directly. (timwolla) + . Added extension specific Exceptions/Errors (RandomException, RandomError, + BrokenRandomEngineError). (timwolla) 04 Aug 2022, PHP 8.2.0beta2 From 2b9c00200096c241ee40e736659a0f365d458adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 2 Aug 2022 18:06:50 +0200 Subject: [PATCH 9/9] [ci skip] Add the change of Exception for random_(int|bytes) to UPGRADING --- UPGRADING | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UPGRADING b/UPGRADING index 75f65abdd3665..09823f01fecfb 100644 --- a/UPGRADING +++ b/UPGRADING @@ -201,6 +201,10 @@ PHP 8.2 UPGRADE NOTES dba_fetch(string|array $key, $skip, $dba): string|false is still accepted, but it is recommended to use the new standard variant. +- Random + . random_bytes() and random_int() now throw \Random\RandomException on CSPRNG failure. + Previously a plain \Exception was thrown. + - SPL . The $iterator parameter of iterator_to_array() and iterator_count() is widened to iterable from Iterator, allowing arrays to be passed.