提交 4c329696 编写于 作者: G Geoff Thorpe

Remove the dual-callback scheme for numeric and pointer thread IDs,

deprecate the original (numeric-only) scheme, and replace with the
CRYPTO_THREADID object. This hides the platform-specifics and should reduce
the possibility for programming errors (where failing to explicitly check
both thread ID forms could create subtle, platform-specific bugs).

Thanks to Bodo, for invaluable review and feedback.
上级 96826bfc
......@@ -4,6 +4,30 @@
Changes between 0.9.8i and 0.9.9 [xx XXX xxxx]
*) To cater for systems that provide a pointer-based thread ID rather
than numeric, deprecate the current numeric thread ID mechanism and
replace it with a structure and associated callback type. This
mechanism allows a numeric "hash" to be extracted from a thread ID in
either case, and on platforms where pointers are larger than 'long',
mixing is done to help ensure the numeric 'hash' is usable even if it
can't be guaranteed unique. The default mechanism is to use "&errno"
as a pointer-based thread ID to distinguish between threads.
Applications that want to provide their own thread IDs should now use
CRYPTO_THREADID_set_callback() to register a callback that will call
either CRYPTO_THREADID_set_numeric() or CRYPTO_THREADID_set_pointer().
(This new approach replaces the functions CRYPTO_set_idptr_callback(),
CRYPTO_get_idptr_callback(), and CRYPTO_thread_idptr() that existed in
OpenSSL 0.9.9-dev between June 2006 and August 2008. Also, if an
application was previously providing a numeric thread callback that
was inappropriate for distinguishing threads, then uniqueness might
have been obtained with &errno that happened immediately in the
intermediate development versions of OpenSSL; this is no longer the
case, the numeric thread callback will now override the automatic use
of &errno.)
[Geoff Thorpe, with help from Bodo Moeller]
*) Initial support for different CRL issuing certificates. This covers a
simple case where the self issued certificates in the chain exist and
the real CRL issuer is higher in the existing chain.
......@@ -307,30 +331,6 @@
list-message-digest-algorithms and list-cipher-algorithms.
[Steve Henson]
*) In addition to the numerical (unsigned long) thread ID, provide
for a pointer (void *) thread ID. This helps accomodate systems
that do not provide an unsigned long thread ID. OpenSSL assumes
it is in the same thread iff both the numerical and the pointer
thread ID agree; so applications are just required to define one
of them appropriately (e.g., by using a pointer to a per-thread
memory object malloc()ed by the application for the pointer-type
thread ID). Exactly analoguous to the existing functions
void CRYPTO_set_id_callback(unsigned long (*func)(void));
unsigned long (*CRYPTO_get_id_callback(void))(void);
unsigned long CRYPTO_thread_id(void);
we now have additional functions
void CRYPTO_set_idptr_callback(void *(*func)(void));
void *(*CRYPTO_get_idptr_callback(void))(void);
void *CRYPTO_thread_idptr(void);
also in <openssl/crypto.h>. The default value for
CRYPTO_thread_idptr() if the application has not provided its own
callback is &errno.
[Bodo Moeller]
*) Change the array representation of binary polynomials: the list
of degrees of non-zero coefficients is now terminated with -1.
Previously it was terminated with 0, which was also part of the
......
......@@ -717,9 +717,7 @@ file.
Multi-threaded applications must provide two callback functions to
OpenSSL by calling CRYPTO_set_locking_callback() and
CRYPTO_set_id_callback(). (For OpenSSL 0.9.9 or later, the new
function CRYPTO_set_idptr_callback() may be used in place of
CRYPTO_set_id_callback().) This is described in the threads(3)
CRYPTO_set_id_callback(). This is described in the threads(3)
manpage.
* I've compiled a program under Windows and it crashes: why?
......
......@@ -181,7 +181,7 @@ extern BIO *bio_err;
# define apps_shutdown() \
do { CONF_modules_unload(1); destroy_ui_method(); \
OBJ_cleanup(); EVP_cleanup(); ENGINE_cleanup(); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \
ERR_free_strings(); COMP_zlib_cleanup();} while(0)
# else
# define apps_startup() \
......@@ -191,7 +191,7 @@ extern BIO *bio_err;
# define apps_shutdown() \
do { CONF_modules_unload(1); destroy_ui_method(); \
OBJ_cleanup(); EVP_cleanup(); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \
ERR_free_strings(); } while(0)
# endif
#endif
......
......@@ -130,6 +130,7 @@
#include <stdio.h> /* FILE */
#endif
#include <openssl/ossl_typ.h>
#include <openssl/crypto.h>
#ifdef __cplusplus
extern "C" {
......@@ -564,10 +565,11 @@ int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *);
#ifndef OPENSSL_NO_DEPRECATED
unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
void *BN_BLINDING_get_thread_idptr(const BN_BLINDING *);
void BN_BLINDING_set_thread_idptr(BN_BLINDING *, void *);
#endif
CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *);
unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
......
......@@ -121,10 +121,11 @@ struct bn_blinding_st
BIGNUM *Ai;
BIGNUM *e;
BIGNUM *mod; /* just a reference */
#ifndef OPENSSL_NO_DEPRECATED
unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b;
* used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
void *thread_idptr; /* added in OpenSSL 0.9.9;
* used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
#endif
CRYPTO_THREADID tid;
unsigned int counter;
unsigned long flags;
BN_MONT_CTX *m_ctx;
......@@ -160,6 +161,7 @@ BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod)
BN_set_flags(ret->mod, BN_FLG_CONSTTIME);
ret->counter = BN_BLINDING_COUNTER;
CRYPTO_THREADID_current(&ret->tid);
return(ret);
err:
if (ret != NULL) BN_BLINDING_free(ret);
......@@ -265,6 +267,7 @@ int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *ct
return(ret);
}
#ifndef OPENSSL_NO_DEPRECATED
unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *b)
{
return b->thread_id;
......@@ -274,15 +277,11 @@ void BN_BLINDING_set_thread_id(BN_BLINDING *b, unsigned long n)
{
b->thread_id = n;
}
#endif
void *BN_BLINDING_get_thread_idptr(const BN_BLINDING *b)
CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *b)
{
return b->thread_idptr;
}
void BN_BLINDING_set_thread_idptr(BN_BLINDING *b, void *p)
{
b->thread_idptr = p;
return &b->tid;
}
unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b)
......
......@@ -187,7 +187,7 @@ int main(int argc, char *argv[])
BN_free(b);
BN_free(m);
BN_CTX_free(ctx);
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks(out);
BIO_free(out);
printf(" done\n");
......
......@@ -184,8 +184,10 @@ static void (MS_FAR *locking_callback)(int mode,int type,
const char *file,int line)=0;
static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
int type,const char *file,int line)=0;
#ifndef OPENSSL_NO_DEPRECATED
static unsigned long (MS_FAR *id_callback)(void)=0;
static void *(MS_FAR *idptr_callback)(void)=0;
#endif
static void (MS_FAR *threadid_callback)(CRYPTO_THREADID *)=0;
static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
(const char *file,int line)=0;
static void (MS_FAR *dynlock_lock_callback)(int mode,
......@@ -414,6 +416,108 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
add_lock_callback=func;
}
/* the memset() here and in set_pointer() seem overkill, but for the sake of
* CRYPTO_THREADID_cmp() this avoids any platform silliness that might cause two
* "equal" THREADID structs to not be memcmp()-identical. */
void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val)
{
memset(id, 0, sizeof(*id));
id->val = val;
}
static const unsigned char hash_coeffs[] = { 3, 5, 7, 11, 13, 17, 19, 23 };
void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr)
{
unsigned char *dest = (void *)&id->val;
unsigned int accum = 0;
unsigned char dnum = sizeof(id->val);
memset(id, 0, sizeof(*id));
id->ptr = ptr;
if (sizeof(id->val) >= sizeof(id->ptr))
{
/* 'ptr' can be embedded in 'val' without loss of uniqueness */
id->val = (unsigned long)id->ptr;
return;
}
/* hash ptr ==> val. Each byte of 'val' gets the mod-256 total of a
* linear function over the bytes in 'ptr', the co-efficients of which
* are a sequence of low-primes (hash_coeffs is an 8-element cycle) -
* the starting prime for the sequence varies for each byte of 'val'
* (unique polynomials unless pointers are >64-bit). For added spice,
* the totals accumulate rather than restarting from zero, and the index
* of the 'val' byte is added each time (position dependence). If I was
* a black-belt, I'd scan big-endian pointers in reverse to give
* low-order bits more play, but this isn't crypto and I'd prefer nobody
* mistake it as such. Plus I'm lazy. */
while (dnum--)
{
const unsigned char *src = (void *)&id->ptr;
unsigned char snum = sizeof(id->ptr);
while (snum--)
accum += *(src++) * hash_coeffs[(snum + dnum) & 7];
accum += dnum;
*(dest++) = accum & 255;
}
}
int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *))
{
if (threadid_callback)
return 0;
threadid_callback = func;
return 1;
}
void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *)
{
return threadid_callback;
}
void CRYPTO_THREADID_current(CRYPTO_THREADID *id)
{
if (threadid_callback)
{
threadid_callback(id);
return;
}
#ifndef OPENSSL_NO_DEPRECATED
/* If the deprecated callback was set, fall back to that */
if (id_callback)
{
CRYPTO_THREADID_set_numeric(id, id_callback());
return;
}
#endif
/* Else pick a backup */
#ifdef OPENSSL_SYS_WIN16
CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentTask());
#elif defined(OPENSSL_SYS_WIN32)
CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId());
#elif defined(OPENSSL_SYS_BEOS)
CRYPTO_THREADID_set_numeric(id, (unsigned long)find_thread(NULL));
#else
/* For everything else, default to using the address of 'errno' */
CRYPTO_THREADID_set_pointer(id, &errno);
#endif
}
int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b)
{
return memcmp(a, b, sizeof(*a));
}
void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src)
{
memcpy(dest, src, sizeof(*src));
}
unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id)
{
return id->val;
}
#ifndef OPENSSL_NO_DEPRECATED
unsigned long (*CRYPTO_get_id_callback(void))(void)
{
return(id_callback);
......@@ -446,33 +550,13 @@ unsigned long CRYPTO_thread_id(void)
ret=id_callback();
return(ret);
}
void *(*CRYPTO_get_idptr_callback(void))(void)
{
return(idptr_callback);
}
void CRYPTO_set_idptr_callback(void *(*func)(void))
{
idptr_callback=func;
}
void *CRYPTO_thread_idptr(void)
{
void *ret=NULL;
if (idptr_callback == NULL)
ret = &errno;
else
ret = idptr_callback();
return ret;
}
#endif
void CRYPTO_lock(int mode, int type, const char *file, int line)
{
#ifdef LOCK_DEBUG
{
CRYPTO_THREADID id;
char *rw_text,*operation_text;
if (mode & CRYPTO_LOCK)
......@@ -489,8 +573,9 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
else
rw_text="ERROR";
fprintf(stderr,"lock:%08lx/%08p:(%s)%s %-18s %s:%d\n",
CRYPTO_thread_id(), CRYPTO_thread_idptr(), rw_text, operation_text,
CRYPTO_THREADID_current(&id);
fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n",
CRYPTO_THREADID_hash(&id), rw_text, operation_text,
CRYPTO_get_lock_name(type), file, line);
}
#endif
......@@ -526,11 +611,14 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
ret=add_lock_callback(pointer,amount,type,file,line);
#ifdef LOCK_DEBUG
fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n",
CRYPTO_thread_id(), CRYPTO_thread_idptr(),
before,amount,ret,
{
CRYPTO_THREADID id;
CRYPTO_THREADID_current(&id);
fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
CRYPTO_THREADID_hash(&id), before,amount,ret,
CRYPTO_get_lock_name(type),
file,line);
}
#endif
}
else
......@@ -539,11 +627,15 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
ret= *pointer+amount;
#ifdef LOCK_DEBUG
fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n",
CRYPTO_thread_id(), CRYPTO_thread_idptr(),
{
CRYPTO_THREADID id;
CRYPTO_THREADID_current(&id);
fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
CRYPTO_THREADID_hash(&id),
*pointer,amount,ret,
CRYPTO_get_lock_name(type),
file,line);
}
#endif
*pointer=ret;
CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line);
......
......@@ -421,12 +421,27 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
const char *file, int line));
int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
const char *file,int line);
/* Don't use this structure directly. */
typedef struct crypto_threadid_st
{
void *ptr;
unsigned long val;
} CRYPTO_THREADID;
/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */
void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val);
void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr);
int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *));
void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *);
void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b);
void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src);
unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id);
#ifndef OPENSSL_NO_DEPRECATED
void CRYPTO_set_id_callback(unsigned long (*func)(void));
unsigned long (*CRYPTO_get_id_callback(void))(void);
unsigned long CRYPTO_thread_id(void);
void CRYPTO_set_idptr_callback(void *(*func)(void));
void *(*CRYPTO_get_idptr_callback(void))(void);
void *CRYPTO_thread_idptr(void);
#endif
const char *CRYPTO_get_lock_name(int type);
int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
......
......@@ -222,7 +222,7 @@ end:
ERR_print_errors(bio_err);
if (dsa != NULL) DSA_free(dsa);
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
ERR_free_strings();
CRYPTO_mem_leaks(bio_err);
if (bio_err != NULL)
......
......@@ -1326,7 +1326,7 @@ int main(int argc, char *argv[])
#endif
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks_fp(stderr);
return 0;
......
......@@ -343,7 +343,7 @@ err:
if (ctx) BN_CTX_free(ctx);
BIO_free(out);
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks_fp(stderr);
EXIT(ret);
return(ret);
......
......@@ -490,7 +490,7 @@ err:
if (ret)
ERR_print_errors(out);
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
ERR_free_strings();
CRYPTO_mem_leaks(out);
if (out != NULL)
......
......@@ -276,7 +276,7 @@ end:
ENGINE_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks_fp(stderr);
return to_return;
}
......
......@@ -429,13 +429,13 @@ static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
static unsigned long err_state_hash(const ERR_STATE *a)
{
return (a->pid + (unsigned long)a->pidptr) * 13;
return CRYPTO_THREADID_hash(&a->tid) * 13;
}
static IMPLEMENT_LHASH_HASH_FN(err_state, ERR_STATE)
static int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b)
{
return (a->pid != b->pid) || (a->pidptr != b->pidptr);
return CRYPTO_THREADID_cmp(&a->tid, &b->tid);
}
static IMPLEMENT_LHASH_COMP_FN(err_state, ERR_STATE)
......@@ -980,40 +980,37 @@ const char *ERR_reason_error_string(unsigned long e)
return((p == NULL)?NULL:p->string);
}
void ERR_remove_state(unsigned long pid)
void ERR_remove_thread_state(const CRYPTO_THREADID *id)
{
ERR_STATE tmp;
void *pidptr;
err_fns_check();
if (pid != 0)
pidptr = &errno;
if (id)
CRYPTO_THREADID_cpy(&tmp.tid, id);
else
{
pid = CRYPTO_thread_id();
pidptr = CRYPTO_thread_idptr();
}
tmp.pid=pid;
tmp.pidptr=pidptr;
CRYPTO_THREADID_current(&tmp.tid);
err_fns_check();
/* thread_del_item automatically destroys the LHASH if the number of
* items reaches zero. */
ERRFN(thread_del_item)(&tmp);
}
#ifndef OPENSSL_NO_DEPRECATED
void ERR_remove_state(unsigned long pid)
{
ERR_remove_thread_state(NULL);
}
#endif
ERR_STATE *ERR_get_state(void)
{
static ERR_STATE fallback;
ERR_STATE *ret,tmp,*tmpp=NULL;
int i;
unsigned long pid;
void *pidptr;
CRYPTO_THREADID tid;
err_fns_check();
pid = CRYPTO_thread_id();
pidptr = CRYPTO_thread_idptr();
tmp.pid = pid;
tmp.pidptr = pidptr;
CRYPTO_THREADID_current(&tid);
CRYPTO_THREADID_cpy(&tmp.tid, &tid);
ret=ERRFN(thread_get_item)(&tmp);
/* ret == the error state, if NULL, make a new one */
......@@ -1021,8 +1018,7 @@ ERR_STATE *ERR_get_state(void)
{
ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
if (ret == NULL) return(&fallback);
ret->pid=pid;
ret->pidptr=pidptr;
CRYPTO_THREADID_cpy(&ret->tid, &tid);
ret->top=0;
ret->bottom=0;
for (i=0; i<ERR_NUM_ERRORS; i++)
......
......@@ -147,8 +147,7 @@ extern "C" {
#define ERR_NUM_ERRORS 16
typedef struct err_state_st
{
unsigned long pid;
void *pidptr; /* new in OpenSSL 0.9.9 */
CRYPTO_THREADID tid;
int err_flags[ERR_NUM_ERRORS];
unsigned long err_buffer[ERR_NUM_ERRORS];
char *err_data[ERR_NUM_ERRORS];
......@@ -351,7 +350,10 @@ void ERR_load_ERR_strings(void);
void ERR_load_crypto_strings(void);
void ERR_free_strings(void);
void ERR_remove_thread_state(const CRYPTO_THREADID *tid);
#ifndef OPENSSL_NO_DEPRECATED
void ERR_remove_state(unsigned long pid); /* if zero we look it up */
#endif
ERR_STATE *ERR_get_state(void);
#ifndef OPENSSL_NO_LHASH
......
......@@ -72,8 +72,10 @@ void ERR_print_errors_cb(int (*cb)(const char *str, size_t len, void *u),
const char *file,*data;
int line,flags;
unsigned long es;
CRYPTO_THREADID cur;
es=CRYPTO_thread_id();
CRYPTO_THREADID_current(&cur);
es=CRYPTO_THREADID_hash(&cur);
while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
{
ERR_error_string_n(l, buf, sizeof buf);
......
......@@ -441,7 +441,7 @@ int main(int argc,char **argv)
#endif
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
ERR_free_strings();
CRYPTO_mem_leaks_fp(stderr);
......
......@@ -150,8 +150,7 @@ typedef struct app_mem_info_st
* CRYPTO_remove_all_info() to pop all entries.
*/
{
unsigned long thread_id;
void *thread_idptr;
CRYPTO_THREADID threadid;
const char *file;
int line;
const char *info;
......@@ -176,8 +175,7 @@ typedef struct mem_st
int num;
const char *file;
int line;
unsigned long thread_id;
void *thread_idptr;
CRYPTO_THREADID threadid;
unsigned long order;
time_t time;
APP_INFO *app_info;
......@@ -198,12 +196,10 @@ static unsigned int num_disable = 0; /* num_disable > 0
* mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE)
*/
/* The following two variables, disabling_thread_id and disabling_thread_idptr,
* are valid iff num_disable > 0. CRYPTO_LOCK_MALLOC2 is locked exactly in
* this case (by the thread named in disabling_thread_id / disabling_thread_idptr).
/* Valid iff num_disable > 0. CRYPTO_LOCK_MALLOC2 is locked exactly in this
* case (by the thread named in disabling_thread).
*/
static unsigned long disabling_thread_id = 0;
static void *disabling_thread_idptr = NULL;
static CRYPTO_THREADID disabling_threadid;
static void app_info_free(APP_INFO *inf)
{
......@@ -240,9 +236,9 @@ int CRYPTO_mem_ctrl(int mode)
case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
if (!num_disable
|| (disabling_thread_id != CRYPTO_thread_id())
|| (disabling_thread_idptr != CRYPTO_thread_idptr())) /* otherwise we already have the MALLOC2 lock */
CRYPTO_THREADID cur;
CRYPTO_THREADID_current(&cur);
if (!num_disable || CRYPTO_THREADID_cmp(&disabling_threadid, &cur)) /* otherwise we already have the MALLOC2 lock */
{
/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
* we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
......@@ -260,8 +256,7 @@ int CRYPTO_mem_ctrl(int mode)
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
disabling_thread_id=CRYPTO_thread_id();
disabling_thread_idptr=CRYPTO_thread_idptr();
CRYPTO_THREADID_cpy(&disabling_threadid, &cur);
}
num_disable++;
}
......@@ -294,11 +289,12 @@ int CRYPTO_is_mem_check_on(void)
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
CRYPTO_THREADID cur;
CRYPTO_THREADID_current(&cur);
CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
|| (disabling_thread_id != CRYPTO_thread_id())
|| (disabling_thread_idptr != CRYPTO_thread_idptr());
|| CRYPTO_THREADID_cmp(&disabling_threadid, &cur);
CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
}
......@@ -344,20 +340,17 @@ static IMPLEMENT_LHASH_HASH_FN(mem, MEM)
/* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */
static int app_info_cmp(const void *a_void, const void *b_void)
{
return (((const APP_INFO *)a_void)->thread_id != ((const APP_INFO *)b_void)->thread_id)
|| (((const APP_INFO *)a_void)->thread_idptr != ((const APP_INFO *)b_void)->thread_idptr);
return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid,
&((const APP_INFO *)b_void)->threadid);
}
static IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO)
static unsigned long app_info_hash(const APP_INFO *a)
{
unsigned long id1, id2;
unsigned long ret;
id1=(unsigned long)a->thread_id;
id2=(unsigned long)a->thread_idptr;
ret = id1 + id2;
ret = CRYPTO_THREADID_hash(&a->threadid);
/* This is left in as a "who am I to question legacy?" measure */
ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
return(ret);
}
......@@ -370,8 +363,7 @@ static APP_INFO *pop_info(void)
if (amih != NULL)
{
tmp.thread_id=CRYPTO_thread_id();
tmp.thread_idptr=CRYPTO_thread_idptr();
CRYPTO_THREADID_current(&tmp.threadid);
if ((ret=lh_APP_INFO_delete(amih,&tmp)) != NULL)
{
APP_INFO *next=ret->next;
......@@ -382,10 +374,11 @@ static APP_INFO *pop_info(void)
(void)lh_APP_INFO_insert(amih,next);
}
#ifdef LEVITTE_DEBUG_MEM
if (ret->thread_id != tmp.thread_id || ret->thread_idptr != tmp.thread_idptr)
if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid))
{
fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu/%p) than the current thread (%lu/%p)!!!!\n",
ret->thread_id, ret->thread_idptr, tmp.thread_id, tmp.thread_idptr);
fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
CRYPTO_THREADID_hash(&ret->threadid),
CRYPTO_THREADID_hash(&tmp.threadid));
abort();
}
#endif
......@@ -425,8 +418,7 @@ int CRYPTO_push_info_(const char *info, const char *file, int line)
}
}
ami->thread_id=CRYPTO_thread_id();
ami->thread_idptr=CRYPTO_thread_idptr();
CRYPTO_THREADID_current(&ami->threadid);
ami->file=file;
ami->line=line;
ami->info=info;
......@@ -436,10 +428,11 @@ int CRYPTO_push_info_(const char *info, const char *file, int line)
if ((amim=lh_APP_INFO_insert(amih,ami)) != NULL)
{
#ifdef LEVITTE_DEBUG_MEM
if (ami->thread_id != amim->thread_id || ami->thread_idptr != amim->thread_idptr)
if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid))
{
fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu/%p) than the current thread (%lu/%p)!!!!\n",
amim->thread_id, amim->thread_idptr, ami->thread_id, ami->thread_idptr);
fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
CRYPTO_THREADID_hash(&amim->threadid),
CRYPTO_THREADID_hash(&ami->threadid));
abort();
}
#endif
......@@ -525,15 +518,9 @@ void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
m->line=line;
m->num=num;
if (options & V_CRYPTO_MDEBUG_THREAD)
{
m->thread_id=CRYPTO_thread_id();
m->thread_idptr=CRYPTO_thread_idptr();
}
CRYPTO_THREADID_current(&m->threadid);
else
{
m->thread_id=0;
m->thread_idptr=NULL;
}
memset(&m->threadid, 0, sizeof(m->threadid));
if (order == break_order_num)
{
......@@ -552,8 +539,7 @@ void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
else
m->time=0;
tmp.thread_id=CRYPTO_thread_id();
tmp.thread_idptr=CRYPTO_thread_idptr();
CRYPTO_THREADID_current(&tmp.threadid);
m->app_info=NULL;
if (amih != NULL
&& (amim=lh_APP_INFO_retrieve(amih,&tmp)) != NULL)
......@@ -682,8 +668,7 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
APP_INFO *amip;
int ami_cnt;
struct tm *lcl = NULL;
unsigned long ti;
void *tip;
CRYPTO_THREADID ti;
#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
......@@ -705,7 +690,8 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
if (options & V_CRYPTO_MDEBUG_THREAD)
{
BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu/%p, ", m->thread_id, m->thread_idptr);
BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ",
CRYPTO_THREADID_hash(&m->threadid));
bufp += strlen(bufp);
}
......@@ -722,9 +708,8 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
ami_cnt=0;
if (!amip)
return;
ti=amip->thread_id;
tip=amip->thread_idptr;
CRYPTO_THREADID_cpy(&ti, &amip->threadid);
do
{
int buf_len;
......@@ -733,8 +718,9 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
ami_cnt++;
memset(buf,'>',ami_cnt);
BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
" thread=%lu/%p, file=%s, line=%d, info=\"",
amip->thread_id, amip->thread_idptr, amip->file, amip->line);
" thread=%lu, file=%s, line=%d, info=\"",
CRYPTO_THREADID_hash(&amip->threadid), amip->file,
amip->line);
buf_len=strlen(buf);
info_len=strlen(amip->info);
if (128 - buf_len - 3 < info_len)
......@@ -754,7 +740,7 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
amip = amip->next;
}
while(amip && amip->thread_id == ti && amip->thread_idptr == tip);
while(amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti));
#ifdef LEVITTE_DEBUG_MEM
if (amip)
......
......@@ -145,8 +145,7 @@ static unsigned int crypto_lock_rand = 0; /* may be set only when a thread
* holds CRYPTO_LOCK_RAND
* (to prevent double locking) */
/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */
static unsigned long locking_thread_id = 0; /* valid iff crypto_lock_rand is set */
static void *locking_thread_idptr = NULL; /* valid iff crypto_lock_rand is set */
static CRYPTO_THREADID locking_threadid; /* valid iff crypto_lock_rand is set */
#ifdef PREDICT
......@@ -214,8 +213,10 @@ static void ssleay_rand_add(const void *buf, int num, double add)
/* check if we already have the lock */
if (crypto_lock_rand)
{
CRYPTO_THREADID cur;
CRYPTO_THREADID_current(&cur);
CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
do_not_lock = (locking_thread_id == CRYPTO_thread_id()) && (locking_thread_idptr == CRYPTO_thread_idptr());
do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
}
else
......@@ -373,8 +374,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
/* prevent ssleay_rand_bytes() from trying to obtain the lock again */
CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
locking_thread_id = CRYPTO_thread_id();
locking_thread_idptr = CRYPTO_thread_idptr();
CRYPTO_THREADID_current(&locking_threadid);
CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
crypto_lock_rand = 1;
......@@ -529,15 +529,17 @@ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
static int ssleay_rand_status(void)
{
CRYPTO_THREADID cur;
int ret;
int do_not_lock;
CRYPTO_THREADID_current(&cur);
/* check if we already have the lock
* (could happen if a RAND_poll() implementation calls RAND_status()) */
if (crypto_lock_rand)
{
CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
do_not_lock = (locking_thread_id == CRYPTO_thread_id()) && (locking_thread_idptr == CRYPTO_thread_idptr());
do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
}
else
......@@ -549,8 +551,7 @@ static int ssleay_rand_status(void)
/* prevent ssleay_rand_bytes() from trying to obtain the lock again */
CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
locking_thread_id = CRYPTO_thread_id();
locking_thread_idptr = CRYPTO_thread_idptr();
CRYPTO_THREADID_cpy(&locking_threadid, &cur);
CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
crypto_lock_rand = 1;
}
......
......@@ -264,6 +264,7 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
{
BN_BLINDING *ret;
int got_write_lock = 0;
CRYPTO_THREADID cur;
CRYPTO_r_lock(CRYPTO_LOCK_RSA);
......@@ -281,7 +282,8 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
if (ret == NULL)
goto err;
if ((BN_BLINDING_get_thread_id(ret) == CRYPTO_thread_id()) && (BN_BLINDING_get_thread_idptr(ret) == CRYPTO_thread_idptr()))
CRYPTO_THREADID_current(&cur);
if (!CRYPTO_THREADID_cmp(&cur, BN_BLINDING_thread_id(ret)))
{
/* rsa->blinding is ours! */
......
......@@ -417,8 +417,7 @@ BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *in_ctx)
RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_BN_LIB);
goto err;
}
BN_BLINDING_set_thread_id(ret, CRYPTO_thread_id());
BN_BLINDING_set_thread_idptr(ret, CRYPTO_thread_idptr());
CRYPTO_THREADID_current(BN_BLINDING_thread_id(ret));
err:
BN_CTX_end(ctx);
if (in_ctx == NULL)
......
......@@ -328,7 +328,7 @@ int main(int argc, char *argv[])
}
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks_fp(stderr);
......
......@@ -22,8 +22,11 @@ functions.
BN_CTX *ctx);
int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
BN_CTX *ctx);
#ifndef OPENSSL_NO_DEPRECATED
unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
#endif
CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *);
unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
......@@ -54,11 +57,11 @@ BN_BLINDING_convert() and BN_BLINDING_invert() are wrapper
functions for BN_BLINDING_convert_ex() and BN_BLINDING_invert_ex()
with B<r> set to NULL.
BN_BLINDING_set_thread_id() and BN_BLINDING_get_thread_id()
set and get the "thread id" value of the B<BN_BLINDING> structure,
a field provided to users of B<BN_BLINDING> structure to help them
provide proper locking if needed for multi-threaded use. The
"thread id" of a newly allocated B<BN_BLINDING> structure is zero.
BN_BLINDING_thread_id() provides access to the B<CRYPTO_THREADID>
object within the B<BN_BLINDING> structure. This is to help users
provide proper locking if needed for multi-threaded use. The "thread
id" object of a newly allocated B<BN_BLINDING> structure is
initialised to the thread id in which BN_BLINDING_new() was called.
BN_BLINDING_get_flags() returns the BN_BLINDING flags. Currently
there are two supported flags: B<BN_BLINDING_NO_UPDATE> and
......@@ -83,8 +86,8 @@ BN_BLINDING_update(), BN_BLINDING_convert(), BN_BLINDING_invert(),
BN_BLINDING_convert_ex() and BN_BLINDING_invert_ex() return 1 on
success and 0 if an error occured.
BN_BLINDING_get_thread_id() returns the thread id (a B<unsigned long>
value) or 0 if not set.
BN_BLINDING_thread_id() returns a pointer to the thread id object
within a B<BN_BLINDING> object.
BN_BLINDING_get_flags() returns the currently set B<BN_BLINDING> flags
(a B<unsigned long> value).
......@@ -98,6 +101,9 @@ L<bn(3)|bn(3)>
=head1 HISTORY
BN_BLINDING_thread_id was first introduced in OpenSSL 0.9.9, and it
deprecates BN_BLINDING_set_thread_id and BN_BLINDING_get_thread_id.
BN_BLINDING_convert_ex, BN_BLINDIND_invert_ex, BN_BLINDING_get_thread_id,
BN_BLINDING_set_thread_id, BN_BLINDING_set_flags, BN_BLINDING_get_flags
and BN_BLINDING_create_param were first introduced in OpenSSL 0.9.8
......
......@@ -2,8 +2,9 @@
=head1 NAME
CRYPTO_set_locking_callback, CRYPTO_set_id_callback,
CRYPTO_set_idptr_callback, CRYPTO_num_locks,
CRYPTO_THREADID_set_callback, CRYPTO_THREADID_get_callback,
CRYPTO_THREADID_current, CRYPTO_THREADID_cmp, CRYPTO_THREADID_cpy,
CRYPTO_THREADID_hash, CRYPTO_set_locking_callback, CRYPTO_num_locks,
CRYPTO_set_dynlock_create_callback, CRYPTO_set_dynlock_lock_callback,
CRYPTO_set_dynlock_destroy_callback, CRYPTO_get_new_dynlockid,
CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support
......@@ -12,16 +13,26 @@ CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support
#include <openssl/crypto.h>
void CRYPTO_set_locking_callback(void (*locking_function)(int mode,
int n, const char *file, int line));
void CRYPTO_set_id_callback(unsigned long (*id_function)(void));
void CRYPTO_set_idptr_callback(void *(*idptr_function)(void));
/* Don't use this structure directly. */
typedef struct crypto_threadid_st
{
void *ptr;
unsigned long val;
} CRYPTO_THREADID;
/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */
void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val);
void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr);
int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *));
void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *);
void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a,
const CRYPTO_THREADID *b);
void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest,
const CRYPTO_THREADID *src);
unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id);
int CRYPTO_num_locks(void);
/* struct CRYPTO_dynlock_value needs to be defined by the user */
struct CRYPTO_dynlock_value;
......@@ -53,7 +64,8 @@ CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support
=head1 DESCRIPTION
OpenSSL can safely be used in multi-threaded applications provided
that at least two callback functions are set.
that at least two callback functions are set, locking_function and
threadid_func.
locking_function(int mode, int n, const char *file, int line) is
needed to perform locking on shared data structures.
......@@ -68,17 +80,42 @@ B<CRYPTO_LOCK>, and releases it otherwise.
B<file> and B<line> are the file number of the function setting the
lock. They can be useful for debugging.
id_function(void) is a function that returns a numerical thread ID,
for example pthread_self() if it returns an integer (see NOTES below).
By OpenSSL's defaults, this is not needed on Windows nor on platforms
where getpid() returns a different ID for each thread (see NOTES
below).
threadid_func(CRYPTO_THREADID *id) is needed to record the currently-executing
thread's identifier into B<id>. The implementation of this callback should not
fill in B<id> directly, but should use CRYPTO_THREADID_set_numeric() if thread
IDs are numeric, or CRYPTO_THREADID_set_pointer() if they are pointer-based.
If the application does not register such a callback using
CRYPTO_THREADID_set_callback(), then a default implementation is used - on
Windows and BeOS this uses the system's default thread identifying APIs, and on
all other platforms it uses the address of B<errno>. The latter is satisfactory
for thread-safety if and only if the platform has a thread-local error number
facility.
idptr_function(void) is a function that similarly returns a thread ID,
but of type void *. This is not needed on platforms where &errno is
different for each thread. OpenSSL assumes that it is in the same
thread iff both the numerical and the pointer thread ID agree, so it
suffices to define one of these two callback functions appropriately.
Once threadid_func() is registered, or if the built-in default implementation is
to be used;
=over 4
=item *
CRYPTO_THREADID_current() records the currently-executing thread ID into the
given B<id> object.
=item *
CRYPTO_THREADID_cmp() compares two thread IDs (returning zero for equality, ie.
the same semantics as memcmp()).
=item *
CRYPTO_THREADID_cpy() duplicates a thread ID value,
=item *
CRYPTO_THREADID_hash() returns a numeric value usable as a hash-table key. This
is usually the exact numeric or pointer-based thread ID used internally, however
this also handles the unusual case where pointers are larger than 'long'
variables and the platform's thread IDs are pointer-based - in this case, mixing
is done to attempt to produce a unique numeric value even though it is not as
wide as the platform's true thread IDs.
=back
Additionally, OpenSSL supports dynamic locks, and sometimes, some parts
of OpenSSL need it for better performance. To enable this, the following
......@@ -150,24 +187,6 @@ You can find out if OpenSSL was configured with thread support:
Also, dynamic locks are currently not used internally by OpenSSL, but
may do so in the future.
Defining id_function(void) has it's own issues. Generally speaking,
pthread_self() should be used, even on platforms where getpid() gives
different answers in each thread, since that may depend on the machine
the program is run on, not the machine where the program is being
compiled. For instance, Red Hat 8 Linux and earlier used
LinuxThreads, whose getpid() returns a different value for each
thread. Red Hat 9 Linux and later use NPTL, which is
Posix-conformant, and has a getpid() that returns the same value for
all threads in a process. A program compiled on Red Hat 8 and run on
Red Hat 9 will therefore see getpid() returning the same value for
all threads.
There is still the issue of platforms where pthread_self() returns
something other than an integer. It is for cases like this that
CRYPTO_set_idptr_callback() comes in handy. (E.g., call malloc(1)
once in each thread, and have idptr_function() return a pointer to
this object.)
=head1 EXAMPLES
B<crypto/threads/mttest.c> shows examples of the callback functions on
......@@ -179,8 +198,10 @@ CRYPTO_set_locking_callback() and CRYPTO_set_id_callback() are
available in all versions of SSLeay and OpenSSL.
CRYPTO_num_locks() was added in OpenSSL 0.9.4.
All functions dealing with dynamic locks were added in OpenSSL 0.9.5b-dev.
CRYPTO_set_idptr_callback() was added in OpenSSL 0.9.9.
B<CRYPTO_THREADID> and associated functions were introduced in OpenSSL 0.9.9
to replace (actually, deprecate) the previous CRYPTO_set_id_callback(),
CRYPTO_get_id_callback(), and CRYPTO_thread_id() functions which assumed
thread IDs to always be represented by 'unsigned long'.
=head1 SEE ALSO
......
......@@ -1014,7 +1014,7 @@ end:
#endif
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
ERR_remove_thread_state(NULL);
EVP_cleanup();
CRYPTO_mem_leaks(bio_err);
if (bio_err != NULL) BIO_free(bio_err);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册