Module Name:    src
Committed By:   tls
Date:           Sat May 19 16:00:41 UTC 2012

Modified Files:
        src/sys/dev: rndpseudo.c
        src/sys/kern: subr_cprng.c

Log Message:
Fix two problems that could cause /dev/random to not wake up readers when 
entropy became available.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/rndpseudo.c
cvs rdiff -u -r1.8 -r1.9 src/sys/kern/subr_cprng.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/dev/rndpseudo.c
diff -u src/sys/dev/rndpseudo.c:1.9 src/sys/dev/rndpseudo.c:1.10
--- src/sys/dev/rndpseudo.c:1.9	Fri Apr 20 21:57:33 2012
+++ src/sys/dev/rndpseudo.c	Sat May 19 16:00:41 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: rndpseudo.c,v 1.9 2012/04/20 21:57:33 tls Exp $	*/
+/*	$NetBSD: rndpseudo.c,v 1.10 2012/05/19 16:00:41 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.9 2012/04/20 21:57:33 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.10 2012/05/19 16:00:41 tls Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -309,14 +309,23 @@ rnd_read(struct file * fp, off_t *offp, 
 		/* XXX is this _really_ what's wanted? */
 		if (ctx->hard) {
 			n = MIN(want, strength - ctx->bytesonkey);
-			ctx->bytesonkey += n;
+			if (n < 1) {
+			    cprng_strong_deplete(cprng);
+			    n = MIN(want, strength);
+			    ctx->bytesonkey = 0;
+			    membar_producer();
+			}
 		} else {
 			n = want;
 		}
 
 		nread = cprng_strong(cprng, bf, n,
 				     (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
-		if (nread != n) {
+
+		if (ctx->hard && nread > 0) {
+			atomic_add_int(&ctx->bytesonkey, nread);
+		}
+		if (nread < 1) {
 			if (fp->f_flag & FNONBLOCK) {
 				ret = EWOULDBLOCK;
 			} else {
@@ -331,12 +340,6 @@ rnd_read(struct file * fp, off_t *offp, 
 		}
 	}
 out:
-	if (ctx->bytesonkey >= strength) {
-		/* Force reseed of underlying DRBG (prediction resistance) */
-		cprng_strong_deplete(cprng);
-		ctx->bytesonkey = 0;
-	}
-
 	pool_cache_put(rp_pc, bf);
 	return (ret);
 }

Index: src/sys/kern/subr_cprng.c
diff -u src/sys/kern/subr_cprng.c:1.8 src/sys/kern/subr_cprng.c:1.9
--- src/sys/kern/subr_cprng.c:1.8	Tue Apr 17 02:50:39 2012
+++ src/sys/kern/subr_cprng.c	Sat May 19 16:00:41 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_cprng.c,v 1.8 2012/04/17 02:50:39 tls Exp $ */
+/*	$NetBSD: subr_cprng.c,v 1.9 2012/05/19 16:00:41 tls Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
 
 #include <sys/cprng.h>
 
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.8 2012/04/17 02:50:39 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.9 2012/05/19 16:00:41 tls Exp $");
 
 void
 cprng_init(void)
@@ -144,6 +144,9 @@ cprng_strong_reseed(void *const arg)
 #ifdef RND_VERBOSE
 	    printf("cprng: sink %s cprng busy, no reseed\n", c->reseed.name);
 #endif
+	    if (c->flags & CPRNG_USE_CV) {	/* XXX if flags change? */
+        	cv_broadcast(&c->cv);
+	    }
 	    return;
 	}
 
@@ -240,23 +243,32 @@ cprng_strong(cprng_strong_t *const c, vo
 				      "failed.", c->name);
 			}
 		} else {
-			if (!(flags & FNONBLOCK) && 
-			     (c->flags & CPRNG_USE_CV)) {
-				int wr;
+			int wr;
 
+			do {
 				cprng_strong_sched_reseed(c);
-				do {
-					wr = cv_wait_sig(&c->cv, &c->mtx);
-					if (wr == ERESTART) {
-						mutex_exit(&c->mtx);
-						return 0;
-					}
-				} while (nist_ctr_drbg_generate(&c->drbg, p,
-								len, &cc,
-								sizeof(cc)));
-			} else {
-				len = 0;
-			}
+				if ((flags & FNONBLOCK) ||
+				    !(c->flags & CPRNG_USE_CV)) {
+					len = 0;
+					break;
+				}
+			/*
+			 * XXX There's a race with the cv_broadcast
+			 * XXX in cprng_strong_sched_reseed, because
+			 * XXX of the use of tryenter in that function.
+			 * XXX This "timedwait" hack works around it,
+			 * XXX at the expense of occasionaly polling
+			 * XXX for success on a /dev/random rekey.
+			 */
+				wr = cv_timedwait_sig(&c->cv, &c->mtx,
+						      mstohz(100));
+				if (wr == ERESTART) {
+					mutex_exit(&c->mtx);
+					return 0;
+				}
+			} while (nist_ctr_drbg_generate(&c->drbg, p,
+							len, &cc,
+							sizeof(cc)));
 		}
 	}
 

Reply via email to