FreeBSD Bugzilla – Attachment 196272 Details for
Bug 182610
[patch] arc4random(3): replace RC4 with ChaCha20, follow OpenBSD
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Proposed patch updated to latest OpenBSD version
arc4random-chacha20.diff (text/plain), 35.53 KB, created by
Xin LI
on 2018-08-17 07:51:04 UTC
(
hide
)
Description:
Proposed patch updated to latest OpenBSD version
Filename:
MIME Type:
Creator:
Xin LI
Created:
2018-08-17 07:51:04 UTC
Size:
35.53 KB
patch
obsolete
>Index: crypto/heimdal/lib/roken/rand.c >=================================================================== >--- crypto/heimdal/lib/roken/rand.c (revision 337959) >+++ crypto/heimdal/lib/roken/rand.c (working copy) >@@ -37,7 +37,6 @@ void ROKEN_LIB_FUNCTION > rk_random_init(void) > { > #if defined(HAVE_ARC4RANDOM) >- arc4random_stir(); > #elif defined(HAVE_SRANDOMDEV) > srandomdev(); > #elif defined(HAVE_RANDOM) >Index: crypto/openssh/config.h >=================================================================== >--- crypto/openssh/config.h (revision 337959) >+++ crypto/openssh/config.h (working copy) >@@ -191,7 +191,7 @@ > #define HAVE_ARC4RANDOM_BUF 1 > > /* Define to 1 if you have the `arc4random_stir' function. */ >-#define HAVE_ARC4RANDOM_STIR 1 >+/* #undef HAVE_ARC4RANDOM_STIR */ > > /* Define to 1 if you have the `arc4random_uniform' function. */ > #define HAVE_ARC4RANDOM_UNIFORM 1 >Index: include/stdlib.h >=================================================================== >--- include/stdlib.h (revision 337959) >+++ include/stdlib.h (working copy) >@@ -250,11 +250,16 @@ extern void (*malloc_message)(void *, const char * > void abort2(const char *, int, void **) __dead2; > __uint32_t > arc4random(void); >-void arc4random_addrandom(unsigned char *, int); > void arc4random_buf(void *, size_t); >-void arc4random_stir(void); > __uint32_t > arc4random_uniform(__uint32_t); >+ >+#if !defined(BURN_BRIDGES) >+/* Deprecated arc4random() functions */ >+#define arc4random_stir() >+#define arc4random_addrandom(a,b) >+#endif >+ > #ifdef __BLOCKS__ > int atexit_b(void (^ _Nonnull)(void)); > void *bsearch_b(const void *, const void *, size_t, >Index: lib/libc/gen/Makefile.inc >=================================================================== >--- lib/libc/gen/Makefile.inc (revision 337959) >+++ lib/libc/gen/Makefile.inc (working copy) >@@ -16,6 +16,8 @@ SRCS+= __getosreldate.c \ > _thread_init.c \ > alarm.c \ > arc4random.c \ >+ arc4random-compat.c \ >+ arc4random_uniform.c \ > assert.c \ > auxv.c \ > basename.c \ >Index: lib/libc/gen/Symbol.map >=================================================================== >--- lib/libc/gen/Symbol.map (revision 337959) >+++ lib/libc/gen/Symbol.map (working copy) >@@ -65,8 +65,6 @@ FBSD_1.0 { > pthread_testcancel; > alarm; > arc4random; >- arc4random_addrandom; >- arc4random_stir; > __assert; > check_utility_compat; > clock; >Index: lib/libc/gen/arc4random-compat.c >=================================================================== >--- lib/libc/gen/arc4random-compat.c (nonexistent) >+++ lib/libc/gen/arc4random-compat.c (working copy) >@@ -0,0 +1,74 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD >+ * >+ * Copyright (c) 2018 Google LLC >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+#include <sys/cdefs.h> >+__FBSDID("$FreeBSD$"); >+ >+#include <sys/types.h> >+#include <stdbool.h> >+#include <syslog.h> >+ >+/* >+ * The following functions were removed from OpenBSD for good reasons: >+ * >+ * - arc4random_stir() >+ * - arc4random_addrandom() >+ * >+ * On FreeBSD, for backward ABI compatibility, we provide two wrapper which >+ * logs this event and returns. >+ */ >+ >+void __arc4random_stir_fbsd11(void); >+void __arc4random_addrandom_fbsd11(u_char *, int); >+ >+static bool warned = false; >+ >+void >+__arc4random_stir_fbsd11(void) >+{ >+ >+ if (!warned) >+ syslog(LOG_NOTICE, "Deprecated function arc4random_stir() called"); >+ warned = true; >+ return; >+} >+ >+void >+__arc4random_addrandom_fbsd11(u_char * dummy1 __unused, int dummy2 __unused) >+{ >+ >+ if (!warned) >+ syslog(LOG_NOTICE, "Deprecated function arc4random_addrandom() called"); >+ warned = true; >+ return; >+} >+ >+__sym_compat(arc4random_stir, __arc4random_stir_fbsd11, FBSD_1.0); >+__sym_compat(arc4random_addrandom, __arc4random_addrandom_fbsd11, FBSD_1.0); > >Property changes on: lib/libc/gen/arc4random-compat.c >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native >\ No newline at end of property >Added: svn:keywords >## -0,0 +1 ## >+FreeBSD=%H >\ No newline at end of property >Added: svn:mime-type >## -0,0 +1 ## >+text/plain >\ No newline at end of property >Index: lib/libc/gen/arc4random.3 >=================================================================== >--- lib/libc/gen/arc4random.3 (revision 337959) >+++ lib/libc/gen/arc4random.3 (working copy) >@@ -1,4 +1,5 @@ >-.\" $OpenBSD: arc4random.3,v 1.2 1997/04/27 22:40:25 angelos Exp $ >+.\" $OpenBSD: arc4random.3,v 1.35 2014/11/25 16:45:24 millert Exp $ >+.\" > .\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> > .\" All rights reserved. > .\" >@@ -30,16 +31,14 @@ > .\" Manual page, using -mandoc macros > .\" $FreeBSD$ > .\" >-.Dd April 15, 1997 >+.Dd July 19, 2014 > .Dt ARC4RANDOM 3 > .Os > .Sh NAME > .Nm arc4random , > .Nm arc4random_buf , >-.Nm arc4random_uniform , >-.Nm arc4random_stir , >-.Nm arc4random_addrandom >-.Nd arc4 random number generator >+.Nm arc4random_uniform >+.Nd random number generator > .Sh LIBRARY > .Lb libc > .Sh SYNOPSIS >@@ -50,20 +49,36 @@ > .Fn arc4random_buf "void *buf" "size_t nbytes" > .Ft uint32_t > .Fn arc4random_uniform "uint32_t upper_bound" >-.Ft void >-.Fn arc4random_stir "void" >-.Ft void >-.Fn arc4random_addrandom "unsigned char *dat" "int datlen" > .Sh DESCRIPTION >+This family of functions provides higher quality data than those >+described in >+.Xr rand 3 , >+.Xr random 3 , >+and >+.Xr rand48 3 . >+.Pp >+Use of these functions is encouraged for almost all random number >+consumption because the other interfaces are deficient in either >+quality, portability, standardization, or availability. >+These functions can be called in almost all coding environments, >+including >+.Xr pthreads 3 >+and >+.Xr chroot 2 . >+.Pp >+High quality 32-bit pseudo-random numbers are generated very quickly. >+On each call, a cryptographic pseudo-random number generator is used >+to generate a new result. >+One data pool is used for all consumers in a process, so that consumption >+under program flow can act as additional stirring. >+The subsystem is re-seeded from the kernel random number subsystem using >+.Xr getentropy 2 >+on a regular basis, and also upon >+.Xr fork 2 . >+.Pp > The > .Fn arc4random >-function uses the key stream generator employed by the >-arc4 cipher, which uses 8*8 8 bit S-Boxes. >-The S-Boxes >-can be in about >-.if t 2\u\s71700\s10\d >-.if n (2**1700) >-states. >+function returns a single 32-bit value. > The > .Fn arc4random > function returns pseudo-random numbers in the range of 0 to >@@ -75,33 +90,24 @@ and > .Xr random 3 . > .Pp > .Fn arc4random_buf >-function fills the region >+fills the region > .Fa buf > of length > .Fa nbytes >-with ARC4-derived random data. >+with random data. > .Pp > .Fn arc4random_uniform >-will return a uniformly distributed random number less than >+will return a single 32-bit value, uniformly distributed but less than > .Fa upper_bound . >-.Fn arc4random_uniform >-is recommended over constructions like >+This is recommended over constructions like > .Dq Li arc4random() % upper_bound > as it avoids "modulo bias" when the upper bound is not a power of two. >-.Pp >-The >-.Fn arc4random_stir >-function reads data from >-.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 >-functions family, since >-they automatically initialize themselves. >+In the worst case, this function may consume multiple iterations >+to ensure uniformity; see the source code to understand the problem >+and solution. >+.Sh RETURN VALUES >+These functions are always successful, and no return value is >+reserved to indicate an error. > .Sh EXAMPLES > The following produces a drop-in replacement for the traditional > .Fn rand >@@ -113,15 +119,17 @@ functions using > .Dl "#define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))" > .Sh SEE ALSO > .Xr rand 3 , >-.Xr random 3 , >-.Xr srandomdev 3 >+.Xr rand48 3 , >+.Xr random 3 > .Sh HISTORY >-.Pa RC4 >-has been designed by RSA Data Security, Inc. >-It was posted anonymously >-to the USENET and was confirmed to be equivalent by several sources who >-had access to the original cipher. >-Since >-.Pa RC4 >-used to be a trade secret, the cipher is now referred to as >-.Pa ARC4 . >+These functions first appeared in >+.Ox 2.1 . >+.Pp >+The original version of this random number generator used the >+RC4 (also known as ARC4) algorithm. >+In >+.Ox 5.5 >+it was replaced with the ChaCha20 cipher, and it may be replaced >+again in the future as cryptographic techniques advance. >+A good mnemonic is >+.Dq A Replacement Call for Random . >Index: lib/libc/gen/arc4random.c >=================================================================== >--- lib/libc/gen/arc4random.c (revision 337959) >+++ lib/libc/gen/arc4random.c (working copy) >@@ -1,8 +1,10 @@ >-/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ >+/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */ > > /* > * Copyright (c) 1996, David Mazieres <dm@uun.org> > * Copyright (c) 2008, Damien Miller <djm@openbsd.org> >+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> >+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above >@@ -18,15 +20,7 @@ > */ > > /* >- * 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. >- * >- * RC4 is a registered trademark of RSA Laboratories. >+ * ChaCha based random number generator for OpenBSD. > */ > > #include <sys/cdefs.h> >@@ -35,267 +29,176 @@ __FBSDID("$FreeBSD$"); > #include "namespace.h" > #include <fcntl.h> > #include <limits.h> >+#include <pthread.h> >+#include <signal.h> >+#include <stdint.h> > #include <stdlib.h> >+#include <string.h> > #include <unistd.h> >-#include <sys/param.h> >-#include <sys/sysctl.h> >+#include <sys/types.h> > #include <sys/time.h> >-#include <pthread.h> >- >+ > #include "libc_private.h" > #include "un-namespace.h" > >-#ifdef __GNUC__ >+#define KEYSTREAM_ONLY >+#include "chacha_private.h" >+ >+#define minimum(a, b) ((a) < (b) ? (a) : (b)) >+ >+#if defined(__GNUC__) || defined(_MSC_VER) > #define inline __inline >-#else /* !__GNUC__ */ >+#else /* __GNUC__ || _MSC_VER */ > #define inline >-#endif /* !__GNUC__ */ >+#endif /* !__GNUC__ && !_MSC_VER */ > >-struct arc4_stream { >- u_int8_t i; >- u_int8_t j; >- u_int8_t s[256]; >-}; >+#define KEYSZ 32 >+#define IVSZ 8 >+#define BLOCKSZ 64 >+#define RSBUFSZ (16*BLOCKSZ) > >-static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; >+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ >+static struct _rs { >+ size_t rs_have; /* valid bytes at end of rs_buf */ >+ size_t rs_count; /* bytes till reseed */ >+} *rs; > >-#define KEYSIZE 128 >-#define _ARC4_LOCK() \ >- do { \ >- if (__isthreaded) \ >- _pthread_mutex_lock(&arc4random_mtx); \ >- } while (0) >+/* Maybe be preserved in fork children, if _rs_allocate() decides. */ >+static struct _rsx { >+ chacha_ctx rs_chacha; /* chacha context for random keystream */ >+ u_char rs_buf[RSBUFSZ]; /* keystream blocks */ >+} *rsx; > >-#define _ARC4_UNLOCK() \ >- do { \ >- if (__isthreaded) \ >- _pthread_mutex_unlock(&arc4random_mtx); \ >- } while (0) >+static inline int _rs_allocate(struct _rs **, struct _rsx **); >+static inline void _rs_forkdetect(void); >+#include "arc4random.h" > >-static int rs_initialized; >-static struct arc4_stream rs; >-static pid_t arc4_stir_pid; >-static int arc4_count; >+static inline void _rs_rekey(u_char *dat, size_t datlen); > >-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, >- void *newp, size_t newlen); >- >-static inline u_int8_t arc4_getbyte(void); >-static void arc4_stir(void); >- > static inline void >-arc4_init(void) >+_rs_init(u_char *buf, size_t n) > { >- int n; >+ if (n < KEYSZ + IVSZ) >+ return; > >- for (n = 0; n < 256; n++) >- rs.s[n] = n; >- rs.i = 0; >- rs.j = 0; >+ if (rs == NULL) { >+ if (_rs_allocate(&rs, &rsx) == -1) >+ abort(); >+ } >+ >+ chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); >+ chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); > } > >-static inline void >-arc4_addrandom(u_char *dat, int datlen) >+static void >+_rs_stir(void) > { >- int n; >- u_int8_t si; >+ u_char rnd[KEYSZ + IVSZ]; > >- rs.i--; >- for (n = 0; n < 256; n++) { >- rs.i = (rs.i + 1); >- si = rs.s[rs.i]; >- rs.j = (rs.j + si + dat[n % datlen]); >- rs.s[rs.i] = rs.s[rs.j]; >- rs.s[rs.j] = si; >- } >- rs.j = rs.i; >-} >+ if (getentropy(rnd, sizeof rnd) == -1) >+ _getentropy_fail(); > >-size_t >-__arc4_sysctl(u_char *buf, size_t size) >-{ >- int mib[2]; >- size_t len, done; >+ if (!rs) >+ _rs_init(rnd, sizeof(rnd)); >+ else >+ _rs_rekey(rnd, sizeof(rnd)); >+ explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ > >- mib[0] = CTL_KERN; >- mib[1] = KERN_ARND; >- done = 0; >+ /* invalidate rs_buf */ >+ rs->rs_have = 0; >+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); > >- do { >- len = size; >- if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) >- return (done); >- done += len; >- buf += len; >- size -= len; >- } while (size > 0); >- >- return (done); >+ rs->rs_count = 1600000; > } > >-static void >-arc4_stir(void) >+static inline void >+_rs_stir_if_needed(size_t len) > { >- u_char rdat[KEYSIZE]; >- int i; >- >- if (!rs_initialized) { >- arc4_init(); >- rs_initialized = 1; >- } >- if (__arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { >- /* >- * The sysctl cannot fail. If it does fail on some FreeBSD >- * derivative or after some future change, just abort so that >- * the problem will be found and fixed. abort is not normally >- * suitable for a library but makes sense here. >- */ >- abort(); >- } >- >- arc4_addrandom(rdat, KEYSIZE); >- >- /* >- * Discard early keystream, as per recommendations in: >- * "(Not So) Random Shuffles of RC4" by Ilya Mironov. >- */ >- for (i = 0; i < 3072; i++) >- (void)arc4_getbyte(); >- arc4_count = 1600000; >+ _rs_forkdetect(); >+ if (!rs || rs->rs_count <= len) >+ _rs_stir(); >+ if (rs->rs_count <= len) >+ rs->rs_count = 0; >+ else >+ rs->rs_count -= len; > } > >-static void >-arc4_stir_if_needed(void) >+static inline void >+_rs_rekey(u_char *dat, size_t datlen) > { >- pid_t pid = getpid(); >+#ifndef KEYSTREAM_ONLY >+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); >+#endif >+ /* fill rs_buf with the keystream */ >+ chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, >+ rsx->rs_buf, sizeof(rsx->rs_buf)); >+ /* mix in optional user provided data */ >+ if (dat) { >+ size_t i, m; > >- if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { >- arc4_stir_pid = pid; >- arc4_stir(); >+ m = minimum(datlen, KEYSZ + IVSZ); >+ for (i = 0; i < m; i++) >+ rsx->rs_buf[i] ^= dat[i]; > } >+ /* immediately reinit for backtracking resistance */ >+ _rs_init(rsx->rs_buf, KEYSZ + IVSZ); >+ memset(rsx->rs_buf, 0, KEYSZ + IVSZ); >+ rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; > } > >-static inline u_int8_t >-arc4_getbyte(void) >+static inline void >+_rs_random_buf(void *_buf, size_t n) > { >- u_int8_t si, sj; >+ u_char *buf = (u_char *)_buf; >+ u_char *keystream; >+ size_t m; > >- rs.i = (rs.i + 1); >- si = rs.s[rs.i]; >- rs.j = (rs.j + si); >- sj = rs.s[rs.j]; >- rs.s[rs.i] = sj; >- rs.s[rs.j] = si; >- return (rs.s[(si + sj) & 0xff]); >+ _rs_stir_if_needed(n); >+ while (n > 0) { >+ if (rs->rs_have > 0) { >+ m = minimum(n, rs->rs_have); >+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf) >+ - rs->rs_have; >+ memcpy(buf, keystream, m); >+ memset(keystream, 0, m); >+ buf += m; >+ n -= m; >+ rs->rs_have -= m; >+ } >+ if (rs->rs_have == 0) >+ _rs_rekey(NULL, 0); >+ } > } > >-static inline u_int32_t >-arc4_getword(void) >+static inline void >+_rs_random_u32(uint32_t *val) > { >- u_int32_t val; >- val = arc4_getbyte() << 24; >- val |= arc4_getbyte() << 16; >- val |= arc4_getbyte() << 8; >- val |= arc4_getbyte(); >- return val; >-} >+ u_char *keystream; > >-void >-arc4random_stir(void) >-{ >- _ARC4_LOCK(); >- arc4_stir(); >- _ARC4_UNLOCK(); >+ _rs_stir_if_needed(sizeof(*val)); >+ if (rs->rs_have < sizeof(*val)) >+ _rs_rekey(NULL, 0); >+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; >+ memcpy(val, keystream, sizeof(*val)); >+ memset(keystream, 0, sizeof(*val)); >+ rs->rs_have -= sizeof(*val); > } > >-void >-arc4random_addrandom(u_char *dat, int datlen) >+uint32_t >+arc4random(void) > { >- _ARC4_LOCK(); >- if (!rs_initialized) >- arc4_stir(); >- arc4_addrandom(dat, datlen); >- _ARC4_UNLOCK(); >-} >+ uint32_t val; > >-u_int32_t >-arc4random(void) >-{ >- u_int32_t val; > _ARC4_LOCK(); >- arc4_count -= 4; >- arc4_stir_if_needed(); >- val = arc4_getword(); >+ _rs_random_u32(&val); > _ARC4_UNLOCK(); > return val; > } > > void >-arc4random_buf(void *_buf, size_t n) >+arc4random_buf(void *buf, size_t n) > { >- u_char *buf = (u_char *)_buf; > _ARC4_LOCK(); >- arc4_stir_if_needed(); >- while (n--) { >- if (--arc4_count <= 0) >- arc4_stir(); >- buf[n] = arc4_getbyte(); >- } >+ _rs_random_buf(buf, n); > _ARC4_UNLOCK(); > } >- >-/* >- * Calculate a uniformly distributed random number less than upper_bound >- * avoiding "modulo bias". >- * >- * Uniformity is achieved by generating new random numbers until the one >- * returned is outside the range [0, 2**32 % upper_bound). This >- * guarantees the selected random number will be inside >- * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) >- * after reduction modulo upper_bound. >- */ >-u_int32_t >-arc4random_uniform(u_int32_t upper_bound) >-{ >- u_int32_t r, min; >- >- if (upper_bound < 2) >- return 0; >- >- /* 2**32 % x == (2**32 - x) % x */ >- min = -upper_bound % upper_bound; >- /* >- * This could theoretically loop forever but each retry has >- * p > 0.5 (worst case, usually far better) of selecting a >- * number inside the range we need, so it should rarely need >- * to re-roll. >- */ >- for (;;) { >- r = arc4random(); >- if (r >= min) >- break; >- } >- >- return r % upper_bound; >-} >- >-#if 0 >-/*-------- Test code for i386 --------*/ >-#include <stdio.h> >-#include <machine/pctr.h> >-int >-main(int argc, char **argv) >-{ >- const int iter = 1000000; >- int i; >- pctrval v; >- >- v = rdtsc(); >- for (i = 0; i < iter; i++) >- arc4random(); >- v = rdtsc() - v; >- v /= iter; >- >- printf("%qd cycles\n", v); >-} >-#endif >Index: lib/libc/gen/arc4random.h >=================================================================== >--- lib/libc/gen/arc4random.h (nonexistent) >+++ lib/libc/gen/arc4random.h (working copy) >@@ -0,0 +1,74 @@ >+/* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */ >+ >+/* >+ * Copyright (c) 1996, David Mazieres <dm@uun.org> >+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org> >+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> >+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> >+ * >+ * 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+/* >+ * Stub functions for portability. >+ */ >+#include <sys/mman.h> >+ >+#include <signal.h> >+ >+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; >+#define _ARC4_LOCK() \ >+ do { \ >+ if (__isthreaded) \ >+ _pthread_mutex_lock(&arc4random_mtx); \ >+ } while (0) >+ >+#define _ARC4_UNLOCK() \ >+ do { \ >+ if (__isthreaded) \ >+ _pthread_mutex_unlock(&arc4random_mtx); \ >+ } while (0) >+ >+static inline void >+_getentropy_fail(void) >+{ >+ raise(SIGKILL); >+} >+ >+static inline int >+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) >+{ >+ struct { >+ struct _rs rs; >+ struct _rsx rsx; >+ } *p; >+ >+ if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE, >+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) >+ return (-1); >+ if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) { >+ munmap(p, sizeof(*p)); >+ return (-1); >+ } >+ >+ *rsp = &p->rs; >+ *rsxp = &p->rsx; >+ return (0); >+} >+ >+static inline void >+_rs_forkdetect(void) >+{ >+} > >Property changes on: lib/libc/gen/arc4random.h >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native >\ No newline at end of property >Added: svn:keywords >## -0,0 +1 ## >+FreeBSD=%H >\ No newline at end of property >Added: svn:mime-type >## -0,0 +1 ## >+text/plain >\ No newline at end of property >Index: lib/libc/gen/arc4random_uniform.c >=================================================================== >--- lib/libc/gen/arc4random_uniform.c (revision 337959) >+++ lib/libc/gen/arc4random_uniform.c (working copy) >@@ -1,7 +1,6 @@ >-/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ >+/* $OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $ */ > > /* >- * Copyright (c) 1996, David Mazieres <dm@uun.org> > * Copyright (c) 2008, Damien Miller <djm@openbsd.org> > * > * Permission to use, copy, modify, and distribute this software for any >@@ -15,235 +14,13 @@ > * 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. >- * >- * RC4 is a registered trademark of RSA Laboratories. >+ * $FreeBSD$ > */ > >-#include <sys/cdefs.h> >-__FBSDID("$FreeBSD$"); >- >-#include "namespace.h" >-#include <fcntl.h> >-#include <limits.h> >+#include <sys/types.h> > #include <stdlib.h> >-#include <unistd.h> >-#include <sys/param.h> >-#include <sys/sysctl.h> >-#include <sys/time.h> >-#include <pthread.h> > >-#include "libc_private.h" >-#include "un-namespace.h" >- >-#ifdef __GNUC__ >-#define inline __inline >-#else /* !__GNUC__ */ >-#define inline >-#endif /* !__GNUC__ */ >- >-struct arc4_stream { >- u_int8_t i; >- u_int8_t j; >- u_int8_t s[256]; >-}; >- >-static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; >- >-#define KEYSIZE 128 >-#define _ARC4_LOCK() \ >- do { \ >- if (__isthreaded) \ >- _pthread_mutex_lock(&arc4random_mtx); \ >- } while (0) >- >-#define _ARC4_UNLOCK() \ >- do { \ >- if (__isthreaded) \ >- _pthread_mutex_unlock(&arc4random_mtx); \ >- } while (0) >- >-static int rs_initialized; >-static struct arc4_stream rs; >-static pid_t arc4_stir_pid; >-static int arc4_count; >- >-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, >- void *newp, size_t newlen); >- >-static inline u_int8_t arc4_getbyte(void); >-static void arc4_stir(void); >- >-static inline void >-arc4_init(void) >-{ >- int n; >- >- for (n = 0; n < 256; n++) >- rs.s[n] = n; >- rs.i = 0; >- rs.j = 0; >-} >- >-static inline void >-arc4_addrandom(u_char *dat, int datlen) >-{ >- int n; >- u_int8_t si; >- >- rs.i--; >- for (n = 0; n < 256; n++) { >- rs.i = (rs.i + 1); >- si = rs.s[rs.i]; >- rs.j = (rs.j + si + dat[n % datlen]); >- rs.s[rs.i] = rs.s[rs.j]; >- rs.s[rs.j] = si; >- } >- rs.j = rs.i; >-} >- >-size_t >-__arc4_sysctl(u_char *buf, size_t size) >-{ >- int mib[2]; >- size_t len, done; >- >- mib[0] = CTL_KERN; >- mib[1] = KERN_ARND; >- done = 0; >- >- do { >- len = size; >- if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) >- return (done); >- done += len; >- buf += len; >- size -= len; >- } while (size > 0); >- >- return (done); >-} >- >-static void >-arc4_stir(void) >-{ >- u_char rdat[KEYSIZE]; >- int i; >- >- if (!rs_initialized) { >- arc4_init(); >- rs_initialized = 1; >- } >- if (__arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { >- /* >- * The sysctl cannot fail. If it does fail on some FreeBSD >- * derivative or after some future change, just abort so that >- * the problem will be found and fixed. abort is not normally >- * suitable for a library but makes sense here. >- */ >- abort(); >- } >- >- arc4_addrandom(rdat, KEYSIZE); >- >- /* >- * Discard early keystream, as per recommendations in: >- * "(Not So) Random Shuffles of RC4" by Ilya Mironov. >- */ >- for (i = 0; i < 3072; i++) >- (void)arc4_getbyte(); >- arc4_count = 1600000; >-} >- >-static void >-arc4_stir_if_needed(void) >-{ >- pid_t pid = getpid(); >- >- if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { >- arc4_stir_pid = pid; >- arc4_stir(); >- } >-} >- >-static inline u_int8_t >-arc4_getbyte(void) >-{ >- u_int8_t si, sj; >- >- rs.i = (rs.i + 1); >- si = rs.s[rs.i]; >- rs.j = (rs.j + si); >- sj = rs.s[rs.j]; >- rs.s[rs.i] = sj; >- rs.s[rs.j] = si; >- return (rs.s[(si + sj) & 0xff]); >-} >- >-static inline u_int32_t >-arc4_getword(void) >-{ >- u_int32_t val; >- val = arc4_getbyte() << 24; >- val |= arc4_getbyte() << 16; >- val |= arc4_getbyte() << 8; >- val |= arc4_getbyte(); >- return val; >-} >- >-void >-arc4random_stir(void) >-{ >- _ARC4_LOCK(); >- arc4_stir(); >- _ARC4_UNLOCK(); >-} >- >-void >-arc4random_addrandom(u_char *dat, int datlen) >-{ >- _ARC4_LOCK(); >- if (!rs_initialized) >- arc4_stir(); >- arc4_addrandom(dat, datlen); >- _ARC4_UNLOCK(); >-} >- >-u_int32_t >-arc4random(void) >-{ >- u_int32_t val; >- _ARC4_LOCK(); >- arc4_count -= 4; >- arc4_stir_if_needed(); >- val = arc4_getword(); >- _ARC4_UNLOCK(); >- return val; >-} >- >-void >-arc4random_buf(void *_buf, size_t n) >-{ >- u_char *buf = (u_char *)_buf; >- _ARC4_LOCK(); >- arc4_stir_if_needed(); >- while (n--) { >- if (--arc4_count <= 0) >- arc4_stir(); >- buf[n] = arc4_getbyte(); >- } >- _ARC4_UNLOCK(); >-} >- > /* > * Calculate a uniformly distributed random number less than upper_bound > * avoiding "modulo bias". >@@ -254,10 +31,10 @@ > * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) > * after reduction modulo upper_bound. > */ >-u_int32_t >-arc4random_uniform(u_int32_t upper_bound) >+uint32_t >+arc4random_uniform(uint32_t upper_bound) > { >- u_int32_t r, min; >+ uint32_t r, min; > > if (upper_bound < 2) > return 0; >@@ -264,6 +41,7 @@ > > /* 2**32 % x == (2**32 - x) % x */ > min = -upper_bound % upper_bound; >+ > /* > * This could theoretically loop forever but each retry has > * p > 0.5 (worst case, usually far better) of selecting a >@@ -278,24 +56,3 @@ > > return r % upper_bound; > } >- >-#if 0 >-/*-------- Test code for i386 --------*/ >-#include <stdio.h> >-#include <machine/pctr.h> >-int >-main(int argc, char **argv) >-{ >- const int iter = 1000000; >- int i; >- pctrval v; >- >- v = rdtsc(); >- for (i = 0; i < iter; i++) >- arc4random(); >- v = rdtsc() - v; >- v /= iter; >- >- printf("%qd cycles\n", v); >-} >-#endif >Index: lib/libc/gen/chacha_private.h >=================================================================== >--- lib/libc/gen/chacha_private.h (nonexistent) >+++ lib/libc/gen/chacha_private.h (working copy) >@@ -0,0 +1,223 @@ >+/* >+chacha-merged.c version 20080118 >+D. J. Bernstein >+Public domain. >+*/ >+/* $FreeBSD$ */ >+ >+/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ >+ >+typedef unsigned char u8; >+typedef unsigned int u32; >+ >+typedef struct >+{ >+ u32 input[16]; /* could be compressed */ >+} chacha_ctx; >+ >+#define U8C(v) (v##U) >+#define U32C(v) (v##U) >+ >+#define U8V(v) ((u8)(v) & U8C(0xFF)) >+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) >+ >+#define ROTL32(v, n) \ >+ (U32V((v) << (n)) | ((v) >> (32 - (n)))) >+ >+#define U8TO32_LITTLE(p) \ >+ (((u32)((p)[0]) ) | \ >+ ((u32)((p)[1]) << 8) | \ >+ ((u32)((p)[2]) << 16) | \ >+ ((u32)((p)[3]) << 24)) >+ >+#define U32TO8_LITTLE(p, v) \ >+ do { \ >+ (p)[0] = U8V((v) ); \ >+ (p)[1] = U8V((v) >> 8); \ >+ (p)[2] = U8V((v) >> 16); \ >+ (p)[3] = U8V((v) >> 24); \ >+ } while (0) >+ >+#define ROTATE(v,c) (ROTL32(v,c)) >+#define XOR(v,w) ((v) ^ (w)) >+#define PLUS(v,w) (U32V((v) + (w))) >+#define PLUSONE(v) (PLUS((v),1)) >+ >+#define QUARTERROUND(a,b,c,d) \ >+ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ >+ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ >+ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ >+ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); >+ >+static const char sigma[16] = "expand 32-byte k"; >+static const char tau[16] = "expand 16-byte k"; >+ >+static void >+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) >+{ >+ const char *constants; >+ >+ x->input[4] = U8TO32_LITTLE(k + 0); >+ x->input[5] = U8TO32_LITTLE(k + 4); >+ x->input[6] = U8TO32_LITTLE(k + 8); >+ x->input[7] = U8TO32_LITTLE(k + 12); >+ if (kbits == 256) { /* recommended */ >+ k += 16; >+ constants = sigma; >+ } else { /* kbits == 128 */ >+ constants = tau; >+ } >+ x->input[8] = U8TO32_LITTLE(k + 0); >+ x->input[9] = U8TO32_LITTLE(k + 4); >+ x->input[10] = U8TO32_LITTLE(k + 8); >+ x->input[11] = U8TO32_LITTLE(k + 12); >+ x->input[0] = U8TO32_LITTLE(constants + 0); >+ x->input[1] = U8TO32_LITTLE(constants + 4); >+ x->input[2] = U8TO32_LITTLE(constants + 8); >+ x->input[3] = U8TO32_LITTLE(constants + 12); >+} >+ >+static void >+chacha_ivsetup(chacha_ctx *x,const u8 *iv) >+{ >+ x->input[12] = 0; >+ x->input[13] = 0; >+ x->input[14] = U8TO32_LITTLE(iv + 0); >+ x->input[15] = U8TO32_LITTLE(iv + 4); >+} >+ >+static void >+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) >+{ >+ u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; >+ u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; >+ u8 *ctarget = NULL; >+ u8 tmp[64]; >+ u_int i; >+ >+ if (!bytes) return; >+ >+ j0 = x->input[0]; >+ j1 = x->input[1]; >+ j2 = x->input[2]; >+ j3 = x->input[3]; >+ j4 = x->input[4]; >+ j5 = x->input[5]; >+ j6 = x->input[6]; >+ j7 = x->input[7]; >+ j8 = x->input[8]; >+ j9 = x->input[9]; >+ j10 = x->input[10]; >+ j11 = x->input[11]; >+ j12 = x->input[12]; >+ j13 = x->input[13]; >+ j14 = x->input[14]; >+ j15 = x->input[15]; >+ >+ for (;;) { >+ if (bytes < 64) { >+ for (i = 0;i < bytes;++i) tmp[i] = m[i]; >+ m = tmp; >+ ctarget = c; >+ c = tmp; >+ } >+ x0 = j0; >+ x1 = j1; >+ x2 = j2; >+ x3 = j3; >+ x4 = j4; >+ x5 = j5; >+ x6 = j6; >+ x7 = j7; >+ x8 = j8; >+ x9 = j9; >+ x10 = j10; >+ x11 = j11; >+ x12 = j12; >+ x13 = j13; >+ x14 = j14; >+ x15 = j15; >+ for (i = 20;i > 0;i -= 2) { >+ QUARTERROUND( x0, x4, x8,x12) >+ QUARTERROUND( x1, x5, x9,x13) >+ QUARTERROUND( x2, x6,x10,x14) >+ QUARTERROUND( x3, x7,x11,x15) >+ QUARTERROUND( x0, x5,x10,x15) >+ QUARTERROUND( x1, x6,x11,x12) >+ QUARTERROUND( x2, x7, x8,x13) >+ QUARTERROUND( x3, x4, x9,x14) >+ } >+ x0 = PLUS(x0,j0); >+ x1 = PLUS(x1,j1); >+ x2 = PLUS(x2,j2); >+ x3 = PLUS(x3,j3); >+ x4 = PLUS(x4,j4); >+ x5 = PLUS(x5,j5); >+ x6 = PLUS(x6,j6); >+ x7 = PLUS(x7,j7); >+ x8 = PLUS(x8,j8); >+ x9 = PLUS(x9,j9); >+ x10 = PLUS(x10,j10); >+ x11 = PLUS(x11,j11); >+ x12 = PLUS(x12,j12); >+ x13 = PLUS(x13,j13); >+ x14 = PLUS(x14,j14); >+ x15 = PLUS(x15,j15); >+ >+#ifndef KEYSTREAM_ONLY >+ x0 = XOR(x0,U8TO32_LITTLE(m + 0)); >+ x1 = XOR(x1,U8TO32_LITTLE(m + 4)); >+ x2 = XOR(x2,U8TO32_LITTLE(m + 8)); >+ x3 = XOR(x3,U8TO32_LITTLE(m + 12)); >+ x4 = XOR(x4,U8TO32_LITTLE(m + 16)); >+ x5 = XOR(x5,U8TO32_LITTLE(m + 20)); >+ x6 = XOR(x6,U8TO32_LITTLE(m + 24)); >+ x7 = XOR(x7,U8TO32_LITTLE(m + 28)); >+ x8 = XOR(x8,U8TO32_LITTLE(m + 32)); >+ x9 = XOR(x9,U8TO32_LITTLE(m + 36)); >+ x10 = XOR(x10,U8TO32_LITTLE(m + 40)); >+ x11 = XOR(x11,U8TO32_LITTLE(m + 44)); >+ x12 = XOR(x12,U8TO32_LITTLE(m + 48)); >+ x13 = XOR(x13,U8TO32_LITTLE(m + 52)); >+ x14 = XOR(x14,U8TO32_LITTLE(m + 56)); >+ x15 = XOR(x15,U8TO32_LITTLE(m + 60)); >+#endif >+ >+ j12 = PLUSONE(j12); >+ if (!j12) { >+ j13 = PLUSONE(j13); >+ /* stopping at 2^70 bytes per nonce is user's responsibility */ >+ } >+ >+ U32TO8_LITTLE(c + 0,x0); >+ U32TO8_LITTLE(c + 4,x1); >+ U32TO8_LITTLE(c + 8,x2); >+ U32TO8_LITTLE(c + 12,x3); >+ U32TO8_LITTLE(c + 16,x4); >+ U32TO8_LITTLE(c + 20,x5); >+ U32TO8_LITTLE(c + 24,x6); >+ U32TO8_LITTLE(c + 28,x7); >+ U32TO8_LITTLE(c + 32,x8); >+ U32TO8_LITTLE(c + 36,x9); >+ U32TO8_LITTLE(c + 40,x10); >+ U32TO8_LITTLE(c + 44,x11); >+ U32TO8_LITTLE(c + 48,x12); >+ U32TO8_LITTLE(c + 52,x13); >+ U32TO8_LITTLE(c + 56,x14); >+ U32TO8_LITTLE(c + 60,x15); >+ >+ if (bytes <= 64) { >+ if (bytes < 64) { >+ for (i = 0;i < bytes;++i) ctarget[i] = c[i]; >+ } >+ x->input[12] = j12; >+ x->input[13] = j13; >+ return; >+ } >+ bytes -= 64; >+ c += 64; >+#ifndef KEYSTREAM_ONLY >+ m += 64; >+#endif >+ } >+} > >Property changes on: lib/libc/gen/chacha_private.h >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native >\ No newline at end of property >Added: svn:keywords >## -0,0 +1 ## >+FreeBSD=%H >\ No newline at end of property >Added: svn:mime-type >## -0,0 +1 ## >+text/plain >\ No newline at end of property >Index: lib/libc/gen/getentropy.c >=================================================================== >--- lib/libc/gen/getentropy.c (revision 337959) >+++ lib/libc/gen/getentropy.c (working copy) >@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); > > #include <sys/param.h> > #include <sys/random.h> >+#include <sys/sysctl.h> > > #include <errno.h> > #include <stdlib.h> >@@ -37,6 +38,30 @@ __FBSDID("$FreeBSD$"); > > #include "libc_private.h" > >+extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); >+ >+static size_t >+arnd_sysctl(u_char *buf, size_t size) >+{ >+ int mib[2]; >+ size_t len, done; >+ >+ mib[0] = CTL_KERN; >+ mib[1] = KERN_ARND; >+ done = 0; >+ >+ do { >+ len = size; >+ if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) >+ return (done); >+ done += len; >+ buf += len; >+ size -= len; >+ } while (size > 0); >+ >+ return (done); >+} >+ > /* > * If a newer libc is accidentally installed on an older kernel, provide high > * quality random data anyway. The sysctl interface is not as fast and does >@@ -54,7 +79,7 @@ getentropy_fallback(void *buf, size_t buflen) > errno = EFAULT; > return (-1); > } >- if (__arc4_sysctl(buf, buflen) != buflen) { >+ if (arnd_sysctl(buf, buflen) != buflen) { > if (errno == EFAULT) > return (-1); > /* >Index: lib/libc/include/libc_private.h >=================================================================== >--- lib/libc/include/libc_private.h (revision 337959) >+++ lib/libc/include/libc_private.h (working copy) >@@ -405,8 +405,6 @@ int __sys_futimens(int fd, const struct timespec > int __sys_utimensat(int fd, const char *path, > const struct timespec *times, int flag) __hidden; > >-__size_t __arc4_sysctl(unsigned char *, __size_t); >- > /* execve() with PATH processing to implement posix_spawnp() */ > int _execvpe(const char *, char * const *, char * const *); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 182610
:
147975
|
147976
|
149068
|
149507
|
189567
|
196272
|
196337
|
196342