[Dnsmasq-discuss] [PATCH 5/6] Reseed with getentropy() ~hourly to avoid low-entropy on boot
Leonid Evdokimov
leon at darkk.net.ru
Fri Oct 4 21:14:52 UTC 2024
---
src/dnsmasq.c | 10 +++++++---
src/dnsmasq.h | 1 +
src/hash-questions.c | 2 ++
src/util.c | 47 +++++++++++++++++++++++++++++++++++---------
4 files changed, 48 insertions(+), 12 deletions(-)
diff --git src/dnsmasq.c src/dnsmasq.c
index d15177f8..68c290a3 100644
--- src/dnsmasq.c
+++ src/dnsmasq.c
@@ -41,7 +41,7 @@ static void tcp_init(void);
int main (int argc, char **argv)
{
- time_t now;
+ time_t now = dnsmasq_time(), reseed_hshqs = 0, reseed_rand = 0;
struct sigaction sigact;
struct iname *if_tmp;
int piperead, pipefd[2], err_pipe[2];
@@ -101,7 +101,7 @@ int main (int argc, char **argv)
umask(022); /* known umask, create leases and pid files as 0644 */
- rand_init(); /* Must precede read_opts() */
+ rand_init(), reseed_rand = now; /* Must precede read_opts() */
read_opts(argc, argv, compile_opts);
@@ -410,7 +410,7 @@ int main (int argc, char **argv)
{
cache_init();
blockdata_init();
- hash_questions_init();
+ hash_questions_init(), reseed_hshqs = now;
/* Scale random socket pool by ftabsize, but
limit it based on available fds. */
@@ -1169,6 +1169,10 @@ int main (int argc, char **argv)
#endif
+ if (should_reseed(reseed_rand, now))
+ rand_init(), reseed_rand = now;
+ if (daemon->port != 0 && !daemon->frec_list && should_reseed(reseed_hshqs, now))
+ hash_questions_init(), reseed_hshqs = now;
/* must do this just before do_poll(), when we know no
more calls to my_syslog() can occur */
diff --git src/dnsmasq.h src/dnsmasq.h
index ff926bf8..65c458e9 100644
--- src/dnsmasq.h
+++ src/dnsmasq.h
@@ -1455,6 +1455,7 @@ void rand_init(void);
unsigned short rand16(void);
u32 rand32(void);
u64 rand64(void);
+unsigned int should_reseed(time_t last, time_t now);
int rr_on_list(struct rrlist *list, unsigned short rr);
int legal_hostname(char *name);
char *canonicalise(char *in, int *nomem);
diff --git src/hash-questions.c src/hash-questions.c
index e6304ac8..b7731c06 100644
--- src/hash-questions.c
+++ src/hash-questions.c
@@ -36,6 +36,8 @@ static unsigned char *digest;
void hash_questions_init(void)
{
+ if (ctx)
+ return;
if (!(hash = hash_find("sha256")))
die(_("Failed to create SHA-256 hash object"), NULL, EC_MISC);
diff --git src/util.c src/util.c
index 28b9c6d2..1631328c 100644
--- src/util.c
+++ src/util.c
@@ -19,6 +19,7 @@
#include "dnsmasq.h"
+#include <stdbool.h>
#ifdef HAVE_BROKEN_RTC
#include <sys/times.h>
@@ -53,27 +54,42 @@ static int getentropy_fallback(void *buffer, size_t length)
/* SURF random number generator */
-static u32 seed[32];
-static u32 in[12];
+static struct surf_state {
+ u32 seed[32];
+ u32 in[12];
+} surfst;
static u32 out[8];
static int outleft = 0;
void rand_init()
{
- if (getentropy(&seed, sizeof(seed)) + getentropy(&in, sizeof(in)) < 0)
- die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+ const u32 * const in = surfst.in;
+ const bool reseed = in[0] || in[1] || in[2] || in[3] || in[4] || in[5] ||
+ in[6] || in[7] || in[8] || in[9] || in[10] || in[11];
+ struct surf_state next;
+ const unsigned bytes = reseed ? sizeof(next.seed) : sizeof(next);
+ if (getentropy(&next, bytes) != 0)
+ {
+ if (!reseed)
+ die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+ else
+ my_syslog(LOG_ERR, _("failed to reseed the random number generator: %s"), strerror(errno));
+ }
+ _Static_assert(surfst.in == surfst.seed + countof(surfst.seed)); // No weird alignment gaps.
+ for (unsigned int i = 0; i < bytes / sizeof(next.seed[0]); i++)
+ surfst.seed[i] ^= next.seed[i];
}
static void rand_atfork(pid_t fpid)
{
- u32 next[countof(seed)];
- for (unsigned int i = 0; i < countof(seed); i++)
- next[i] = rand32();
+ struct surf_state next;
+ for (unsigned int i = 0; i < countof(next.seed); i++)
+ next.seed[i] = rand32();
// Child reseeds the state with generated values. Parent skips those values explicitly as they
// might be exposed to an external observer and used to guess something about PRNG of the child.
if (fpid == 0)
- for (unsigned int i = 0; i < countof(seed); i++)
- seed[i] ^= next[i];
+ for (unsigned int i = 0; i < countof(next.seed); i++)
+ surfst.seed[i] ^= next.seed[i];
}
#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
@@ -81,6 +97,8 @@ static void rand_atfork(pid_t fpid)
static void surf(void)
{
+ u32 * const in = surfst.in;
+ const u32 * const seed = surfst.seed;
u32 t[12]; u32 x; u32 sum = 0;
int r; int i; int loop;
@@ -124,6 +142,17 @@ u64 rand64(void)
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
}
+// Reseeding hourly to avoid low-entropy condition right after boot that is somewhat possible
+// in the embedded world. dnsmasq boxes often lack of RTC clocks and/or observe clock jumps
+// due to NTP during boot. So, "hourly" is an approximated as "once in 4096 seconds".
+unsigned int should_reseed(time_t last, time_t now)
+{
+ static u16 offset;
+ if (!offset)
+ offset = 1 + (rand16() & 4095);
+ return ((last + offset) >> 12) != ((now + offset) >> 12);
+}
+
int rr_on_list(struct rrlist *list, unsigned short rr)
{
while (list)
--
2.34.1
More information about the Dnsmasq-discuss
mailing list