Commit ad6019d6 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Move locking and thread ID functions into new files lock.c and thr_id.c,

redirect locking to minimal FIPS_lock() function where required.
parent a27de7b7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -34,8 +34,8 @@ GENERAL=Makefile README crypto-lib.com install.com

LIB= $(TOP)/libcrypto.a
SHARED_LIB= libcrypto$(SHLIB_EXT)
LIBSRC=	cryptlib.c mem.c mem_clr.c mem_dbg.c cversion.c ex_data.c cpt_err.c ebcdic.c uid.c o_time.c o_str.c o_dir.c
LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o cpt_err.o ebcdic.o uid.o o_time.o o_str.o o_dir.o $(CPUID_OBJ)
LIBSRC=	cryptlib.c mem.c mem_clr.c mem_dbg.c cversion.c ex_data.c cpt_err.c ebcdic.c uid.c o_time.c o_str.c o_dir.c thr_id.c lock.c
LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o cpt_err.o ebcdic.o uid.o o_time.o o_str.o o_dir.o thr_id.o lock.o $(CPUID_OBJ)

SRC= $(LIBSRC)

+0 −536
Original line number Diff line number Diff line
@@ -121,542 +121,6 @@
static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
#endif

DECLARE_STACK_OF(CRYPTO_dynlock)

/* real #defines in crypto.h, keep these upto date */
static const char* const lock_names[CRYPTO_NUM_LOCKS] =
	{
	"<<ERROR>>",
	"err",
	"ex_data",
	"x509",
	"x509_info",
	"x509_pkey",
	"x509_crl",
	"x509_req",
	"dsa",
	"rsa",
	"evp_pkey",
	"x509_store",
	"ssl_ctx",
	"ssl_cert",
	"ssl_session",
	"ssl_sess_cert",
	"ssl",
	"ssl_method",
	"rand",
	"rand2",
	"debug_malloc",
	"BIO",
	"gethostbyname",
	"getservbyname",
	"readdir",
	"RSA_blinding",
	"dh",
	"debug_malloc2",
	"dso",
	"dynlock",
	"engine",
	"ui",
	"ecdsa",
	"ec",
	"ecdh",
	"bn",
	"ec_pre_comp",
	"store",
	"comp",
	"fips",
	"fips2",
#if CRYPTO_NUM_LOCKS != 41
# error "Inconsistency between crypto.h and cryptlib.c"
#endif
	};

/* This is for applications to allocate new type names in the non-dynamic
   array of lock names.  These are numbered with positive numbers.  */
static STACK_OF(OPENSSL_STRING) *app_locks=NULL;

/* For applications that want a more dynamic way of handling threads, the
   following stack is used.  These are externally numbered with negative
   numbers.  */
static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL;


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;
#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,
	struct CRYPTO_dynlock_value *l, const char *file,int line)=0;
static void (MS_FAR *dynlock_destroy_callback)(struct CRYPTO_dynlock_value *l,
	const char *file,int line)=0;

int CRYPTO_get_new_lockid(char *name)
	{
	char *str;
	int i;

#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
	/* A hack to make Visual C++ 5.0 work correctly when linking as
	 * a DLL using /MT. Without this, the application cannot use
	 * any floating point printf's.
	 * It also seems to be needed for Visual C 1.5 (win16) */
	SSLeay_MSVC5_hack=(double)name[0]*(double)name[1];
#endif

	if ((app_locks == NULL) && ((app_locks=sk_OPENSSL_STRING_new_null()) == NULL))
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	if ((str=BUF_strdup(name)) == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	i=sk_OPENSSL_STRING_push(app_locks,str);
	if (!i)
		OPENSSL_free(str);
	else
		i+=CRYPTO_NUM_LOCKS; /* gap of one :-) */
	return(i);
	}

int CRYPTO_num_locks(void)
	{
	return CRYPTO_NUM_LOCKS;
	}

int CRYPTO_get_new_dynlockid(void)
	{
	int i = 0;
	CRYPTO_dynlock *pointer = NULL;

	if (dynlock_create_callback == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
		return(0);
		}
	CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
	if ((dyn_locks == NULL)
		&& ((dyn_locks=sk_CRYPTO_dynlock_new_null()) == NULL))
		{
		CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);

	pointer = (CRYPTO_dynlock *)OPENSSL_malloc(sizeof(CRYPTO_dynlock));
	if (pointer == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	pointer->references = 1;
	pointer->data = dynlock_create_callback(__FILE__,__LINE__);
	if (pointer->data == NULL)
		{
		OPENSSL_free(pointer);
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}

	CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
	/* First, try to find an existing empty slot */
	i=sk_CRYPTO_dynlock_find(dyn_locks,NULL);
	/* If there was none, push, thereby creating a new one */
	if (i == -1)
		/* Since sk_push() returns the number of items on the
		   stack, not the location of the pushed item, we need
		   to transform the returned number into a position,
		   by decreasing it.  */
		i=sk_CRYPTO_dynlock_push(dyn_locks,pointer) - 1;
	else
		/* If we found a place with a NULL pointer, put our pointer
		   in it.  */
		(void)sk_CRYPTO_dynlock_set(dyn_locks,i,pointer);
	CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);

	if (i == -1)
		{
		dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
		OPENSSL_free(pointer);
		}
	else
		i += 1; /* to avoid 0 */
	return -i;
	}

void CRYPTO_destroy_dynlockid(int i)
	{
	CRYPTO_dynlock *pointer = NULL;
	if (i)
		i = -i-1;
	if (dynlock_destroy_callback == NULL)
		return;

	CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);

	if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
		{
		CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
		return;
		}
	pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
	if (pointer != NULL)
		{
		--pointer->references;
#ifdef REF_CHECK
		if (pointer->references < 0)
			{
			fprintf(stderr,"CRYPTO_destroy_dynlockid, bad reference count\n");
			abort();
			}
		else
#endif
			if (pointer->references <= 0)
				{
				(void)sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
				}
			else
				pointer = NULL;
		}
	CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);

	if (pointer)
		{
		dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
		OPENSSL_free(pointer);
		}
	}

struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i)
	{
	CRYPTO_dynlock *pointer = NULL;
	if (i)
		i = -i-1;

	CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);

	if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks))
		pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
	if (pointer)
		pointer->references++;

	CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);

	if (pointer)
		return pointer->data;
	return NULL;
	}

struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))
	(const char *file,int line)
	{
	return(dynlock_create_callback);
	}

void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,
	struct CRYPTO_dynlock_value *l, const char *file,int line)
	{
	return(dynlock_lock_callback);
	}

void (*CRYPTO_get_dynlock_destroy_callback(void))
	(struct CRYPTO_dynlock_value *l, const char *file,int line)
	{
	return(dynlock_destroy_callback);
	}

void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func)
	(const char *file, int line))
	{
	dynlock_create_callback=func;
	}

void CRYPTO_set_dynlock_lock_callback(void (*func)(int mode,
	struct CRYPTO_dynlock_value *l, const char *file, int line))
	{
	dynlock_lock_callback=func;
	}

void CRYPTO_set_dynlock_destroy_callback(void (*func)
	(struct CRYPTO_dynlock_value *l, const char *file, int line))
	{
	dynlock_destroy_callback=func;
	}


void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
		int line)
	{
	return(locking_callback);
	}

int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
					  const char *file,int line)
	{
	return(add_lock_callback);
	}

void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
					      const char *file,int line))
	{
	locking_callback=func;
	}

void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
					      const char *file,int line))
	{
	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);
	}

void CRYPTO_set_id_callback(unsigned long (*func)(void))
	{
	id_callback=func;
	}

unsigned long CRYPTO_thread_id(void)
	{
	unsigned long ret=0;

	if (id_callback == NULL)
		{
#ifdef OPENSSL_SYS_WIN16
		ret=(unsigned long)GetCurrentTask();
#elif defined(OPENSSL_SYS_WIN32)
		ret=(unsigned long)GetCurrentThreadId();
#elif defined(GETPID_IS_MEANINGLESS)
		ret=1L;
#elif defined(OPENSSL_SYS_BEOS)
		ret=(unsigned long)find_thread(NULL);
#else
		ret=(unsigned long)getpid();
#endif
		}
	else
		ret=id_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)
			operation_text="lock  ";
		else if (mode & CRYPTO_UNLOCK)
			operation_text="unlock";
		else
			operation_text="ERROR ";

		if (mode & CRYPTO_READ)
			rw_text="r";
		else if (mode & CRYPTO_WRITE)
			rw_text="w";
		else
			rw_text="ERROR";

		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
	if (type < 0)
		{
		if (dynlock_lock_callback != NULL)
			{
			struct CRYPTO_dynlock_value *pointer
				= CRYPTO_get_dynlock_value(type);

			OPENSSL_assert(pointer != NULL);

			dynlock_lock_callback(mode, pointer, file, line);

			CRYPTO_destroy_dynlockid(type);
			}
		}
	else
		if (locking_callback != NULL)
			locking_callback(mode,type,file,line);
	}

int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
	     int line)
	{
	int ret = 0;

	if (add_lock_callback != NULL)
		{
#ifdef LOCK_DEBUG
		int before= *pointer;
#endif

		ret=add_lock_callback(pointer,amount,type,file,line);
#ifdef LOCK_DEBUG
		{
		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
		{
		CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,file,line);

		ret= *pointer+amount;
#ifdef LOCK_DEBUG
		{
		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);
		}
	return(ret);
	}

const char *CRYPTO_get_lock_name(int type)
	{
	if (type < 0)
		return("dynamic");
	else if (type < CRYPTO_NUM_LOCKS)
		return(lock_names[type]);
	else if (type-CRYPTO_NUM_LOCKS > sk_OPENSSL_STRING_num(app_locks))
		return("ERROR");
	else
		return(sk_OPENSSL_STRING_value(app_locks,type-CRYPTO_NUM_LOCKS));
	}

#if	defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
	defined(__INTEL__) || \
	defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+4 −0
Original line number Diff line number Diff line
@@ -249,6 +249,10 @@ typedef struct openssl_item_st
#define CRYPTO_add(a,b,c)	((*(a))+=(b))
#endif

#if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSEVP)
#define CRYPTO_lock FIPS_lock
#endif

/* Some applications as well as some parts of OpenSSL need to allocate
   and deallocate locks in a dynamic fashion.  The following typedef
   makes this possible in a type-safe manner.  */

crypto/lock.c

0 → 100644
+518 −0

File added.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ static void (*free_locked_func)(void *) = free;

/* may be changed as long as 'allow_customize_debug' is set */
/* XXX use correct function pointer types */
#ifdef CRYPTO_MDEBUG
#if defined(CRYPTO_MDEBUG) && !defined(OPENSSL_FIPSCANISTER)
/* use default functions from mem_dbg.c */
static void (*malloc_debug_func)(void *,int,const char *,int,int)
	= CRYPTO_dbg_malloc;
Loading