com php-src: Fixed bug #74105: NEWS ext/standard/random.c
[email protected] (Nikita Popov)
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Commit: 513582814b0ca82d81eb6b98897d745e0f0eebf5 Author: Benjamin Robin <[email protected]> Thu, 16 Feb 2017 00:06:46 +0100 Committer: Nikita Popov <[email protected]> Fri, 17 Feb 2017 18:42:35 +0100 Parents: 61e59db99d29cd028336b66884b3a8e69b46cf71 Branches: PHP-7.0 PHP-7.1 master Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=513582814b0ca82d81eb6b98897d745e0f0eebf5 Log: Fixed bug #74105 If getrandom syscall is unavailable (ENOSYS), try to fallback on /dev/urandom. Bugs: https://bugs.php.net/74105 Changed paths: M NEWS M ext/standard/random.c Diff: diff --git a/NEWS b/NEWS index 4c73dbf..6f9c15c 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ PHP NEWS (Anatol) . Fixed bug #73118 (is_callable callable name reports misleading value for anonymous classes). (Adam Saponara) + . Fixed bug #74105 (PHP on Linux should use /dev/urandom when getrandom is + not available). (Benjamin Robin) - Streams: . Fixed bug #73496 (Invalid memory access in zend_inline_hash_func). diff --git a/ext/standard/random.c b/ext/standard/random.c index 6d314c5..1434450 100644 --- a/ext/standard/random.c +++ b/ext/standard/random.c @@ -93,14 +93,13 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw) } #elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001)) arc4random_buf(bytes, size); -#elif defined(__linux__) && defined(SYS_getrandom) - /* Linux getrandom(2) syscall */ +#else size_t read_bytes = 0; - size_t amount_to_read = 0; ssize_t n; - +#if defined(__linux__) && defined(SYS_getrandom) + /* Linux getrandom(2) syscall */ /* Keep reading until we get enough entropy */ - do { + while (read_bytes < size) { /* Below, (bytes + read_bytes) is pointer arithmetic. bytes read_bytes size @@ -110,11 +109,17 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw) amount_to_read */ - amount_to_read = size - read_bytes; + size_t amount_to_read = size - read_bytes; n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0); if (n == -1) { - if (errno == EINTR || errno == EAGAIN) { + if (errno == ENOSYS) { + /* This can happen if PHP was compiled against a newer kernel where getrandom() + * is available, but then runs on an older kernel without getrandom(). If this + * happens we simply fall back to reading from /dev/urandom. */ + ZEND_ASSERT(read_bytes == 0); + break; + } else if (errno == EINTR || errno == EAGAIN) { /* Try again */ continue; } @@ -130,53 +135,52 @@ PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw) } read_bytes += (size_t) n; - } while (read_bytes < size); -#else - int fd = RANDOM_G(fd); - struct stat st; - size_t read_bytes = 0; - ssize_t n; + } +#endif + if (read_bytes < size) { + int fd = RANDOM_G(fd); + struct stat st; - if (fd < 0) { + if (fd < 0) { #if HAVE_DEV_URANDOM - fd = open("/dev/urandom", O_RDONLY); + fd = open("/dev/urandom", O_RDONLY); #endif - if (fd < 0) { - if (should_throw) { - zend_throw_exception(zend_ce_exception, "Cannot open source device", 0); + if (fd < 0) { + if (should_throw) { + zend_throw_exception(zend_ce_exception, "Cannot open source device", 0); + } + return FAILURE; } - return FAILURE; - } - /* Does the file exist and is it a character device? */ - if (fstat(fd, &st) != 0 || + /* Does the file exist and is it a character device? */ + if (fstat(fd, &st) != 0 || # ifdef S_ISNAM - !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) + !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) # else - !S_ISCHR(st.st_mode) + !S_ISCHR(st.st_mode) # endif - ) { - close(fd); - if (should_throw) { - zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); + ) { + close(fd); + if (should_throw) { + zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); + } + return FAILURE; } - return FAILURE; + RANDOM_G(fd) = fd; } - RANDOM_G(fd) = fd; - } - while (read_bytes < size) { - n = read(fd, bytes + read_bytes, size - read_bytes); - if (n <= 0) { - break; + for (read_bytes = 0; read_bytes < size; read_bytes += (size_t) n) { + n = read(fd, bytes + read_bytes, size - read_bytes); + if (n <= 0) { + break; + } } - read_bytes += n; - } - if (read_bytes < size) { - if (should_throw) { - zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0); + if (read_bytes < size) { + if (should_throw) { + zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0); + } + return FAILURE; } - return FAILURE; } #endif