From f4c406b83b1f9e06c5374a75f551aa5f3e7fb405 Mon Sep 17 00:00:00 2001 From: kurt <> Date: Tue, 1 Jan 2008 00:43:39 +0000 Subject: [PATCH] - make arc4random*() functions thread safe. Use a custom spinlock function instead of the generic pthread macros since free(3) uses __arc4_getbyte() when freeing small sized allocations and the generic pthread macros call malloc(3). - eliminate passing pointers to a static variable with global scope (rs) for additional code clarity and reduction. - shlib minor bumps for libc and libpthread due to new functions. From andreas@ with some bits from me. okay tedu@ marc@ w/some spot checking from millert@ --- src/lib/libc/crypt/arc4random.c | 97 +++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/src/lib/libc/crypt/arc4random.c b/src/lib/libc/crypt/arc4random.c index 35d79530..8604548f 100644 --- a/src/lib/libc/crypt/arc4random.c +++ b/src/lib/libc/crypt/arc4random.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arc4random.c,v 1.16 2007/02/12 19:58:47 otto Exp $ */ +/* $OpenBSD: arc4random.c,v 1.17 2008/01/01 00:43:39 kurt Exp $ */ /* * Copyright (c) 1996, David Mazieres @@ -40,6 +40,7 @@ #include #include #include +#include "thread_private.h" #ifdef __GNUC__ #define inline __inline @@ -58,43 +59,48 @@ 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 *); +static inline u_int8_t arc4_getbyte(void); static inline void -arc4_init(struct arc4_stream *as) +arc4_init(void) { int n; for (n = 0; n < 256; n++) - as->s[n] = n; - as->i = 0; - as->j = 0; + rs.s[n] = n; + rs.i = 0; + rs.j = 0; } static inline void -arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen) +arc4_addrandom(u_char *dat, int datlen) { int n; u_int8_t si; - as->i--; + rs.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; + 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; } - as->j = as->i; + rs.j = rs.i; } static void -arc4_stir(struct arc4_stream *as) +arc4_stir(void) { int i, mib[2]; size_t len; u_char rnd[128]; + if (!rs_initialized) { + arc4_init(); + rs_initialized = 1; + } + mib[0] = CTL_KERN; mib[1] = KERN_ARND; @@ -102,75 +108,84 @@ arc4_stir(struct arc4_stream *as) sysctl(mib, 2, rnd, &len, NULL, 0); arc4_stir_pid = getpid(); - arc4_addrandom(as, rnd, sizeof(rnd)); + arc4_addrandom(rnd, sizeof(rnd)); /* * Discard early keystream, as per recommendations in: * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps */ for (i = 0; i < 256; i++) - (void)arc4_getbyte(as); + (void)arc4_getbyte(); arc4_count = 1600000; } static inline u_int8_t -arc4_getbyte(struct arc4_stream *as) +arc4_getbyte(void) { 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]); + 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]); } u_int8_t __arc4_getbyte(void) { + u_int8_t val; + + _ARC4_LOCK(); if (--arc4_count == 0 || !rs_initialized) - arc4random_stir(); - return arc4_getbyte(&rs); + arc4_stir(); + val = arc4_getbyte(); + _ARC4_UNLOCK(); + return val; } static inline u_int32_t -arc4_getword(struct arc4_stream *as) +arc4_getword(void) { u_int32_t val; - val = arc4_getbyte(as) << 24; - val |= arc4_getbyte(as) << 16; - val |= arc4_getbyte(as) << 8; - val |= arc4_getbyte(as); + val = arc4_getbyte() << 24; + val |= arc4_getbyte() << 16; + val |= arc4_getbyte() << 8; + val |= arc4_getbyte(); return val; } void arc4random_stir(void) { - if (!rs_initialized) { - arc4_init(&rs); - rs_initialized = 1; - } - arc4_stir(&rs); + _ARC4_LOCK(); + arc4_stir(); + _ARC4_UNLOCK(); } void arc4random_addrandom(u_char *dat, int datlen) { + _ARC4_LOCK(); if (!rs_initialized) - arc4random_stir(); - arc4_addrandom(&rs, dat, datlen); + arc4_stir(); + arc4_addrandom(dat, datlen); + _ARC4_UNLOCK(); } u_int32_t arc4random(void) { + u_int32_t val; + _ARC4_LOCK(); arc4_count -= 4; if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid()) - arc4random_stir(); - return arc4_getword(&rs); + arc4_stir(); + val = arc4_getword(); + _ARC4_UNLOCK(); + return val; } #if 0