Submitted By: Robert Connolly (ashes) Date: 2008-05-18 Initial Package Version: 2.5.1 Upstream Status: Rejected http://sources.redhat.com/bugzilla/show_bug.cgi?id=4417 Origin: OpenBSD src/lib/libc/crypt/arc4random.c v1.16, Alt/Owl Linux's glibc-2.5-owl-alt-res_randomid.patch, and gcc-4.1.2's libiberty/mkstemps.c. Description: This patch adds arc4random(3) to the Glibc library, to tempname.c for mktemp and friends, to res_init.c and res_mkquery.c to improve the resolver, to bindrsvprt.c to randomize the port numbers, and to strfry(3). This patch also adds the mkstemps(3) function. Both arc4random(3) and mkstemps(3) are non-standard BSD functions. They will be used by many packages if they're found, such as openntpd, bind9, perl, kde, poppler, binutils, gcc. Manual pages for arc4random() and mkstemps() are in the manual/ directory. This patch also adds the --with-prng-device configure option to let you specify /dev/urandom, /dev/erandom, or whatever. This device does not need to exist at build time. This device will be used arc4random and stack smashing protector, and /dev/urandom will be attempted at run time if the device from --with-prng-device fails to open. gettimeofday() and getpid() are always used so arc4random()'s output will still change even if the /dev/?random device is outputting non-random data. After 'make install' you will probably want to install the manual pages by hand. diff -Naur glibc-2.5.1.orig/config.h.in glibc-2.5.1/config.h.in --- glibc-2.5.1.orig/config.h.in 2007-07-12 15:07:13.000000000 +0000 +++ glibc-2.5.1/config.h.in 2008-05-18 19:53:01.000000000 +0000 @@ -209,6 +209,9 @@ /* Define if __stack_chk_guard canary should be randomized at program startup. */ #undef ENABLE_STACKGUARD_RANDOMIZE +/* Define this to the system's pseudo-random device (/dev/urandom). */ +#undef PRNG_DEV + /* */ diff -Naur glibc-2.5.1.orig/configure glibc-2.5.1/configure --- glibc-2.5.1.orig/configure 2007-07-31 13:41:51.000000000 +0000 +++ glibc-2.5.1/configure 2008-05-18 19:53:01.000000000 +0000 @@ -903,6 +903,9 @@ --with-headers=PATH location of system headers to use (for example /usr/src/linux/include) [default=compiler default] + --with-prng-device=/path/to/prng + specify the path to the system's pseudo-random + device. [default=/dev/urandom] --with-tls enable support for TLS --without-__thread do not use TLS features even when supporting them --with-cpu=CPU select code for CPU variant @@ -1513,6 +1516,19 @@ sysheaders='' fi; + +# Check whether --with-prng-device or --without-prng-device was given. +if test "${with_prng_device+set}" = set; then + withval="$with_prng_device" + prng_device=$withval +fi; +if test "$prng_device" != "/dev/urandom"; then + cat >>confdefs.h <<_ACEOF +#define PRNG_DEV "$prng_device" +_ACEOF + +fi + # Check whether --enable-sanity-checks or --disable-sanity-checks was given. if test "${enable_sanity_checks+set}" = set; then enableval="$enable_sanity_checks" diff -Naur glibc-2.5.1.orig/configure.in glibc-2.5.1/configure.in --- glibc-2.5.1.orig/configure.in 2006-07-10 21:45:29.000000000 +0000 +++ glibc-2.5.1/configure.in 2008-05-18 19:53:01.000000000 +0000 @@ -100,6 +100,16 @@ [sysheaders=$withval], [sysheaders='']) +AC_ARG_WITH([prng-device], + AC_HELP_STRING([--with-prng-device=/path/to/prng], + [specify the path to the system's + pseudo-random device. + @<:@default=/dev/urandom@:>@]), + [prng_device=$withval]) +if test "$prng_device" != "/dev/urandom"; then + AC_DEFINE_UNQUOTED(PRNG_DEV, "$prng_device") +fi + AC_ARG_ENABLE([sanity-checks], AC_HELP_STRING([--disable-sanity-checks], [really do not use threads (should not be used except in special situations) @<:@default=yes@:>@]), diff -Naur glibc-2.5.1.orig/manual/arc4random.3 glibc-2.5.1/manual/arc4random.3 --- glibc-2.5.1.orig/manual/arc4random.3 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.5.1/manual/arc4random.3 2008-05-18 19:53:01.000000000 +0000 @@ -0,0 +1,110 @@ +.\" $OpenBSD: arc4random.3,v 1.19 2005/07/17 08:50:55 jaredy Exp $ +.\" +.\" Copyright 1997 Niels Provos +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Niels Provos. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Manual page, using -mandoc macros +.\" +.Dd April 15, 1997 +.Dt ARC4RANDOM 3 +.Os +.Sh NAME +.Nm arc4random , +.Nm arc4random_stir , +.Nm arc4random_addrandom +.Nd arc4 random number generator +.Sh SYNOPSIS +.Fd #include +.Ft u_int32_t +.Fn arc4random "void" +.Ft void +.Fn arc4random_stir "void" +.Ft void +.Fn arc4random_addrandom "u_char *dat" "int datlen" +.Sh DESCRIPTION +The +.Fn arc4random +function provides a high quality 32-bit pseudo-random +number very quickly. +.Fn arc4random +seeds itself on a regular basis from the kernel strong random number +subsystem described in +.Xr random 4 . +On each call, an ARC4 generator is used to generate a new result. +The +.Fn arc4random +function uses the ARC4 cipher key stream generator, +which uses 8*8 8-bit S-Boxes. +The S-Boxes can be in about (2**1700) states. +.Pp +.Fn arc4random +fits into a middle ground not covered by other subsystems such as +the strong, slow, and resource expensive random +devices described in +.Xr random 4 +versus the fast but poor quality interfaces described in +.Xr rand 3 , +.Xr random 3 , +and +.Xr drand48 3 . +.Pp +The +.Fn arc4random_stir +function reads data from a pseudo-random device, usually +.Pa /dev/urandom, +and uses it to permute the S-Boxes via +.Fn arc4random_addrandom . +.Pp +There is no need to call +.Fn arc4random_stir +before using +.Fn arc4random , +since +.Fn arc4random +automatically initializes itself. +.Sh SEE ALSO +.Xr rand 3 , +.Xr rand48 3 , +.Xr random 3 +.Sh HISTORY +An algorithm called +.Pa RC4 +was designed by RSA Data Security, Inc. +It was considered a trade secret. +Because it was a trade secret, it obviously could not be patented. +A clone of this was posted anonymously to USENET and confirmed to +be equivalent by several sources who had access to the original cipher. +Because of the trade secret situation, RSA Data Security, Inc. can do +nothing about the release of the ARC4 algorithm. +Since +.Pa RC4 +used to be a trade secret, the cipher is now referred to as +.Pa ARC4 . +.Pp +These functions first appeared in +.Ox 2.1 . diff -Naur glibc-2.5.1.orig/manual/mkstemps.3 glibc-2.5.1/manual/mkstemps.3 --- glibc-2.5.1.orig/manual/mkstemps.3 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.5.1/manual/mkstemps.3 2008-05-18 19:53:01.000000000 +0000 @@ -0,0 +1,86 @@ +.\" $OpenBSD: mktemp.3,v 1.40 2007/05/10 22:46:36 espie Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt MKTEMP 3 +.Os +.Sh NAME +.Nm mkstemps +.Nd make temporary file name (unique) +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn mkstemps "char *template" "int suffixlen" +.Sh DESCRIPTION +.Pp +The +.Fn mkstemps +function acts the same as +.Fn mkstemp , +except it permits a suffix to exist in the template. +The template should be of the form +.Pa /tmp/tmpXXXXXXXXXXsuffix . +.Fn mkstemps +is told the length of the suffix string, i.e., +.Li strlen("suffix") . +.Pp +The +.Fn mkstemps +function return \-1 if no suitable file could be created. +If any call fails, an error code is placed in the global variable +.Va errno . +The +.Fn mkstemps +function may also set +.Va errno +to any value specified by the +.Xr open 2 +function or, +.Bl -tag -width Er +.It Bq Er EINVAL +The suffix length is longer than the template length. +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr getpid 2 , +.Xr mkdir 2 , +.Xr open 2 , +.Xr stat 2 , +.Xr tempnam 3 , +.Xr tmpfile 3 , +.Xr tmpnam 3 +.Sh HISTORY +The +.Fn mkstemps +function appeared in +.Ox 2.3 . +.Sh BUGS +The +.Fn mkstemps +function are non-standard and should not be used if portability is required. diff -Naur glibc-2.5.1.orig/misc/Makefile glibc-2.5.1/misc/Makefile --- glibc-2.5.1.orig/misc/Makefile 2007-01-12 17:20:09.000000000 +0000 +++ glibc-2.5.1/misc/Makefile 2008-05-18 19:53:01.000000000 +0000 @@ -44,7 +44,7 @@ acct chroot fsync sync fdatasync reboot \ gethostid sethostid \ revoke vhangup \ - swapon swapoff mktemp mkstemp mkstemp64 mkdtemp \ + swapon swapoff mktemp mkstemp mkstemps mkstemp64 mkdtemp \ ualarm usleep \ gtty stty \ ptrace \ diff -Naur glibc-2.5.1.orig/misc/Versions glibc-2.5.1/misc/Versions --- glibc-2.5.1.orig/misc/Versions 2005-11-11 18:58:19.000000000 +0000 +++ glibc-2.5.1/misc/Versions 2008-05-18 19:53:01.000000000 +0000 @@ -54,7 +54,7 @@ # m* madvise; mkstemp; mktemp; mlock; mlockall; mmap; mount; mprotect; msync; - munlock; munlockall; munmap; + munlock; munlockall; munmap; mkstemps; # o* openlog; diff -Naur glibc-2.5.1.orig/misc/mkstemps.c glibc-2.5.1/misc/mkstemps.c --- glibc-2.5.1.orig/misc/mkstemps.c 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.5.1/misc/mkstemps.c 2008-05-18 19:53:01.000000000 +0000 @@ -0,0 +1,116 @@ +/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc. + This file is derived from mkstemp.c from the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* From gcc-4.1.2 libiberty. This version uses arc4random(). - ashes */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* We need to provide a type for gcc_uint64_t. */ +#ifdef __GNUC__ +__extension__ typedef unsigned long long gcc_uint64_t; +#else +typedef unsigned long gcc_uint64_t; +#endif + +#ifndef TMP_MAX +#define TMP_MAX 16384 +#endif + +/* + +@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len}) + +Generate a unique temporary file name from @var{pattern}. +@var{pattern} has the form: + +@example + @var{path}/ccXXXXXX@var{suffix} +@end example + +@var{suffix_len} tells us how long @var{suffix} is (it can be zero +length). The last six characters of @var{pattern} before @var{suffix} +must be @samp{XXXXXX}; they are replaced with a string that makes the +filename unique. Returns a file descriptor open on the file for +reading and writing. + +@end deftypefn + +*/ + +int +mkstemps (char *pattern, int suffix_len) +{ + static const char letters[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static gcc_uint64_t value; + char *XXXXXX; + size_t len; + int count; + + len = strlen (pattern); + + if ((int) len < 6 + suffix_len + || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6)) + { + return -1; + } + + XXXXXX = &pattern[len - 6 - suffix_len]; + + value = arc4random(); + + for (count = 0; count < TMP_MAX; ++count) + { + gcc_uint64_t v = value; + int fd; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + fd = open (pattern, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd >= 0) + /* The file does not exist. */ + return fd; + + /* This is a random value. It is only necessary that the next + TMP_MAX values generated by adding 7777 to VALUE are different + with (module 2^32). */ + value += 7777; + } + + /* We return the null string if we can't find a unique file name. */ + pattern[0] = '\0'; + return -1; +} diff -Naur glibc-2.5.1.orig/resolv/res_init.c glibc-2.5.1/resolv/res_init.c --- glibc-2.5.1.orig/resolv/res_init.c 2006-09-04 17:59:54.000000000 +0000 +++ glibc-2.5.1/resolv/res_init.c 2008-05-18 19:53:01.000000000 +0000 @@ -537,7 +537,7 @@ u_int res_randomid(void) { - return 0xffff & __getpid(); + return arc4random() & 0xffff; } #ifdef _LIBC libc_hidden_def (__res_randomid) diff -Naur glibc-2.5.1.orig/resolv/res_mkquery.c glibc-2.5.1/resolv/res_mkquery.c --- glibc-2.5.1.orig/resolv/res_mkquery.c 2006-09-04 17:57:02.000000000 +0000 +++ glibc-2.5.1/resolv/res_mkquery.c 2008-05-18 19:53:01.000000000 +0000 @@ -120,23 +120,7 @@ return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; - /* We randomize the IDs every time. The old code just - incremented by one after the initial randomization which - still predictable if the application does multiple - requests. */ - int randombits; - do - { -#ifdef RANDOM_BITS - RANDOM_BITS (randombits); -#else - struct timeval tv; - __gettimeofday (&tv, NULL); - randombits = (tv.tv_sec << 8) ^ tv.tv_usec; -#endif - } - while ((randombits & 0xffff) == 0); - statp->id = (statp->id + randombits) & 0xffff; + statp->id = arc4random() & 0xffff; hp->id = statp->id; hp->opcode = op; hp->rd = (statp->options & RES_RECURSE) != 0; diff -Naur glibc-2.5.1.orig/scripts/data/localplt-i386-linux-gnu.data glibc-2.5.1/scripts/data/localplt-i386-linux-gnu.data --- glibc-2.5.1.orig/scripts/data/localplt-i386-linux-gnu.data 2006-01-11 21:06:19.000000000 +0000 +++ glibc-2.5.1/scripts/data/localplt-i386-linux-gnu.data 2008-05-18 19:53:01.000000000 +0000 @@ -1,7 +1,11 @@ libc.so: _Unwind_Find_FDE +libc.so: arc4random +libc.so: arc4random_stir libc.so: calloc libc.so: free libc.so: malloc libc.so: memalign +libc.so: open +libc.so: puts libc.so: realloc libm.so: matherr diff -Naur glibc-2.5.1.orig/stdlib/Makefile glibc-2.5.1/stdlib/Makefile --- glibc-2.5.1.orig/stdlib/Makefile 2007-01-12 18:23:27.000000000 +0000 +++ glibc-2.5.1/stdlib/Makefile 2008-05-18 19:53:01.000000000 +0000 @@ -30,7 +30,7 @@ routines := \ atof atoi atol atoll \ - abort \ + abort arc4random \ bsearch qsort msort \ getenv putenv setenv secure-getenv \ exit on_exit atexit cxa_atexit cxa_finalize old_atexit \ diff -Naur glibc-2.5.1.orig/stdlib/Versions glibc-2.5.1/stdlib/Versions --- glibc-2.5.1.orig/stdlib/Versions 2004-05-03 21:25:53.000000000 +0000 +++ glibc-2.5.1/stdlib/Versions 2008-05-18 19:53:01.000000000 +0000 @@ -11,6 +11,7 @@ # a* a64l; abort; abs; atexit; atof; atoi; atol; atoll; + arc4random_stir; arc4random_addrandom; arc4random; # b* bsearch; diff -Naur glibc-2.5.1.orig/stdlib/arc4random.c glibc-2.5.1/stdlib/arc4random.c --- glibc-2.5.1.orig/stdlib/arc4random.c 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.5.1/stdlib/arc4random.c 2008-05-18 19:53:01.000000000 +0000 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1996, David Mazieres + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Arc4 random number generator for OpenBSD. + * + * This code is derived from section 17.1 of Applied Cryptography, + * second edition, which describes a stream cipher allegedly + * compatible with RSA Labs "RC4" cipher (the actual description of + * which is a trade secret). The same algorithm is used as a stream + * cipher called "arcfour" in Tatu Ylonen's ssh package. + * + * Here the stream cipher has been modified always to include entropy + * when initializing the state. That makes it impossible to + * regenerate the same random sequence twice, so this can't be used + * for encryption, but will generate good random numbers. + * + * RC4 is a registered trademark of RSA Laboratories. + */ + +/* Modified by Robert Connolly for Glibc. November 23, 2007 */ + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#define inline __inline +#else +#define inline +#endif + +struct arc4_stream { + u_int8_t i; + u_int8_t j; + u_int8_t s[256]; +}; + +static int rs_initialized; +static struct arc4_stream rs; +static pid_t arc4_stir_pid; +static int arc4_count; + +static inline u_int8_t arc4_getbyte(struct arc4_stream *); + +#if defined(TEST) +u_int32_t arc4random(void); +void arc4random_stir(void); +void arc4random_addrandom(unsigned char *, int); +#endif + +#if !defined(_LIBC) +#define __getpid getpid +#define __gettimeofday gettimeofday +#define __open open +#define __read read +#define __close close +#endif + +static inline void +arc4_init(struct arc4_stream *as) +{ + int n; + + for (n = 0; n < 256; n++) + as->s[n] = n; + as->i = 0; + as->j = 0; +} + +static inline void +arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen) +{ + int n; + u_int8_t si; + + as->i--; + for (n = 0; n < 256; n++) { + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si + dat[n % datlen]); + as->s[as->i] = as->s[as->j]; + as->s[as->j] = si; + } + as->j = as->i; +} + +static void +arc4_stir(struct arc4_stream *as) +{ + int n, fd; + u_char rnd[128]; + struct timeval tv; + + /* Start with gettimeofday(). */ + if (__gettimeofday(&tv, NULL) != (-1)) { + /* + * Initialize the first element so it's hopefully not '0', + * to help out the next loop. Tossing in some prime numbers + * probably can't hurt. + */ + rnd[0] = (tv.tv_sec % 10000) * 23 + tv.tv_usec * 7 + \ + (__getpid() % 1000) * 13; + + for (n = 1; n < 127 ; n++) { + /* + * Take advantage of the stack space. Only initialize + * elements equal to '0'. This will make the rnd[] + * array much less vulnerable to timing attacks. Here + * we'll stir getpid() into the value of the previous + * elememnt. Approximately 1 in 128 elements will still + * become '0'. + */ + if (rnd[n] == 0) { + rnd[n] = ((rnd[n - 1] + n) ^ \ + ((__getpid() % 1000) * 7)); + } + } + } else { /* gettimeofday=-1? This should never happen! */ + puts ("gettimeofday() failed. Exiting from arc4random()."); + exit (1); + } + + /* Now try to get some real entropy. */ +#ifdef PRNG_DEV + fd = __open(PRNG_DEV, O_RDONLY, 0); + if (fd != -1) { + /* + * This sizeof(rnd) is divided by two so we only fill half of + * the rnd[] array. This is done in case PRNG_DEV=/dev/zero, or + * the PRNG_DEV device is seriously messed up, so half of the + * array always uses the previous routine. + */ + __read(fd, rnd, sizeof(rnd)/2); + __close(fd); + } else { /* fd=-1? Try again. */ +#endif + fd = __open("/dev/urandom", O_RDONLY, 0); + if (fd != -1) { + __read(fd, rnd, sizeof(rnd)/2); + __close(fd); + } +#ifdef PRNG_DEV + } +#endif + + arc4_stir_pid = __getpid(); + arc4_addrandom(as, rnd, sizeof(rnd)); + + /* + * Discard early keystream, as per recommendations in: + * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps + */ + for (n = 0; n < 256; n++) + (void)arc4_getbyte(as); + arc4_count = 1600000; +} + +static inline u_int8_t +arc4_getbyte(struct arc4_stream *as) +{ + u_int8_t si, sj; + + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si); + sj = as->s[as->j]; + as->s[as->i] = sj; + as->s[as->j] = si; + return (as->s[(si + sj) & 0xff]); +} + +/* + * __arc4_getbyte() is a libc private function intended for use + * with malloc(3) without calling getpid(2). It's good for + * fetching a specific amount of bytes. + */ +u_int8_t +__arc4_getbyte(void) +{ + if (--arc4_count == 0 || !rs_initialized) + arc4random_stir(); + return arc4_getbyte(&rs); +} + +static inline u_int32_t +arc4_getword(struct arc4_stream *as) +{ + u_int32_t val; + val = arc4_getbyte(as) << 24; + val |= arc4_getbyte(as) << 16; + val |= arc4_getbyte(as) << 8; + val |= arc4_getbyte(as); + return val; +} + +void +arc4random_stir(void) +{ + if (!rs_initialized) { + arc4_init(&rs); + rs_initialized = 1; + } + arc4_stir(&rs); +} + +void +arc4random_addrandom(u_char *dat, int datlen) +{ + if (!rs_initialized) + arc4random_stir(); + arc4_addrandom(&rs, dat, datlen); +} + +u_int32_t +arc4random(void) +{ + arc4_count -= 4; + if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != __getpid()) + arc4random_stir(); + return arc4_getword(&rs); +} + +#if defined(TEST) +#include +int main(void) +{ + int random_number; + random_number = arc4random() % 65536; + printf("%d\n", random_number); + return 0; +} +#endif diff -Naur glibc-2.5.1.orig/stdlib/stdlib.h glibc-2.5.1/stdlib/stdlib.h --- glibc-2.5.1.orig/stdlib/stdlib.h 2007-07-12 16:58:08.000000000 +0000 +++ glibc-2.5.1/stdlib/stdlib.h 2008-05-18 19:53:01.000000000 +0000 @@ -577,6 +577,12 @@ extern int lcong48_r (unsigned short int __param[7], struct drand48_data *__buffer) __THROW __nonnull ((1, 2)); + +/* Arcfour random number generator. */ +extern u_int32_t arc4random(void); +extern void arc4random_stir(void); +extern void arc4random_addrandom(unsigned char *, int); + # endif /* Use misc. */ #endif /* Use SVID or X/Open. */ @@ -727,6 +733,7 @@ Returns TEMPLATE, or a null pointer if it cannot get a unique name. The directory is created mode 700. */ extern char *mkdtemp (char *__template) __THROW __nonnull ((1)) __wur; +extern int mkstemps(char *, int) __THROW __wur; #endif diff -Naur glibc-2.5.1.orig/string/strfry.c glibc-2.5.1/string/strfry.c --- glibc-2.5.1.orig/string/strfry.c 2002-03-11 23:47:45.000000000 +0000 +++ glibc-2.5.1/string/strfry.c 2008-05-18 19:53:51.000000000 +0000 @@ -32,7 +32,7 @@ { static char state[32]; rdata.state = NULL; - __initstate_r (time ((time_t *) NULL) ^ getpid (), + __initstate_r (arc4random(), state, sizeof (state), &rdata); init = 1; } diff -Naur glibc-2.5.1.orig/sunrpc/bindrsvprt.c glibc-2.5.1/sunrpc/bindrsvprt.c --- glibc-2.5.1.orig/sunrpc/bindrsvprt.c 2005-11-22 04:39:05.000000000 +0000 +++ glibc-2.5.1/sunrpc/bindrsvprt.c 2008-05-18 19:53:01.000000000 +0000 @@ -67,7 +67,7 @@ if (port == 0) { - port = (__getpid () % NPORTS) + STARTPORT; + port = (arc4random() % NPORTS) + STARTPORT; } /* Initialize to make gcc happy. */ diff -Naur glibc-2.5.1.orig/sysdeps/posix/tempname.c glibc-2.5.1/sysdeps/posix/tempname.c --- glibc-2.5.1.orig/sysdeps/posix/tempname.c 2006-04-07 19:29:07.000000000 +0000 +++ glibc-2.5.1/sysdeps/posix/tempname.c 2008-05-18 19:53:01.000000000 +0000 @@ -52,10 +52,6 @@ # include #endif -#if HAVE_SYS_TIME_H || _LIBC -# include -#endif - #if HAVE_STDINT_H || _LIBC # include #endif @@ -94,8 +90,6 @@ # define struct_stat64 struct stat64 #else # define struct_stat64 struct stat -# define __getpid getpid -# define __gettimeofday gettimeofday # define __mkdir mkdir # define __open open # define __open64 open @@ -107,25 +101,6 @@ # define __secure_getenv getenv #endif -#ifdef _LIBC -# include -# if HP_TIMING_AVAIL -# define RANDOM_BITS(Var) \ - if (__builtin_expect (value == UINT64_C (0), 0)) \ - { \ - /* If this is the first time this function is used initialize \ - the variable we accumulate the value in to some somewhat \ - random value. If we'd not do this programs at startup time \ - might have a reduced set of possible names, at least on slow \ - machines. */ \ - struct timeval tv; \ - __gettimeofday (&tv, NULL); \ - value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ - } \ - HP_TIMING_NOW (Var) -# endif -#endif - /* Use the widest available unsigned type if uint64_t is not available. The algorithm below extracts a number less than 62**6 (approximately 2**35.725) from uint64_t, so ancient hosts where @@ -229,10 +204,8 @@ { int len; char *XXXXXX; - static uint64_t value; - uint64_t random_time_bits; - unsigned int count; int fd = -1; + unsigned int i; int save_errno = errno; struct_stat64 st; @@ -262,39 +235,13 @@ /* This is where the Xs start. */ XXXXXX = &tmpl[len - 6]; - /* Get some more or less random data. */ -#ifdef RANDOM_BITS - RANDOM_BITS (random_time_bits); -#else -# if HAVE_GETTIMEOFDAY || _LIBC - { - struct timeval tv; - __gettimeofday (&tv, NULL); - random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; - } -# else - random_time_bits = time (NULL); -# endif -#endif - value += random_time_bits ^ __getpid (); - - for (count = 0; count < attempts; value += 7777, ++count) + for (i = 0; i < 6 ; ++i) { - uint64_t v = value; - - /* Fill in the random bits. */ - XXXXXX[0] = letters[v % 62]; - v /= 62; - XXXXXX[1] = letters[v % 62]; - v /= 62; - XXXXXX[2] = letters[v % 62]; - v /= 62; - XXXXXX[3] = letters[v % 62]; - v /= 62; - XXXXXX[4] = letters[v % 62]; - v /= 62; - XXXXXX[5] = letters[v % 62]; + XXXXXX[i] = letters[(arc4random() % 62)]; + } + for (i = 0; i < attempts; ++i) + { switch (kind) { case __GT_FILE: diff -Naur glibc-2.5.1.orig/sysdeps/unix/sysv/linux/dl-osinfo.h glibc-2.5.1/sysdeps/unix/sysv/linux/dl-osinfo.h --- glibc-2.5.1.orig/sysdeps/unix/sysv/linux/dl-osinfo.h 2006-08-01 06:55:27.000000000 +0000 +++ glibc-2.5.1/sysdeps/unix/sysv/linux/dl-osinfo.h 2008-05-18 19:53:01.000000000 +0000 @@ -163,14 +163,27 @@ { uintptr_t ret; #ifdef ENABLE_STACKGUARD_RANDOMIZE - int fd = __open ("/dev/urandom", O_RDONLY); +# ifdef PRNG_DEV + int fd = __open (PRNG_DEV, O_RDONLY); if (fd >= 0) { ssize_t reslen = __read (fd, &ret, sizeof (ret)); __close (fd); if (reslen == (ssize_t) sizeof (ret)) return ret; + } else { /* fd=-1? Try again. */ +# endif + fd = __open("/dev/urandom", O_RDONLY, 0); + if (fd != -1) + { + ssize_t reslen = __read (fd, &ret, sizeof (ret)); + __close (fd); + if (reslen == (ssize_t) sizeof (ret)) + return ret; + } +# ifdef PRNG_DEV } +# endif #endif ret = 0; unsigned char *p = (unsigned char *) &ret;