mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
random: Make php_random_bytes() useable early during engine startup (#14291)
php_random_bytes() can now be used before RANDOM_G() is initialized
This commit is contained in:
parent
c7bdf30daa
commit
44c199ce6b
5 changed files with 81 additions and 48 deletions
|
@ -269,6 +269,16 @@ char *alloca();
|
|||
# define ZEND_ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
|
||||
#if ZEND_GCC_VERSION >= 3003 || __has_attribute(nonnull)
|
||||
/* All pointer arguments must be non-null */
|
||||
# define ZEND_ATTRIBUTE_NONNULL __attribute__((nonnull))
|
||||
/* Specified arguments must be non-null (1-based) */
|
||||
# define ZEND_ATTRIBUTE_NONNULL_ARGS(...) __attribute__((nonnull(__VA_ARGS__)))
|
||||
#else
|
||||
# define ZEND_ATTRIBUTE_NONNULL
|
||||
# define ZEND_ATTRIBUTE_NONNULL_ARGS(...)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ZEND_GCC_VERSION >= 4003
|
||||
# define ZEND_COLD __attribute__((cold))
|
||||
# ifdef __OPTIMIZE__
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "php.h"
|
||||
|
||||
#include "Zend/zend_exceptions.h"
|
||||
#include "Zend/zend_atomic.h"
|
||||
|
||||
#include "php_random.h"
|
||||
#include "php_random_csprng.h"
|
||||
|
@ -61,14 +62,16 @@
|
|||
# include <sanitizer/msan_interface.h>
|
||||
#endif
|
||||
|
||||
PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
||||
#ifndef PHP_WIN32
|
||||
static zend_atomic_int random_fd = ZEND_ATOMIC_INT_INITIALIZER(-1);
|
||||
#endif
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes_ex(void *bytes, size_t size, char *errstr, size_t errstr_size)
|
||||
{
|
||||
#ifdef PHP_WIN32
|
||||
/* Defer to CryptGenRandom on Windows */
|
||||
if (php_win32_get_random_bytes(bytes, size) == FAILURE) {
|
||||
if (should_throw) {
|
||||
zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (BCryptGenRandom)", 0);
|
||||
}
|
||||
snprintf(errstr, errstr_size, "Failed to retrieve randomness from the operating system (BCryptGenRandom)");
|
||||
return FAILURE;
|
||||
}
|
||||
#elif HAVE_COMMONCRYPTO_COMMONRANDOM_H
|
||||
|
@ -79,9 +82,7 @@ PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
|||
* the vast majority of the time, it works fine ; but better make sure we catch failures
|
||||
*/
|
||||
if (CCRandomGenerateBytes(bytes, size) != kCCSuccess) {
|
||||
if (should_throw) {
|
||||
zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)", 0);
|
||||
}
|
||||
snprintf(errstr, errstr_size, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)");
|
||||
return FAILURE;
|
||||
}
|
||||
#elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001 && __NetBSD_Version__ < 1000000000) || \
|
||||
|
@ -147,19 +148,17 @@ PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
|||
}
|
||||
# endif
|
||||
if (read_bytes < size) {
|
||||
int fd = RANDOM_G(random_fd);
|
||||
int fd = zend_atomic_int_load_ex(&random_fd);
|
||||
struct stat st;
|
||||
|
||||
if (fd < 0) {
|
||||
errno = 0;
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (should_throw) {
|
||||
if (errno != 0) {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom: %s", strerror(errno));
|
||||
} else {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom");
|
||||
}
|
||||
if (errno != 0) {
|
||||
snprintf(errstr, errstr_size, "Cannot open /dev/urandom: %s", strerror(errno));
|
||||
} else {
|
||||
snprintf(errstr, errstr_size, "Cannot open /dev/urandom");
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
@ -174,16 +173,19 @@ PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
|||
# endif
|
||||
) {
|
||||
close(fd);
|
||||
if (should_throw) {
|
||||
if (errno != 0) {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom: %s", strerror(errno));
|
||||
} else {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom");
|
||||
}
|
||||
if (errno != 0) {
|
||||
snprintf(errstr, errstr_size, "Error reading from /dev/urandom: %s", strerror(errno));
|
||||
} else {
|
||||
snprintf(errstr, errstr_size, "Error reading from /dev/urandom");
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
RANDOM_G(random_fd) = fd;
|
||||
int expected = -1;
|
||||
if (!zend_atomic_int_compare_exchange_ex(&random_fd, &expected, fd)) {
|
||||
close(fd);
|
||||
/* expected is now the actual value of random_fd */
|
||||
fd = expected;
|
||||
}
|
||||
}
|
||||
|
||||
read_bytes = 0;
|
||||
|
@ -192,12 +194,10 @@ PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
|||
ssize_t n = read(fd, bytes + read_bytes, size - read_bytes);
|
||||
|
||||
if (n <= 0) {
|
||||
if (should_throw) {
|
||||
if (errno != 0) {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data: %s", strerror(errno));
|
||||
} else {
|
||||
zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data");
|
||||
}
|
||||
if (errno != 0) {
|
||||
snprintf(errstr, errstr_size, "Could not gather sufficient random data: %s", strerror(errno));
|
||||
} else {
|
||||
snprintf(errstr, errstr_size, "Could not gather sufficient random data");
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
@ -210,7 +210,19 @@ PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw)
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
|
||||
{
|
||||
char errstr[128];
|
||||
zend_result result = php_random_bytes_ex(bytes, size, errstr, sizeof(errstr));
|
||||
|
||||
if (result == FAILURE && should_throw) {
|
||||
zend_throw_exception(random_ce_Random_RandomException, errstr, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw)
|
||||
{
|
||||
zend_ulong umax;
|
||||
zend_ulong trial;
|
||||
|
@ -251,3 +263,13 @@ PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *resul
|
|||
*result = (zend_long)((trial % umax) + min);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PHPAPI void php_random_csprng_shutdown(void)
|
||||
{
|
||||
#ifndef PHP_WIN32
|
||||
int fd = zend_atomic_int_exchange(&random_fd, -1);
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -195,7 +195,6 @@ PHP_MSHUTDOWN_FUNCTION(random);
|
|||
PHP_RINIT_FUNCTION(random);
|
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(random)
|
||||
int random_fd;
|
||||
bool combined_lcg_seeded;
|
||||
bool mt19937_seeded;
|
||||
bool fallback_seed_initialized;
|
||||
|
|
|
@ -20,27 +20,31 @@
|
|||
|
||||
# include "php.h"
|
||||
|
||||
PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw);
|
||||
PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw);
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw);
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes_ex(void *bytes, size_t size, char *errstr, size_t errstr_size);
|
||||
|
||||
static inline zend_result php_random_bytes_throw(void *bytes, size_t size)
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw);
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL static inline zend_result php_random_bytes_throw(void *bytes, size_t size)
|
||||
{
|
||||
return php_random_bytes(bytes, size, true);
|
||||
}
|
||||
|
||||
static inline zend_result php_random_bytes_silent(void *bytes, size_t size)
|
||||
ZEND_ATTRIBUTE_NONNULL static inline zend_result php_random_bytes_silent(void *bytes, size_t size)
|
||||
{
|
||||
return php_random_bytes(bytes, size, false);
|
||||
}
|
||||
|
||||
static inline zend_result php_random_int_throw(zend_long min, zend_long max, zend_long *result)
|
||||
ZEND_ATTRIBUTE_NONNULL static inline zend_result php_random_int_throw(zend_long min, zend_long max, zend_long *result)
|
||||
{
|
||||
return php_random_int(min, max, result, true);
|
||||
}
|
||||
|
||||
static inline zend_result php_random_int_silent(zend_long min, zend_long max, zend_long *result)
|
||||
ZEND_ATTRIBUTE_NONNULL static inline zend_result php_random_int_silent(zend_long min, zend_long max, zend_long *result)
|
||||
{
|
||||
return php_random_int(min, max, result, false);
|
||||
}
|
||||
|
||||
PHPAPI void php_random_csprng_shutdown(void);
|
||||
|
||||
#endif /* PHP_RANDOM_CSPRNG_H */
|
||||
|
|
|
@ -683,21 +683,10 @@ PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
|||
/* {{{ PHP_GINIT_FUNCTION */
|
||||
static PHP_GINIT_FUNCTION(random)
|
||||
{
|
||||
random_globals->random_fd = -1;
|
||||
random_globals->fallback_seed_initialized = false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_GSHUTDOWN_FUNCTION */
|
||||
static PHP_GSHUTDOWN_FUNCTION(random)
|
||||
{
|
||||
if (random_globals->random_fd >= 0) {
|
||||
close(random_globals->random_fd);
|
||||
random_globals->random_fd = -1;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION */
|
||||
PHP_MINIT_FUNCTION(random)
|
||||
{
|
||||
|
@ -766,6 +755,15 @@ PHP_MINIT_FUNCTION(random)
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MSHUTDOWN_FUNCTION */
|
||||
PHP_MSHUTDOWN_FUNCTION(random)
|
||||
{
|
||||
php_random_csprng_shutdown();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_RINIT_FUNCTION */
|
||||
PHP_RINIT_FUNCTION(random)
|
||||
{
|
||||
|
@ -782,14 +780,14 @@ zend_module_entry random_module_entry = {
|
|||
"random", /* Extension name */
|
||||
ext_functions, /* zend_function_entry */
|
||||
PHP_MINIT(random), /* PHP_MINIT - Module initialization */
|
||||
NULL, /* PHP_MSHUTDOWN - Module shutdown */
|
||||
PHP_MSHUTDOWN(random), /* PHP_MSHUTDOWN - Module shutdown */
|
||||
PHP_RINIT(random), /* PHP_RINIT - Request initialization */
|
||||
NULL, /* PHP_RSHUTDOWN - Request shutdown */
|
||||
NULL, /* PHP_MINFO - Module info */
|
||||
PHP_VERSION, /* Version */
|
||||
PHP_MODULE_GLOBALS(random), /* ZTS Module globals */
|
||||
PHP_GINIT(random), /* PHP_GINIT - Global initialization */
|
||||
PHP_GSHUTDOWN(random), /* PHP_GSHUTDOWN - Global shutdown */
|
||||
NULL, /* PHP_GSHUTDOWN - Global shutdown */
|
||||
NULL, /* Post deactivate */
|
||||
STANDARD_MODULE_PROPERTIES_EX
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue