Module Name: src Committed By: riastradh Date: Sun May 10 00:08:12 UTC 2020
Modified Files: src/sys/kern: kern_entropy.c Log Message: Use a temporary pool to consolidate entropy atomically. There was a low-probability race with the entropy consolidation logic: calls to entropy_extract at the same time as consolidation is happening might witness partial contributions from the CPUs when needed=256, say 64 bits at a time. To avoid this, feed everything from the per-CPU pools into a temporary pool, and then feed the temporary pool into the global pool under the lock at the same time as we update needed. To generate a diff of this commit: cvs rdiff -u -r1.18 -r1.19 src/sys/kern/kern_entropy.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_entropy.c diff -u src/sys/kern/kern_entropy.c:1.18 src/sys/kern/kern_entropy.c:1.19 --- src/sys/kern/kern_entropy.c:1.18 Sat May 9 06:12:32 2020 +++ src/sys/kern/kern_entropy.c Sun May 10 00:08:12 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_entropy.c,v 1.18 2020/05/09 06:12:32 riastradh Exp $ */ +/* $NetBSD: kern_entropy.c,v 1.19 2020/05/10 00:08:12 riastradh Exp $ */ /*- * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -75,7 +75,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.18 2020/05/09 06:12:32 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.19 2020/05/10 00:08:12 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -984,11 +984,14 @@ entropy_do_consolidate(void) { static const struct timeval interval = {.tv_sec = 60, .tv_usec = 0}; static struct timeval lasttime; /* serialized by E->lock */ + struct entpool pool; + uint8_t buf[ENTPOOL_CAPACITY]; unsigned diff; uint64_t ticket; - /* Gather entropy on all CPUs. */ - ticket = xc_broadcast(0, &entropy_consolidate_xc, NULL, NULL); + /* Gather entropy on all CPUs into a temporary pool. */ + memset(&pool, 0, sizeof pool); + ticket = xc_broadcast(0, &entropy_consolidate_xc, &pool, NULL); xc_wait(ticket); /* Acquire the lock to notify waiters. */ @@ -1000,6 +1003,11 @@ entropy_do_consolidate(void) /* Note when we last consolidated, i.e. now. */ E->timestamp = time_uptime; + /* Mix what we gathered into the global pool. */ + entpool_extract(&pool, buf, sizeof buf); + entpool_enter(&E->pool, buf, sizeof buf); + explicit_memset(&pool, 0, sizeof pool); + /* Count the entropy that was gathered. */ diff = MIN(E->needed, E->pending); atomic_store_relaxed(&E->needed, E->needed - diff); @@ -1024,8 +1032,9 @@ entropy_do_consolidate(void) * into the global pool. */ static void -entropy_consolidate_xc(void *arg1 __unused, void *arg2 __unused) +entropy_consolidate_xc(void *vpool, void *arg2 __unused) { + struct entpool *pool = vpool; struct entropy_cpu *ec; uint8_t buf[ENTPOOL_CAPACITY]; uint32_t extra[7]; @@ -1063,15 +1072,15 @@ entropy_consolidate_xc(void *arg1 __unus /* * Copy over statistics, and enter the per-CPU extract and the - * extra timing into the global pool, under the global lock. + * extra timing into the temporary pool, under the global lock. */ mutex_enter(&E->lock); extra[i++] = entropy_timer(); - entpool_enter(&E->pool, buf, sizeof buf); + entpool_enter(pool, buf, sizeof buf); explicit_memset(buf, 0, sizeof buf); extra[i++] = entropy_timer(); KASSERT(i == __arraycount(extra)); - entpool_enter(&E->pool, extra, sizeof extra); + entpool_enter(pool, extra, sizeof extra); explicit_memset(extra, 0, sizeof extra); mutex_exit(&E->lock); }