[PATCH] rand.c updates from FreeBSD RELENG_5

William M. Grim wgrim at siue.edu
Wed May 12 04:11:21 PDT 2004


Hi.

I know there is the random(3) function, which is much better at 
randomness than rand(3); however, rand(3) is ISO C, whereas random(3) is 
not, as far as I know.  Plus, many students and others tend to use 
rand(3) because its taught.

The FreeBSD team has already made some updates to rand.c; so, I did not 
need to do much to port it to DragonFly in the form of an update that 
generates some better randomness.

I have included the patch, but to see what I mean about the current 
rand(3) not being great, try this code (yes, I know, the seeding could 
have been done better):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
        int cs, i,r; /*cs == case*/
        srand(time(0));
        while(1)
        {
                cs = rand() % 2;
                if(cs)
                        printf("O");
                else
                        printf("o");
        fflush(stdout);
        }
        return EXIT_SUCCESS;
}
Notice that this code prints "OoOoOoOoOo..." in a very predictable 
manner.  Now, the update doesn't make rand(3) all that more secure, but 
it's just nice to have it be better than its current state.

Oh, and if you check revision 1.15 of the FreeBSD rand.c code (where I 
got this), you will notice I removed the '#include "namespace.h"' and 
'#include "un-namespace.h"' lines.  They wrapped around the headers to 
make them use different functions.  This doesn't seem to have any 
negative effects with the code I have, but it'd be nice if someone who 
knows more can comment.  It'd be easy to just copy those files if need 
be and re-add the lines.

If this is viable for a commit, I would appreciate it.  If not, send it 
back to me and I'll make the necessary changes.

Thanks again,
Mike
--- rand.c.orig	2004-05-11 01:34:30.000000000 -0500
+++ rand.c	2004-05-12 05:50:54.000000000 -0500
@@ -31,15 +31,18 @@
  * SUCH DAMAGE.
  *
  * Posix rand_r function added May 1999 by Wes Peters <wes at xxxxxxxxxxxx>.
- *
- * $FreeBSD: src/lib/libc/stdlib/rand.c,v 1.2.2.1 2001/03/05 11:33:57 obrien Exp $
- * $DragonFly: src/lib/libc/stdlib/rand.c,v 1.2 2003/06/17 04:26:46 dillon Exp $
- *
- * @(#)rand.c	8.1 (Berkeley) 6/14/93
  */
 
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rand.c	8.1 (Berkeley) 6/14/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+
+#include <sys/time.h>          /* for sranddev() */
 #include <sys/types.h>
+#include <fcntl.h>             /* for sranddev() */
 #include <stdlib.h>
+#include <unistd.h>            /* for sranddev() */
 
 #ifdef TEST
 #include <stdio.h>
@@ -48,7 +51,34 @@
 static int
 do_rand(unsigned long *ctx)
 {
+#ifdef  USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
 	return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
+#else   /* !USE_WEAK_SEEDING */
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ *      (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+	long hi, lo, x;
+
+	/* Can't be initialized with 0, so use another value. */
+	if (*ctx == 0)
+		*ctx = 123459876;
+	hi = *ctx / 127773;
+	lo = *ctx % 127773;
+	x = 16807 * lo - 2836 * hi;
+	if (x < 0)
+		x += 0x7fffffff;
+	return ((*ctx = x) % ((u_long)RAND_MAX + 1));
+#endif  /* !USE_WEAK_SEEDING */
 }
 
 
@@ -56,8 +86,10 @@
 rand_r(unsigned int *ctx)
 {
 	u_long val = (u_long) *ctx;
-	*ctx = do_rand(&val);
-	return (int) *ctx;
+	int r = do_rand(&val);
+
+	*ctx = (unsigned int) val;
+	return (r);
 }
 
 
@@ -66,7 +98,7 @@
 int
 rand()
 {
-	return do_rand(&next);
+	return (do_rand(&next));
 }
 
 void
@@ -76,6 +108,37 @@
 	next = seed;
 }
 
+
+/*
+ * sranddev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems.  We seed the generator using the much more
+ * secure random(4) interface.
+ */
+void
+sranddev()
+{
+	int fd, done;
+
+	done = 0;
+	fd = _open("/dev/random", O_RDONLY, 0);
+	if (fd >= 0) {
+		if (_read(fd, (void *) &next, sizeof(next)) == sizeof(next))
+			done = 1;
+		_close(fd);
+	}
+
+	if (!done) {
+		struct timeval tv;
+		unsigned long junk;
+
+		gettimeofday(&tv, NULL);
+		srand((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+	}
+}
+
+
 #ifdef TEST
 
 main()




More information about the Submit mailing list