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);
 }

Reply via email to