Skip to content

Commit fc9050c

Browse files
authored
Merge pull request #280 from masahisak/fix_dev_urandom
random-util.c: sync dev_urandom implementation to systemd-udev
2 parents e98a667 + a49a3aa commit fc9050c

2 files changed

Lines changed: 35 additions & 39 deletions

File tree

src/shared/missing.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
7979
#define GRND_RANDOM 0x0002
8080
#endif
8181

82+
#ifndef GRND_INSECURE
83+
#define GRND_INSECURE 0x0004
84+
#endif
85+
8286
#ifndef BTRFS_IOCTL_MAGIC
8387
#define BTRFS_IOCTL_MAGIC 0x94
8488
#endif

src/shared/random-util.c

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,45 +31,37 @@
3131
#include "util.h"
3232

3333
int dev_urandom(void *p, size_t n) {
34-
static int have_syscall = -1;
35-
36-
_cleanup_close_ int fd = -1;
37-
int r;
38-
39-
/* Gathers some randomness from the kernel. This call will
40-
* never block, and will always return some data from the
41-
* kernel, regardless if the random pool is fully initialized
42-
* or not. It thus makes no guarantee for the quality of the
43-
* returned entropy, but is good enough for or usual usecases
44-
* of seeding the hash functions for hashtable */
45-
46-
/* Use the getrandom() syscall unless we know we don't have
47-
* it, or when the requested size is too large for it. */
48-
if (have_syscall != 0 || (size_t) (int) n != n) {
49-
r = getrandom(p, n, GRND_NONBLOCK);
50-
if (r == (int) n) {
51-
have_syscall = true;
52-
return 0;
53-
}
54-
55-
if (r < 0) {
56-
if (errno == ENOSYS)
57-
/* we lack the syscall, continue with
58-
* reading from /dev/urandom */
59-
have_syscall = false;
60-
else if (errno == EAGAIN)
61-
/* not enough entropy for now. Let's
62-
* remember to use the syscall the
63-
* next time, again, but also read
64-
* from /dev/urandom for now, which
65-
* doesn't care about the current
66-
* amount of entropy. */
67-
have_syscall = true;
68-
else
69-
return -errno;
70-
} else
71-
/* too short read? */
72-
return -ENODATA;
34+
static bool have_getrandom = true, have_grndinsecure = true;
35+
_cleanup_close_ int fd = -EBADF;
36+
37+
if (n == 0)
38+
return 0;
39+
40+
for (;;) {
41+
ssize_t l;
42+
43+
if (!have_getrandom)
44+
break;
45+
46+
l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
47+
if (l > 0) {
48+
if ((size_t) l == n)
49+
return 0; /* Done reading, success. */
50+
p = (uint8_t *) p + l;
51+
n -= l;
52+
continue; /* Interrupted by a signal; keep going. */
53+
} else if (l == 0)
54+
break; /* Weird, so fallback to /dev/urandom. */
55+
else if (errno == ENOSYS) {
56+
have_getrandom = false;
57+
break; /* No syscall, so fallback to /dev/urandom. */
58+
} else if (errno == EINVAL && have_grndinsecure) {
59+
have_grndinsecure = false;
60+
continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
61+
} else if (errno == EAGAIN && !have_grndinsecure)
62+
break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
63+
64+
break; /* Unexpected, so just give up and fallback to /dev/urandom. */
7365
}
7466

7567
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);

0 commit comments

Comments
 (0)