From 0c67ab8bf7edbef019be3f16d6fecf3415f936b8 Mon Sep 17 00:00:00 2001 From: Kurt Miller Date: Tue, 1 Jan 2008 00:43:40 +0000 Subject: - 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@ --- lib/libc/crypt/arc4random.c | 97 +++++++++++++++++------------- lib/libc/include/thread_private.h | 14 ++++- lib/libc/shlib_version | 2 +- lib/libc/thread/unithread_malloc_lock.c | 20 +++++- lib/libpthread/shlib_version | 2 +- lib/libpthread/thread/thread_malloc_lock.c | 15 ++++- lib/libpthread/uthread/uthread_init.c | 4 +- lib/librthread/rthread_libc.c | 19 +++++- 8 files changed, 125 insertions(+), 48 deletions(-) diff --git a/lib/libc/crypt/arc4random.c b/lib/libc/crypt/arc4random.c index 35d79530022..8604548f3fc 100644 --- a/lib/libc/crypt/arc4random.c +++ b/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 diff --git a/lib/libc/include/thread_private.h b/lib/libc/include/thread_private.h index 146f0b0a015..f55880f7bae 100644 --- a/lib/libc/include/thread_private.h +++ b/lib/libc/include/thread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: thread_private.h,v 1.21 2007/11/19 02:54:19 kurt Exp $ */ +/* $OpenBSD: thread_private.h,v 1.22 2008/01/01 00:43:39 kurt Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ @@ -150,4 +150,16 @@ void _thread_atexit_unlock(void); _thread_atexit_unlock();\ } while (0) +void _thread_arc4_lock(void); +void _thread_arc4_unlock(void); + +#define _ARC4_LOCK() do { \ + if (__isthreaded) \ + _thread_arc4_lock(); \ + } while (0) +#define _ARC4_UNLOCK() do { \ + if (__isthreaded) \ + _thread_arc4_unlock();\ + } while (0) + #endif /* _THREAD_PRIVATE_H_ */ diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index d5194cd8c2f..3c07d167bfa 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,4 +1,4 @@ major=42 -minor=0 +minor=1 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then libpthread must also be updated. diff --git a/lib/libc/thread/unithread_malloc_lock.c b/lib/libc/thread/unithread_malloc_lock.c index f7231915d6f..ca5081ba780 100644 --- a/lib/libc/thread/unithread_malloc_lock.c +++ b/lib/libc/thread/unithread_malloc_lock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: unithread_malloc_lock.c,v 1.6 2006/02/22 07:16:32 otto Exp $ */ +/* $OpenBSD: unithread_malloc_lock.c,v 1.7 2008/01/01 00:43:39 kurt Exp $ */ #include #include "thread_private.h" @@ -17,6 +17,12 @@ WEAK_PROTOTYPE(_thread_atexit_unlock); WEAK_ALIAS(_thread_atexit_lock); WEAK_ALIAS(_thread_atexit_unlock); +WEAK_PROTOTYPE(_thread_arc4_lock); +WEAK_PROTOTYPE(_thread_arc4_unlock); + +WEAK_ALIAS(_thread_arc4_lock); +WEAK_ALIAS(_thread_arc4_unlock); + void WEAK_NAME(_thread_malloc_lock)(void) { @@ -46,3 +52,15 @@ WEAK_NAME(_thread_atexit_unlock)(void) { return; } + +void +WEAK_NAME(_thread_arc4_lock)(void) +{ + return; +} + +void +WEAK_NAME(_thread_arc4_unlock)(void) +{ + return; +} diff --git a/lib/libpthread/shlib_version b/lib/libpthread/shlib_version index d0f0988b418..00604e64e7d 100644 --- a/lib/libpthread/shlib_version +++ b/lib/libpthread/shlib_version @@ -1,2 +1,2 @@ major=8 -minor=0 +minor=1 diff --git a/lib/libpthread/thread/thread_malloc_lock.c b/lib/libpthread/thread/thread_malloc_lock.c index 6e8b96bb656..6deebb53f66 100644 --- a/lib/libpthread/thread/thread_malloc_lock.c +++ b/lib/libpthread/thread/thread_malloc_lock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: thread_malloc_lock.c,v 1.5 2006/02/22 07:16:32 otto Exp $ */ +/* $OpenBSD: thread_malloc_lock.c,v 1.6 2008/01/01 00:43:39 kurt Exp $ */ /* Public Domain */ #include @@ -6,6 +6,7 @@ static spinlock_t malloc_lock = _SPINLOCK_INITIALIZER; static spinlock_t atexit_lock = _SPINLOCK_INITIALIZER; +static spinlock_t arc4_lock = _SPINLOCK_INITIALIZER; void _thread_malloc_lock() @@ -35,3 +36,15 @@ _thread_atexit_unlock() { _SPINUNLOCK(&atexit_lock); } + +void +_thread_arc4_lock() +{ + _SPINLOCK(&arc4_lock); +} + +void +_thread_arc4_unlock() +{ + _SPINUNLOCK(&arc4_lock); +} diff --git a/lib/libpthread/uthread/uthread_init.c b/lib/libpthread/uthread/uthread_init.c index d48e1173566..36559a5ae34 100644 --- a/lib/libpthread/uthread/uthread_init.c +++ b/lib/libpthread/uthread/uthread_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_init.c,v 1.40 2007/07/20 22:34:40 kettenis Exp $ */ +/* $OpenBSD: uthread_init.c,v 1.41 2008/01/01 00:43:39 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. @@ -135,6 +135,8 @@ static void *references[] = { &_thread_malloc_unlock, &_thread_atexit_lock, &_thread_atexit_unlock, + &_thread_arc4_lock, + &_thread_arc4_unlock, &_thread_tag_lock, &_thread_tag_unlock, &_thread_tag_storage, diff --git a/lib/librthread/rthread_libc.c b/lib/librthread/rthread_libc.c index bf3c057d874..da0d92f8da5 100644 --- a/lib/librthread/rthread_libc.c +++ b/lib/librthread/rthread_libc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_libc.c,v 1.4 2007/06/05 18:11:49 kurt Exp $ */ +/* $OpenBSD: rthread_libc.c,v 1.5 2008/01/01 00:43:39 kurt Exp $ */ /* $snafu: libc_tag.c,v 1.4 2004/11/30 07:00:06 marc Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ @@ -175,6 +175,23 @@ _thread_malloc_init(void) { } +/* + * arc4random lock + */ +static _spinlock_lock_t arc4_lock = _SPINLOCK_UNLOCKED; + +void +_thread_arc4_lock(void) +{ + _spinlock(&arc4_lock); +} + +void +_thread_arc4_unlock(void) +{ + _spinunlock(&arc4_lock); +} + #if 0 /* * miscellaneous libc exported symbols we want to override -- cgit v1.2.3