Skip to content

Commit 7e6dcd9

Browse files
committed
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.
1 parent 7cad849 commit 7e6dcd9

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

src/random.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,28 @@ static void RandAddSeedPerfmon()
102102
#endif
103103
}
104104

105+
#ifndef WIN32
106+
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
107+
* compatible way to get cryptographic randomness on UNIX-ish platforms.
108+
*/
109+
void GetDevURandom(unsigned char *ent32)
110+
{
111+
int f = open("/dev/urandom", O_RDONLY);
112+
if (f == -1) {
113+
RandFailure();
114+
}
115+
int have = 0;
116+
do {
117+
ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
118+
if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
119+
RandFailure();
120+
}
121+
have += n;
122+
} while (have < NUM_OS_RANDOM_BYTES);
123+
close(f);
124+
}
125+
#endif
126+
105127
/** Get 32 bytes of system entropy. */
106128
void GetOSRand(unsigned char *ent32)
107129
{
@@ -122,8 +144,17 @@ void GetOSRand(unsigned char *ent32)
122144
* will always return as many bytes as requested and will not be
123145
* interrupted by signals."
124146
*/
125-
if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
126-
RandFailure();
147+
int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
148+
if (rv != NUM_OS_RANDOM_BYTES) {
149+
if (rv < 0 && errno == ENOSYS) {
150+
/* Fallback for kernel <3.17: the return value will be -1 and errno
151+
* ENOSYS if the syscall is not available, in that case fall back
152+
* to /dev/urandom.
153+
*/
154+
GetDevURandom(ent32);
155+
} else {
156+
RandFailure();
157+
}
127158
}
128159
#elif defined(HAVE_GETENTROPY)
129160
/* On OpenBSD this can return up to 256 bytes of entropy, will return an
@@ -150,19 +181,7 @@ void GetOSRand(unsigned char *ent32)
150181
/* Fall back to /dev/urandom if there is no specific method implemented to
151182
* get system entropy for this OS.
152183
*/
153-
int f = open("/dev/urandom", O_RDONLY);
154-
if (f == -1) {
155-
RandFailure();
156-
}
157-
int have = 0;
158-
do {
159-
ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
160-
if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
161-
RandFailure();
162-
}
163-
have += n;
164-
} while (have < NUM_OS_RANDOM_BYTES);
165-
close(f);
184+
GetDevURandom(ent32);
166185
#endif
167186
}
168187

0 commit comments

Comments
 (0)