From ae2868acf0acb6dd5e4426e6c109c02cd16dfec0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 22 Oct 2006 00:18:49 -0400 Subject: [PATCH] Add failsafe against duplicate UUID's generated by threaded programs Add in randomness based on Linux's thread id (gettid) to avoid race conditions when two threads try to generate uuid's at the same time. This shouldn't be an issue if /dev/urandom has proper locking and is present, so this is just a failsafe. Addresses SourceForge Bug: #1529672 Signed-off-by: "Theodore Ts'o" --- ChangeLog | 2 ++ configure | 3 ++- configure.in | 2 +- lib/uuid/ChangeLog | 9 +++++++++ lib/uuid/gen_uuid.c | 23 +++++++++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b416349..f0f5641 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2006-10-22 Theodore Tso + * configure, configure.in: Add test for jrand48() + * MCONFIG.in: Add datarootdir definition for compatibility with autoconf 2.60. diff --git a/configure b/configure index a3008ef..a0aae22 100755 --- a/configure +++ b/configure @@ -16306,7 +16306,8 @@ fi -for ac_func in chflags getrusage llseek lseek64 open64 fstat64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl + +for ac_func in chflags getrusage llseek lseek64 open64 fstat64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/configure.in b/configure.in index c78d03d..068d6ed 100644 --- a/configure.in +++ b/configure.in @@ -659,7 +659,7 @@ AC_CHECK_MEMBER(struct sockaddr.sa_len, [#include #include ]) dnl -AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 fstat64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl) +AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 fstat64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl) dnl dnl Check to see if -lsocket is required (solaris) to make something dnl that uses socket() to compile; this is needed for the UUID library diff --git a/lib/uuid/ChangeLog b/lib/uuid/ChangeLog index 1a1a9e8..d51b999 100644 --- a/lib/uuid/ChangeLog +++ b/lib/uuid/ChangeLog @@ -1,3 +1,12 @@ +2006-10-22 Theodore Tso + + * gen_uuid.c (get_random_bytes): Add in randomness based on + Linux's thread id (gettid) to avoid race conditions when + two threads try to generate uuid's at the same time. This + shouldn't be an issue if /dev/urandom has proper locking + and is present, so this is just a failsafe. (Addresses + SourceForge Bug: #1529672) + 2006-01-06 Theodore Ts'o * gen_uuid.c (get_random_fd): Set the FD_CLOEXEC flag on the file diff --git a/lib/uuid/gen_uuid.c b/lib/uuid/gen_uuid.c index 421314a..61f2805 100644 --- a/lib/uuid/gen_uuid.c +++ b/lib/uuid/gen_uuid.c @@ -69,6 +69,9 @@ #ifdef HAVE_NET_IF_DL_H #include #endif +#ifdef __linux__ +#include +#endif #include "uuidP.h" @@ -77,6 +80,11 @@ #define rand() random() #endif +#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) +#define DO_JRAND_MIX +static unsigned short jrand_seed[3]; +#endif + static int get_random_fd(void) { struct timeval tv; @@ -94,6 +102,11 @@ static int get_random_fd(void) fcntl(fd, F_SETFD, i | FD_CLOEXEC); } srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); +#ifdef DO_JRAND_MIX + jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); + jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); + jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; +#endif } /* Crank the random number generator a few times */ gettimeofday(&tv, 0); @@ -112,6 +125,7 @@ static void get_random_bytes(void *buf, int nbytes) int i, n = nbytes, fd = get_random_fd(); int lose_counter = 0; unsigned char *cp = (unsigned char *) buf; + unsigned short tmp_seed[3]; if (fd >= 0) { while (n > 0) { @@ -133,6 +147,15 @@ static void get_random_bytes(void *buf, int nbytes) */ for (cp = buf, i = 0; i < nbytes; i++) *cp++ ^= (rand() >> 7) & 0xFF; +#ifdef DO_JRAND_MIX + memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed)); + jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid); + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; + memcpy(jrand_seed, tmp_seed, + sizeof(jrand_seed)-sizeof(unsigned short)); +#endif + return; } -- 1.8.3.1