From ad0256f3543a69ff0d44bca838bade6aac04bcbd Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Sun, 8 Sep 2019 16:24:00 +0100 Subject: [PATCH] common: make seeding pseudo-random number generator easy Unify how srand() calls are done, with some care to try avoiding bad seeding with hope pseudo-random numbers are unpredictable. Acked-by: Petr Vorel Signed-off-by: Sami Kerola --- iputils_common.c | 40 ++++++++++++++++++++++++++++++++++++++++ iputils_common.h | 1 + meson.build | 1 + ninfod/ninfod_core.c | 16 +--------------- ping6_common.c | 9 +-------- rdisc.c | 6 +++--- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/iputils_common.c b/iputils_common.c index 4ea71b44..51001c0b 100644 --- a/iputils_common.c +++ b/iputils_common.c @@ -4,8 +4,13 @@ #include #include #include +#include #include +#if HAVE_GETRANDOM +# include +#endif + #ifdef HAVE_ERROR_H # include #else @@ -79,3 +84,38 @@ long strtol_or_err(char const *const str, char const *const errmesg, error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); abort(); } + +static unsigned int iputil_srand_fallback(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + return ((getpid() << 16) ^ getuid() ^ ts.tv_sec ^ ts.tv_nsec); +} + +void iputils_srand(void) +{ + unsigned int i; +#if HAVE_GETRANDOM + ssize_t ret; + + while ((ret = getrandom(&i, sizeof(i), GRND_NONBLOCK)) != sizeof(i)) { + switch(errno) { + case EINTR: + continue; + default: + i = iputil_srand_fallback(); + break; + } + } +#else + i = iputil_srand_fallback(); +#endif + srand(i); + /* Consume up to 31 random numbers */ + i = rand() & 0x1F; + while (0 < i) { + rand(); + i--; + } +} diff --git a/iputils_common.h b/iputils_common.h index 97f9572a..f8cfa383 100644 --- a/iputils_common.h +++ b/iputils_common.h @@ -59,5 +59,6 @@ extern int close_stream(FILE *stream); extern void close_stdout(void); extern long strtol_or_err(char const *const str, char const *const errmesg, const long min, const long max); +extern void iputils_srand(void); #endif /* IPUTILS_COMMON_H */ diff --git a/meson.build b/meson.build index 18790487..45f9c02b 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ conf.set('_GNU_SOURCE', 1, description : 'Enable GNU extensions on systems that # Check functions. foreach f : ''' __fpending + getrandom nanosleep '''.split() if cc.has_function(f, args : '-D_GNU_SOURCE') diff --git a/ninfod/ninfod_core.c b/ninfod/ninfod_core.c index c8c72bc1..9c4c166a 100644 --- a/ninfod/ninfod_core.c +++ b/ninfod/ninfod_core.c @@ -305,21 +305,7 @@ void init_core(int forced) DEBUG(LOG_DEBUG, "%s()\n", __func__); if (!initialized || forced) { - struct timeval tv; - unsigned int seed = 0; - pid_t pid; - - if (gettimeofday(&tv, NULL) < 0) { - DEBUG(LOG_WARNING, "%s(): failed to gettimeofday()\n", __func__); - } else { - seed = (tv.tv_usec & 0xffffffff); - } - - pid = getpid(); - seed ^= (((unsigned long)pid) & 0xffffffff); - - srand(seed); - + iputils_srand(); #if ENABLE_THREADS if (initialized) pthread_attr_destroy(&pattr); diff --git a/ping6_common.c b/ping6_common.c index 59af79ad..15c54828 100644 --- a/ping6_common.c +++ b/ping6_common.c @@ -176,14 +176,7 @@ struct { static void niquery_init_nonce(void) { #if PING6_NONCE_MEMORY - struct timeval tv; - unsigned long seed; - - seed = (unsigned long)getpid(); - if (!gettimeofday(&tv, NULL)) - seed ^= tv.tv_usec; - srand(seed); - + iputils_srand(); ni_nonce_ptr = calloc(NI_NONCE_SIZE, MAX_DUP_CHK); if (!ni_nonce_ptr) error(2, errno, "calloc"); diff --git a/rdisc.c b/rdisc.c index 2d2e8165..fb937077 100644 --- a/rdisc.c +++ b/rdisc.c @@ -419,7 +419,7 @@ int main(int argc, char **argv) #ifdef RDISC_SERVER if (responder) - srandom((int)gethostid()); + iputils_srand(); #endif if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { @@ -503,7 +503,7 @@ void timer() else left_until_advertise = min_adv_int + ((max_adv_int - min_adv_int) * - (random() % 1000)/1000); + (rand() % 1000)/1000); } else #endif if (solicit && left_until_solicit <= 0) { @@ -873,7 +873,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from) /* Restart the timer when we broadcast */ left_until_advertise = min_adv_int + ((max_adv_int - min_adv_int) - * (random() % 1000)/1000); + * (rand() % 1000)/1000); } else { sin.sin_addr.s_addr = ip->saddr; if (!is_directly_connected(sin.sin_addr)) {