bin/63287: [patch] patch to make libc arc4random reentrant

Christian S.J. Peron maneo at bsdpro.com
Mon Feb 23 13:50:11 PST 2004


>Number:         63287
>Category:       bin
>Synopsis:       [patch] patch to make libc arc4random reentrant
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 23 13:50:11 PST 2004
>Closed-Date:
>Last-Modified:
>Originator:     Christian S.J. Peron
>Release:        FreeBSD 5.2-CURRENT i386
>Organization:
>Environment:
System: FreeBSD movl 5.2-CURRENT FreeBSD 5.2-CURRENT #8: Mon Feb 2 22:04:49 GMT 2004 modulus at movl:/usr/src/sys/i386/compile/ROUTER i386

	
>Description:
	Manipulation and permutation of S-boxes in the arc4random PRNG
	is susceptible to data races during multithreaded operation.

	I have enclosed a patch which serializes S-box manipulation.

>How-To-Repeat:
	N/A
	
>Fix:


--- lib/libc/gen/arc4random.c.orig	Mon Feb 23 20:15:57 2004
+++ lib/libc/gen/arc4random.c	Mon Feb 23 21:05:12 2004
@@ -34,6 +34,9 @@
 #include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <pthread.h>
+
+#include "libc_private.h"
 #include "un-namespace.h"
 
 struct arc4_stream {
@@ -42,10 +45,27 @@
 	u_int8_t s[256];
 };
 
-static int rs_initialized;
+static pthread_mutex_t	arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+#define	RANDOMDEV	"/dev/urandom"
+#define	THREAD_LOCK()						\
+	do {							\
+		if (__isthreaded)				\
+			_pthread_mutex_lock(&arc4random_mtx);	\
+	} while (0)
+
+#define	THREAD_UNLOCK()						\
+	do {							\
+		if (__isthreaded)				\
+			_pthread_mutex_unlock(&arc4random_mtx);	\
+	} while (0)
+
 static struct arc4_stream rs;
+static int rs_initialized;
+static int rs_stired;
 
 static inline u_int8_t arc4_getbyte(struct arc4_stream *);
+static void arc4_stir(struct arc4_stream *);
 
 static inline void
 arc4_init(as)
@@ -91,11 +111,11 @@
 
 	gettimeofday(&rdat.tv, NULL);
 	rdat.pid = getpid();
-	fd = _open("/dev/urandom", O_RDONLY, 0);
+	fd = _open(RANDOMDEV, O_RDONLY, 0);
 	if (fd >= 0) {
 		(void) _read(fd, rdat.rnd, sizeof(rdat.rnd));
 		_close(fd);
-	}
+	} 
 	/* fd < 0?  Ah, what the heck. We'll just take whatever was on the
 	 * stack... */
 
@@ -142,14 +162,31 @@
 	return (val);
 }
 
-void
-arc4random_stir()
+static void
+arc4_check_init(void)
 {
 	if (!rs_initialized) {
 		arc4_init(&rs);
 		rs_initialized = 1;
 	}
+}
+
+static void
+arc4_check_stir(void)
+{
+	if (!rs_stired) {
+		arc4_stir(&rs);
+		rs_stired = 1;
+	}
+}
+
+void
+arc4random_stir()
+{
+	THREAD_LOCK();
+	arc4_check_init();
 	arc4_stir(&rs);
+	THREAD_UNLOCK();
 }
 
 void
@@ -157,18 +194,25 @@
 	u_char *dat;
 	int     datlen;
 {
-	if (!rs_initialized)
-		arc4random_stir();
+	THREAD_LOCK();
+	arc4_check_init();
+	arc4_check_stir();
 	arc4_addrandom(&rs, dat, datlen);
+	THREAD_UNLOCK();
 }
 
 u_int32_t
 arc4random()
 {
-	if (!rs_initialized)
-		arc4random_stir();
+	u_int32_t rnd;
+
+	THREAD_LOCK();
+	arc4_check_init();
+	arc4_check_stir();
+	rnd = arc4_getword(&rs);
+	THREAD_UNLOCK();
 
-	return (arc4_getword(&rs));
+	return (rnd);
 }
 
 #if 0
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list