Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(169315)

Side by Side Diff: Python/random.c

Issue 22181: os.urandom() should use Linux 3.17 getrandom() syscall
Patch Set: Created 4 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include "Python.h" 1 #include "Python.h"
2 #ifdef MS_WINDOWS 2 #ifdef MS_WINDOWS
3 #include <windows.h> 3 # include <windows.h>
4 #else 4 #else
5 #include <fcntl.h> 5 # include <fcntl.h>
6 #ifdef HAVE_SYS_STAT_H 6 # ifdef HAVE_SYS_STAT_H
7 #include <sys/stat.h> 7 # include <sys/stat.h>
8 #endif 8 # endif
9 # ifdef HAVE_SYS_SYSCALL_H
10 # include <sys/syscall.h>
11 # if defined(__linux__) && defined(SYS_getrandom)
12 # define HAVE_GETRANDOM
13 # endif
14 # endif
9 #endif 15 #endif
10 16
11 #ifdef Py_DEBUG 17 #ifdef Py_DEBUG
12 int _Py_HashSecret_Initialized = 0; 18 int _Py_HashSecret_Initialized = 0;
13 #else 19 #else
14 static int _Py_HashSecret_Initialized = 0; 20 static int _Py_HashSecret_Initialized = 0;
15 #endif 21 #endif
16 22
17 #ifdef MS_WINDOWS 23 #ifdef MS_WINDOWS
18 static HCRYPTPROV hCryptProv = 0; 24 static HCRYPTPROV hCryptProv = 0;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 PyErr_SetFromErrno(PyExc_OSError); 93 PyErr_SetFromErrno(PyExc_OSError);
88 return -1; 94 return -1;
89 } 95 }
90 } 96 }
91 buffer += len; 97 buffer += len;
92 size -= len; 98 size -= len;
93 } 99 }
94 return 0; 100 return 0;
95 } 101 }
96 102
97 #else 103 #else /* !HAVE_GETENTROPY */
104
105 #ifdef HAVE_GETRANDOM
106 static int
107 py_getrandom(void *buffer, Py_ssize_t size, int raise)
108 {
109 /* is getrandom() supported by the running kernel?
110 * need Linux kernel 3.17 or later */
111 static int getrandom_works = 1;
112 /* Use /dev/urandom, block if the kernel has no entropy */
113 const int flags = 0;
114 int n;
115
116 if (!getrandom_works)
117 return 0;
118
119 while (0 < size) {
120 errno = 0;
121 /* the libc doesn't expose getrandom() yet, see:
122 * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
123 n = syscall(SYS_getrandom, buffer, size, flags);
124 if (n < 0) {
125 if (errno == ENOSYS) {
126 getrandom_works = 0;
127 return 0;
128 }
129
130 if (errno == EINTR) {
131 if (PyErr_CheckSignals()) {
132 if (!raise)
133 Py_FatalError("getrandom() interrupted by a signal");
134 return -1;
135 }
136 /* retry getrandom() */
137 continue;
138 }
139
140 if (raise)
141 PyErr_SetFromErrno(PyExc_OSError);
142 else
143 Py_FatalError("getrandom() failed");
144 return -1;
145 }
146
147 buffer += n;
148 size -= n;
149 }
150 return 1;
151 }
152 #endif
153
98 static struct { 154 static struct {
99 int fd; 155 int fd;
100 dev_t st_dev; 156 dev_t st_dev;
101 ino_t st_ino; 157 ino_t st_ino;
102 } urandom_cache = { -1 }; 158 } urandom_cache = { -1 };
103 159
160
104 /* Read size bytes from /dev/urandom into buffer. 161 /* Read size bytes from /dev/urandom into buffer.
105 Call Py_FatalError() on error. */ 162 Call Py_FatalError() on error. */
106 static void 163 static void
107 dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) 164 dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
108 { 165 {
109 int fd; 166 int fd;
110 Py_ssize_t n; 167 Py_ssize_t n;
111 168
112 assert (0 < size); 169 assert (0 < size);
113 170
114 fd = _Py_open("/dev/urandom", O_RDONLY); 171 fd = _Py_open("/dev/urandom", O_RDONLY);
115 if (fd < 0) 172 if (fd < 0)
116 Py_FatalError("Failed to open /dev/urandom"); 173 Py_FatalError("Failed to open /dev/urandom");
174
175 #ifdef HAVE_GETRANDOM
176 if (py_getrandom(buffer, size, 0) == 1)
177 return;
178 /* getrandom() is not supported by the running kernel, fall back
179 * on reading /dev/urandom */
180 #endif
117 181
118 while (0 < size) 182 while (0 < size)
119 { 183 {
120 do { 184 do {
121 n = read(fd, buffer, (size_t)size); 185 n = read(fd, buffer, (size_t)size);
122 } while (n < 0 && errno == EINTR); 186 } while (n < 0 && errno == EINTR);
123 if (n <= 0) 187 if (n <= 0)
124 { 188 {
125 /* stop on error or if read(size) returned 0 */ 189 /* stop on error or if read(size) returned 0 */
126 Py_FatalError("Failed to read bytes from /dev/urandom"); 190 Py_FatalError("Failed to read bytes from /dev/urandom");
127 break; 191 break;
128 } 192 }
129 buffer += n; 193 buffer += n;
130 size -= (Py_ssize_t)n; 194 size -= (Py_ssize_t)n;
131 } 195 }
132 close(fd); 196 close(fd);
133 } 197 }
134 198
135 /* Read size bytes from /dev/urandom into buffer. 199 /* Read size bytes from /dev/urandom into buffer.
136 Return 0 on success, raise an exception and return -1 on error. */ 200 Return 0 on success, raise an exception and return -1 on error. */
137 static int 201 static int
138 dev_urandom_python(char *buffer, Py_ssize_t size) 202 dev_urandom_python(char *buffer, Py_ssize_t size)
139 { 203 {
140 int fd; 204 int fd;
141 Py_ssize_t n; 205 Py_ssize_t n;
142 struct stat st; 206 struct stat st;
207 #ifdef HAVE_GETRANDOM
208 int res;
209 #endif
143 210
144 if (size <= 0) 211 if (size <= 0)
145 return 0; 212 return 0;
146 213
214 #ifdef HAVE_GETRANDOM
215 res = py_getrandom(buffer, size, 1);
216 if (res < 0)
217 return -1;
218 if (res == 1)
219 return 0;
220 /* getrandom() is not supported by the running kernel, fall back
221 * on reading /dev/urandom */
222 #endif
223
147 if (urandom_cache.fd >= 0) { 224 if (urandom_cache.fd >= 0) {
148 /* Does the fd point to the same thing as before? (issue #21207) */ 225 /* Does the fd point to the same thing as before? (issue #21207) */
149 if (fstat(urandom_cache.fd, &st) 226 if (fstat(urandom_cache.fd, &st)
150 || st.st_dev != urandom_cache.st_dev 227 || st.st_dev != urandom_cache.st_dev
151 || st.st_ino != urandom_cache.st_ino) { 228 || st.st_ino != urandom_cache.st_ino) {
152 /* Something changed: forget the cached fd (but don't close it, 229 /* Something changed: forget the cached fd (but don't close it,
153 since it probably points to something important for some 230 since it probably points to something important for some
154 third-party code). */ 231 third-party code). */
155 urandom_cache.fd = -1; 232 urandom_cache.fd = -1;
156 } 233 }
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 if (hCryptProv) { 406 if (hCryptProv) {
330 CryptReleaseContext(hCryptProv, 0); 407 CryptReleaseContext(hCryptProv, 0);
331 hCryptProv = 0; 408 hCryptProv = 0;
332 } 409 }
333 #elif HAVE_GETENTROPY 410 #elif HAVE_GETENTROPY
334 /* nothing to clean */ 411 /* nothing to clean */
335 #else 412 #else
336 dev_urandom_close(); 413 dev_urandom_close();
337 #endif 414 #endif
338 } 415 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+