X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=0f44eb5afe7a8c57c8985a8397747339d4a11c75;hb=1caa12d0a8a818d5f2545aab809b3fdfec73871d;hp=ceafba86af4201dcda117aee038ffc37a44f705f;hpb=539618a0ddc2dc7f0fbe28de2ae0e07b34c81e60;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index ceafba86a..0f44eb5af 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -2470,10 +2470,17 @@ int dev_urandom(void *p, size_t n) { int r, fd; ssize_t k; - /* Use the syscall unless we know we don't have it, or when - * the requested size is too large for it. */ + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + /* Use the getrandom() syscall unless we know we don't have + * it, or when the requested size is too large for it. */ if (have_syscall != 0 || (size_t) (int) n != n) { - r = getrandom(p, n, 0); + r = getrandom(p, n, GRND_NONBLOCK); if (r == (int) n) { have_syscall = true; return 0; @@ -2481,8 +2488,17 @@ int dev_urandom(void *p, size_t n) { if (r < 0) { if (errno == ENOSYS) - /* we lack the syscall, continue with reading from /dev/urandom */ + /* we lack the syscall, continue with + * reading from /dev/urandom */ have_syscall = false; + else if (errno == EAGAIN) + /* not enough entropy for now. Let's + * remember to use the syscall the + * next time, again, but also read + * from /dev/urandom for now, which + * doesn't care about the current + * amount of entropy. */ + have_syscall = true; else return -errno; } else @@ -2505,8 +2521,36 @@ int dev_urandom(void *p, size_t n) { return 0; } -void random_bytes(void *p, size_t n) { +void initialize_srand(void) { static bool srand_called = false; + unsigned x; +#ifdef HAVE_SYS_AUXV_H + void *auxv; +#endif + + if (srand_called) + return; + + x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; +} + +void random_bytes(void *p, size_t n) { uint8_t *q; int r; @@ -2517,28 +2561,7 @@ void random_bytes(void *p, size_t n) { /* If some idiot made /dev/urandom unavailable to us, he'll * get a PRNG instead. */ - if (!srand_called) { - unsigned x = 0; - -#ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in - * auxv, so let's try to make use of that to seed the - * pseudo-random generator. It's better than - * nothing... */ - - void *auxv; - - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; -#endif - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; - } + initialize_srand(); for (q = p; q < (uint8_t*) p + n; q ++) *q = rand();