diff options
| author | Benjamin Robin <dev@benjarobin.fr> | 2017-02-16 00:06:46 +0100 | 
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2017-02-17 18:42:35 +0100 | 
| commit | 513582814b0ca82d81eb6b98897d745e0f0eebf5 (patch) | |
| tree | 11db83018a9ad905fb7ca02a2d9cedfed552fa42 | |
| parent | 61e59db99d29cd028336b66884b3a8e69b46cf71 (diff) | |
| download | php-git-513582814b0ca82d81eb6b98897d745e0f0eebf5.tar.gz | |
Fixed bug #74105
If getrandom syscall is unavailable (ENOSYS), try to fallback on
/dev/urandom.
| -rw-r--r-- | NEWS | 2 | ||||
| -rw-r--r-- | ext/standard/random.c | 86 | 
2 files changed, 47 insertions, 41 deletions
@@ -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 6d314c559e..1434450039 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  | 
