From 72592b866492b84ba5ca1251d1a45875764c7b27 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 24 May 2019 17:52:17 +0100 Subject: [PATCH] Split thread intialisation and handling out of init.c We're going to need some of these functions in the FIPS module, but most of the rest of the code in init.c is not needed. Therefore we split it out. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9040) --- crypto/include/internal/cryptlib_int.h | 2 + crypto/init.c | 119 ++--------------------- crypto/initthread.c | 129 +++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 113 deletions(-) create mode 100644 crypto/initthread.c diff --git a/crypto/include/internal/cryptlib_int.h b/crypto/include/internal/cryptlib_int.h index b3529dcaf9..e810ef02eb 100644 --- a/crypto/include/internal/cryptlib_int.h +++ b/crypto/include/internal/cryptlib_int.h @@ -14,6 +14,8 @@ typedef void (*ossl_thread_stop_handler_fn)(OPENSSL_CTX *ctx); int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn); +int init_thread(void); +void cleanup_thread(void); /* * OPENSSL_INIT flags. The primary list of these is in crypto.h. Flags below diff --git a/crypto/init.c b/crypto/init.c index 7512a1e9d6..fd24e4f50b 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -31,58 +31,6 @@ static int stopped = 0; -typedef struct thread_event_handler_st THREAD_EVENT_HANDLER; -struct thread_event_handler_st { - OPENSSL_CTX *ctx; - ossl_thread_stop_handler_fn handfn; - THREAD_EVENT_HANDLER *next; -}; - -/* - * Since per-thread-specific-data destructors are not universally - * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key - * is assumed to have destructor associated. And then an effort is made - * to call this single destructor on non-pthread platform[s]. - * - * Initial value is "impossible". It is used as guard value to shortcut - * destructor for threads terminating before libcrypto is initialized or - * after it's de-initialized. Access to the key doesn't have to be - * serialized for the said threads, because they didn't use libcrypto - * and it doesn't matter if they pick "impossible" or derefernce real - * key value and pull NULL past initialization in the first thread that - * intends to use libcrypto. - */ -static union { - long sane; - CRYPTO_THREAD_LOCAL value; -} destructor_key = { -1 }; - -static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands); - -static void ossl_init_thread_destructor(void *hands) -{ - ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands); -} - -static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc) -{ - THREAD_EVENT_HANDLER **hands = - CRYPTO_THREAD_get_local(&destructor_key.value); - - if (alloc) { - if (hands == NULL - && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL - && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) { - OPENSSL_free(hands); - return NULL; - } - } else { - CRYPTO_THREAD_set_local(&destructor_key.value, NULL); - } - - return hands; -} - typedef struct ossl_init_stop_st OPENSSL_INIT_STOP; struct ossl_init_stop_st { void (*handler)(void); @@ -96,8 +44,6 @@ static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT; static int base_inited = 0; DEFINE_RUN_ONCE_STATIC(ossl_init_base) { - CRYPTO_THREAD_LOCAL key; - if (ossl_trace_init() == 0) return 0; @@ -105,13 +51,14 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) #ifndef OPENSSL_NO_CRYPTO_MDEBUG ossl_malloc_setup_failures(); #endif - if (!CRYPTO_THREAD_init_local(&key, ossl_init_thread_destructor)) - return 0; + if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL) goto err; OPENSSL_cpuid_setup(); - destructor_key.value = key; + if (!init_thread()) + return 0; + base_inited = 1; return 1; @@ -120,7 +67,6 @@ err: CRYPTO_THREAD_lock_free(init_lock); init_lock = NULL; - CRYPTO_THREAD_cleanup_local(&key); return 0; } @@ -424,60 +370,9 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_zlib) } #endif -static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands) -{ - THREAD_EVENT_HANDLER *curr, *prev = NULL; - - /* Can't do much about this */ - if (hands == NULL) - return; - - curr = *hands; - while (curr != NULL) { - curr->handfn(curr->ctx); - prev = curr; - curr = curr->next; - OPENSSL_free(prev); - } - - OPENSSL_free(hands); -} - -void OPENSSL_thread_stop(void) -{ - if (destructor_key.sane != -1) - ossl_init_thread_stop(ossl_init_get_thread_local(0)); -} - -int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn) -{ - THREAD_EVENT_HANDLER **hands; - THREAD_EVENT_HANDLER *hand; - - if (!OPENSSL_init_crypto(0, NULL)) - return 0; - - hands = ossl_init_get_thread_local(1); - - if (hands == NULL) - return 0; - - hand = OPENSSL_malloc(sizeof(*hand)); - if (hand == NULL) - return 0; - - hand->handfn = handfn; - hand->ctx = ctx; - hand->next = *hands; - *hands = hand; - - return 1; -} - void OPENSSL_cleanup(void) { OPENSSL_INIT_STOP *currhandler, *lasthandler; - CRYPTO_THREAD_LOCAL key; /* * TODO(3.0): This function needs looking at with a view to moving most/all @@ -497,7 +392,7 @@ void OPENSSL_cleanup(void) * Thread stop may not get automatically called by the thread library for * the very last thread in some situations, so call it directly. */ - ossl_init_thread_stop(ossl_init_get_thread_local(0)); + OPENSSL_thread_stop(); currhandler = stop_handlers; while (currhandler != NULL) { @@ -533,9 +428,7 @@ void OPENSSL_cleanup(void) err_free_strings_int(); } - key = destructor_key.value; - destructor_key.sane = -1; - CRYPTO_THREAD_cleanup_local(&key); + cleanup_thread(); /* * Note that cleanup order is important: diff --git a/crypto/initthread.c b/crypto/initthread.c new file mode 100644 index 0000000000..6e56d47338 --- /dev/null +++ b/crypto/initthread.c @@ -0,0 +1,129 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include "internal/cryptlib_int.h" + +typedef struct thread_event_handler_st THREAD_EVENT_HANDLER; +struct thread_event_handler_st { + OPENSSL_CTX *ctx; + ossl_thread_stop_handler_fn handfn; + THREAD_EVENT_HANDLER *next; +}; + +/* + * Since per-thread-specific-data destructors are not universally + * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key + * is assumed to have destructor associated. And then an effort is made + * to call this single destructor on non-pthread platform[s]. + * + * Initial value is "impossible". It is used as guard value to shortcut + * destructor for threads terminating before libcrypto is initialized or + * after it's de-initialized. Access to the key doesn't have to be + * serialized for the said threads, because they didn't use libcrypto + * and it doesn't matter if they pick "impossible" or derefernce real + * key value and pull NULL past initialization in the first thread that + * intends to use libcrypto. + */ +static union { + long sane; + CRYPTO_THREAD_LOCAL value; +} destructor_key = { -1 }; + +static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands); + +static void ossl_init_thread_destructor(void *hands) +{ + ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands); +} + +int init_thread(void) +{ + + if (!CRYPTO_THREAD_init_local(&destructor_key.value, + ossl_init_thread_destructor)) + return 0; + + return 1; +} + +void cleanup_thread(void) +{ + CRYPTO_THREAD_cleanup_local(&destructor_key.value); + destructor_key.sane = -1; +} + +static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc) +{ + THREAD_EVENT_HANDLER **hands = + CRYPTO_THREAD_get_local(&destructor_key.value); + + if (alloc) { + if (hands == NULL + && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL + && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) { + OPENSSL_free(hands); + return NULL; + } + } else { + CRYPTO_THREAD_set_local(&destructor_key.value, NULL); + } + + return hands; +} + +static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands) +{ + THREAD_EVENT_HANDLER *curr, *prev = NULL; + + /* Can't do much about this */ + if (hands == NULL) + return; + + curr = *hands; + while (curr != NULL) { + curr->handfn(curr->ctx); + prev = curr; + curr = curr->next; + OPENSSL_free(prev); + } + + OPENSSL_free(hands); +} + +void OPENSSL_thread_stop(void) +{ + if (destructor_key.sane != -1) + ossl_init_thread_stop(ossl_init_get_thread_local(0)); +} + +int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn) +{ + THREAD_EVENT_HANDLER **hands; + THREAD_EVENT_HANDLER *hand; + + if (!OPENSSL_init_crypto(0, NULL)) + return 0; + + hands = ossl_init_get_thread_local(1); + + if (hands == NULL) + return 0; + + hand = OPENSSL_malloc(sizeof(*hand)); + if (hand == NULL) + return 0; + + hand->handfn = handfn; + hand->ctx = ctx; + hand->next = *hands; + *hands = hand; + + return 1; +}