aboutsummaryrefslogtreecommitdiff
path: root/src/random.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2017-02-22 08:51:26 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2017-02-22 08:51:26 +0100
commit7e6dcd9995b99e894b8017f09016c405b066ca36 (patch)
tree4a7b37b6c622abe872d141918375cb90d378f4c1 /src/random.cpp
parent7cad84929907c4294f07377453aa77887911b486 (diff)
downloadbitcoin-7e6dcd9995b99e894b8017f09016c405b066ca36.tar.xz
random: Add fallback if getrandom syscall not available
If the code was compiled with newer (>=3.17) kernel headers but executed on a system without the system call, every use of random would crash the program. Add a fallback for that case.
Diffstat (limited to 'src/random.cpp')
-rw-r--r--src/random.cpp49
1 files changed, 34 insertions, 15 deletions
diff --git a/src/random.cpp b/src/random.cpp
index 7fdada7525..8284f457c9 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -102,6 +102,28 @@ static void RandAddSeedPerfmon()
#endif
}
+#ifndef WIN32
+/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
+ * compatible way to get cryptographic randomness on UNIX-ish platforms.
+ */
+void GetDevURandom(unsigned char *ent32)
+{
+ int f = open("/dev/urandom", O_RDONLY);
+ if (f == -1) {
+ RandFailure();
+ }
+ int have = 0;
+ do {
+ ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
+ if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
+ RandFailure();
+ }
+ have += n;
+ } while (have < NUM_OS_RANDOM_BYTES);
+ close(f);
+}
+#endif
+
/** Get 32 bytes of system entropy. */
void GetOSRand(unsigned char *ent32)
{
@@ -122,8 +144,17 @@ void GetOSRand(unsigned char *ent32)
* will always return as many bytes as requested and will not be
* interrupted by signals."
*/
- if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
- RandFailure();
+ int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
+ if (rv != NUM_OS_RANDOM_BYTES) {
+ if (rv < 0 && errno == ENOSYS) {
+ /* Fallback for kernel <3.17: the return value will be -1 and errno
+ * ENOSYS if the syscall is not available, in that case fall back
+ * to /dev/urandom.
+ */
+ GetDevURandom(ent32);
+ } else {
+ RandFailure();
+ }
}
#elif defined(HAVE_GETENTROPY)
/* On OpenBSD this can return up to 256 bytes of entropy, will return an
@@ -150,19 +181,7 @@ void GetOSRand(unsigned char *ent32)
/* Fall back to /dev/urandom if there is no specific method implemented to
* get system entropy for this OS.
*/
- int f = open("/dev/urandom", O_RDONLY);
- if (f == -1) {
- RandFailure();
- }
- int have = 0;
- do {
- ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
- if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
- RandFailure();
- }
- have += n;
- } while (have < NUM_OS_RANDOM_BYTES);
- close(f);
+ GetDevURandom(ent32);
#endif
}