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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.