lib/randutils: improve getrandom() usage
The getrandom() does not have to return all requested bytes (missing entropy or when interrupted by signal). The current implementation in util-linux stupidly asks for all random data again, rather than only for missing bytes. The current code also does not care if we repeat our requests for ever; that's bad. This patch uses the same way as we already use for reading from /dev/urandom. It means: * repeat getrandom() for only missing bytes * limit number of unsuccessful request (16 times) * fallback to /dev/urandom on ENOSYS (old kernel or so...) Addresses: https://github.com/karelzak/util-linux/issues/496 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
60eedb0a53
commit
5264aebb4f
|
@ -95,27 +95,39 @@ int random_get_fd(void)
|
||||||
*/
|
*/
|
||||||
void random_get_bytes(void *buf, size_t nbytes)
|
void random_get_bytes(void *buf, size_t nbytes)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
unsigned char *cp = (unsigned char *)buf;
|
unsigned char *cp = (unsigned char *)buf;
|
||||||
|
size_t i, n = nbytes;
|
||||||
|
int lose_counter = 0;
|
||||||
|
|
||||||
#ifdef HAVE_GETRANDOM
|
#ifdef HAVE_GETRANDOM
|
||||||
errno = 0;
|
while (n > 0) {
|
||||||
while (getrandom(buf, nbytes, 0) != (ssize_t)nbytes) {
|
int x;
|
||||||
if (errno == EINTR)
|
|
||||||
|
errno = 0;
|
||||||
|
x = getrandom(cp, n, 0);
|
||||||
|
if (x > 0) { /* success */
|
||||||
|
n -= x;
|
||||||
|
cp += x;
|
||||||
|
lose_counter = 0;
|
||||||
|
} else if (errno == ENOSYS) { /* kernel without getrandom() */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (lose_counter++ > 16) /* entropy problem? */
|
||||||
|
break;
|
||||||
continue;
|
continue;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno == ENOSYS)
|
if (errno == ENOSYS)
|
||||||
/*
|
|
||||||
* We've been built against headers that support getrandom,
|
|
||||||
* but the running kernel does not.
|
|
||||||
* Fallback to reading from /dev/{u,}random as before
|
|
||||||
*/
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've been built against headers that support getrandom, but the
|
||||||
|
* running kernel does not. Fallback to reading from /dev/{u,}random
|
||||||
|
* as before
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
size_t n = nbytes;
|
|
||||||
int fd = random_get_fd();
|
int fd = random_get_fd();
|
||||||
int lose_counter = 0;
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
|
@ -153,7 +165,6 @@ void random_get_bytes(void *buf, size_t nbytes)
|
||||||
sizeof(ul_jrand_seed)-sizeof(unsigned short));
|
sizeof(ul_jrand_seed)-sizeof(unsigned short));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,15 +192,32 @@ const char *random_tell_source(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TEST_PROGRAM_RANDUTILS
|
#ifdef TEST_PROGRAM_RANDUTILS
|
||||||
int main(int argc __attribute__ ((__unused__)),
|
int main(int argc, char *argv[])
|
||||||
char *argv[] __attribute__ ((__unused__)))
|
|
||||||
{
|
{
|
||||||
unsigned int v, i;
|
size_t i, n;
|
||||||
|
int64_t *vp, v;
|
||||||
|
char *buf;
|
||||||
|
size_t bufsz;
|
||||||
|
|
||||||
/* generate and print 10 random numbers */
|
n = argc == 1 ? 16 : atoi(argv[1]);
|
||||||
for (i = 0; i < 10; i++) {
|
|
||||||
|
printf("Multiple random calls:\n");
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
random_get_bytes(&v, sizeof(v));
|
random_get_bytes(&v, sizeof(v));
|
||||||
printf("%d\n", v);
|
printf("#%02zu: %25ju\n", i, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
printf("One random call:\n");
|
||||||
|
bufsz = n * sizeof(*vp);
|
||||||
|
buf = malloc(bufsz);
|
||||||
|
if (!buf)
|
||||||
|
err(EXIT_FAILURE, "failed to allocate buffer");
|
||||||
|
|
||||||
|
random_get_bytes(buf, bufsz);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
vp = (int64_t *) (buf + (i * sizeof(*vp)));
|
||||||
|
printf("#%02zu: %25ju\n", i, *vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
Loading…
Reference in New Issue