aboutsummaryrefslogtreecommitdiffstats
path: root/testing/php7.1/getrandom.patch
blob: 205a226b4e1f055a419e4bce9cd6cb8636d0549c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
--- 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