[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