Subject: lib/25367: arc4random state is shared across forks
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <apb@cequrux.com>
List: netbsd-bugs
Date: 04/28/2004 17:31:01
>Number: 25367
>Category: lib
>Synopsis: arc4random state is shared across forks
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Apr 28 15:32:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator: Alan Barrett
>Release: NetBSD 1.6ZK
>Organization:
Not much
>Environment:
System: NetBSD 1.6ZK
Architecture: i386
Machine: i386
>Description:
arc4random() returns the same stream of values in all children of
a common parent process. This violates the principle of least
astonishment.
>How-To-Repeat:
sh$ ./test_arc4random
top-level process 28045: toprand=0xb70ed1c5
child process 22848: childrand[0]=0x617d6e3e
child process 22848: childrand[1]=0xd9af1d32
child process 14579: childrand[0]=0x617d6e3e
child process 14579: childrand[1]=0xd9af1d32
child process 5365: childrand[0]=0x617d6e3e
child process 5365: childrand[1]=0xd9af1d32
child process 17748: childrand[0]=0x617d6e3e
child process 17748: childrand[1]=0xd9af1d32
child process 17560: childrand[0]=0x617d6e3e
child process 17560: childrand[1]=0xd9af1d32
sh$ cat ./test_arc4random.c
#include <unistd.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/wait.h>
#define CHILDREN 5 /* number of children to run */
#define RAND_PER_CHILD 2 /* number of arc4random() calls per child */
int
main(int argc, char **argv)
{
int nchildren = 0;
int nerrors = 0;
pid_t toppid = getpid();
u_int32_t toprand;
/* initialise arc4random()'s private data in the parent */
toprand = arc4random();
printf("top-level process %lu: toprand=0x%" PRIx32 "\n",
(unsigned long)toppid, toprand);
fflush(stdout);
for (nerrors = nchildren = 0; nchildren < CHILDREN && nerrors <= 10; ) {
pid_t forkresult = fork();
if (forkresult < 0) {
nerrors++;
sleep(1);
} else if (forkresult == 0) {
pid_t childpid = getpid();
u_int32_t childrand;
int i;
for (i = 0; i < RAND_PER_CHILD; i++) {
childrand = arc4random();
printf("child process %lu: childrand[%d]=0x%" PRIx32 "\n",
(unsigned long)childpid, i, childrand);
}
fflush(stdout);
exit(0);
} else {
nchildren++;
(void) wait(NULL);
}
}
exit(0);
}
>Fix:
Somehow make arc4random re-seed itself after a fork().
Since there seems to be no fork_hooks infrastructure, I suppose we could
save the pid somewhere and re-seed if getpid() says the pid has changed.
>Release-Note:
>Audit-Trail:
>Unformatted: