From 90bbc9b76d381bccbfe370f1926941b35b5b56ec Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sun, 14 Nov 2021 14:57:15 +0100 Subject: locks: use once execution for on-demand initialization of globals This makes sure that the global variables are initialized only once. Most of those variables are initialized at ELF constructor, though a couple of occasions they are initialized on-demand: the global keylog file pointer and TPM2 TCTI context. To properly protect the initialization this patch uses gl_once provided by Gnulib. Signed-off-by: Daiki Ueno --- lib/global.c | 3 +++ lib/kx.c | 25 +++++++++++++++--------- lib/locks.c | 9 +++++++++ lib/locks.h | 5 +++++ lib/tpm2.c | 5 +++++ lib/tpm2.h | 11 +++++++++-- lib/tpm2_esys.c | 60 ++++++++++++++++++++++++++++++++++++++------------------- tests/seccomp.c | 3 +++ 8 files changed, 90 insertions(+), 31 deletions(-) diff --git a/lib/global.c b/lib/global.c index a6a23ab532..77039d9ded 100644 --- a/lib/global.c +++ b/lib/global.c @@ -420,6 +420,9 @@ static void _gnutls_global_deinit(unsigned destructor) #ifdef HAVE_TROUSERS _gnutls_tpm_global_deinit(); #endif +#ifdef HAVE_TPM2 + _gnutls_tpm2_deinit(); +#endif _gnutls_nss_keylog_deinit(); } else { diff --git a/lib/kx.c b/lib/kx.c index d69e1ef0c1..b016779e3f 100644 --- a/lib/kx.c +++ b/lib/kx.c @@ -136,19 +136,26 @@ _gnutls_nss_keylog_func(gnutls_session_t session, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-file-leak" +GNUTLS_ONCE(keylog_once); + +static void +keylog_once_init(void) +{ + const char *keylogfile; + + keylogfile = secure_getenv("SSLKEYLOGFILE"); + if (keylogfile != NULL && *keylogfile != '\0') { + keylog = fopen(keylogfile, "ae"); + _gnutls_debug_log("unable to open keylog file %s\n", + keylogfile); + } +} + void _gnutls_nss_keylog_write(gnutls_session_t session, const char *label, const uint8_t *secret, size_t secret_size) { - static const char *keylogfile = NULL; - static unsigned checked_env = 0; - - if (!checked_env) { - checked_env = 1; - keylogfile = secure_getenv("SSLKEYLOGFILE"); - if (keylogfile != NULL) - keylog = fopen(keylogfile, "ae"); - } + (void)gnutls_once(&keylog_once, keylog_once_init); if (keylog) { char client_random_hex[2*GNUTLS_RANDOM_SIZE+1]; diff --git a/lib/locks.c b/lib/locks.c index 3c05e4d988..146a806132 100644 --- a/lib/locks.c +++ b/lib/locks.c @@ -117,3 +117,12 @@ gnutls_rwlock_unlock(gnutls_rwlock_t rwlock) } return 0; } + +int +gnutls_once(gnutls_once_t once, void (*init_func) (void)) +{ + if (unlikely(glthread_once(once, init_func))) { + return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); + } + return 0; +} diff --git a/lib/locks.h b/lib/locks.h index b48d2e702b..a1ff0fa9d7 100644 --- a/lib/locks.h +++ b/lib/locks.h @@ -54,4 +54,9 @@ int gnutls_rwlock_rdlock(gnutls_rwlock_t rwlock); int gnutls_rwlock_wrlock(gnutls_rwlock_t rwlock); int gnutls_rwlock_unlock(gnutls_rwlock_t rwlock); +#define GNUTLS_ONCE(once) gl_once_define(static, once) +typedef gl_once_t *gnutls_once_t; + +int gnutls_once(gnutls_once_t once, void (*init_func) (void)); + #endif /* GNUTLS_LIB_LOCKS_H */ diff --git a/lib/tpm2.c b/lib/tpm2.c index 5c293a553c..076cc7f407 100644 --- a/lib/tpm2.c +++ b/lib/tpm2.c @@ -294,3 +294,8 @@ int _gnutls_load_tpm2_key(gnutls_privkey_t pkey, const gnutls_datum_t *fdata) gnutls_free(asn1.data); return ret; } + +void _gnutls_tpm2_deinit(void) +{ + tpm2_tcti_deinit(); +} diff --git a/lib/tpm2.h b/lib/tpm2.h index b55c2e1331..e40dc01df7 100644 --- a/lib/tpm2.h +++ b/lib/tpm2.h @@ -26,13 +26,20 @@ #include "pin.h" +/* Functions used outside tpm2.c */ + +void _gnutls_tpm2_deinit(void); +int _gnutls_load_tpm2_key(gnutls_privkey_t pkey, const gnutls_datum_t *fdata); + +/* Functions only used in tpm2.c */ + struct tpm2_info_st; struct tpm2_info_st *tpm2_info_init(struct pin_info_st *pin); -void release_tpm2_ctx(struct tpm2_info_st *info); +void tpm2_tcti_deinit(void); -int _gnutls_load_tpm2_key(gnutls_privkey_t pkey, const gnutls_datum_t *fdata); +void release_tpm2_ctx(struct tpm2_info_st *info); int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey, unsigned int parent, bool emptyauth, diff --git a/lib/tpm2_esys.c b/lib/tpm2_esys.c index d219faf1e0..93e54413ba 100644 --- a/lib/tpm2_esys.c +++ b/lib/tpm2_esys.c @@ -66,13 +66,13 @@ #include #include "tpm2.h" +#include "locks.h" #include #include #include struct tpm2_info_st { - TSS2_TCTI_CONTEXT *tcti_ctx; TPM2B_PUBLIC pub; TPM2B_PRIVATE priv; TPM2B_DIGEST userauth; @@ -85,6 +85,8 @@ struct tpm2_info_st { struct pin_info_st *pin_info; }; +static TSS2_TCTI_CONTEXT *tcti_ctx; + #define PRIMARY_HASH_ALGORITHM TPM2_ALG_SHA256 #define PRIMARY_OBJECT_ATTRIBUTES (TPMA_OBJECT_USERWITHAUTH | \ TPMA_OBJECT_RESTRICTED | \ @@ -357,7 +359,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle, _gnutls_debug_log("tpm2: establishing connection with TPM\n"); - rc = Esys_Initialize(ctx, info->tcti_ctx, NULL); + rc = Esys_Initialize(ctx, tcti_ctx, NULL); if (rc) { gnutls_assert(); _gnutls_debug_log("tpm2: Esys_Initialize failed: 0x%x\n", rc); @@ -693,9 +695,18 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo, return ret; } -int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey, - unsigned int parent, bool emptyauth, - gnutls_datum_t *privdata, gnutls_datum_t *pubdata) +GNUTLS_ONCE(tcti_once); + +void +tpm2_tcti_deinit(void) +{ + if (tcti_ctx) { + Tss2_TctiLdr_Finalize(&tcti_ctx); + } +} + +static void +tcti_once_init(void) { const char *tcti; const char * const tcti_vars[] = { @@ -707,16 +718,6 @@ int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey, size_t i; TSS2_RC rc; - if (!parent_is_persistent(parent) && - parent != TPM2_RH_OWNER && parent != TPM2_RH_NULL && - parent != TPM2_RH_ENDORSEMENT && parent != TPM2_RH_PLATFORM) { - _gnutls_debug_log("tpm2: Invalid TPM2 parent handle 0x%08x\n", - parent); - return gnutls_assert_val(GNUTLS_E_TPM_ERROR); - } - - info->parent = parent; - for (i = 0; i < sizeof(tcti_vars) / sizeof(tcti_vars[0]); i++) { tcti = secure_getenv(tcti_vars[i]); if (tcti && *tcti != '\0') { @@ -726,13 +727,35 @@ int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey, } } if (tcti && *tcti != '\0') { - rc = Tss2_TctiLdr_Initialize(tcti, &info->tcti_ctx); + rc = Tss2_TctiLdr_Initialize(tcti, &tcti_ctx); if (rc) { _gnutls_debug_log("tpm2: TSS2_TctiLdr_Initialize failed: 0x%x\n", rc); - return gnutls_assert_val(GNUTLS_E_TPM_ERROR); } } +} + +int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey, + unsigned int parent, bool emptyauth, + gnutls_datum_t *privdata, gnutls_datum_t *pubdata) +{ + TSS2_RC rc; + + (void)gnutls_once(&tcti_once, tcti_once_init); + + if (!tcti_ctx) { + return gnutls_assert_val(GNUTLS_E_TPM_ERROR); + } + + if (!parent_is_persistent(parent) && + parent != TPM2_RH_OWNER && parent != TPM2_RH_NULL && + parent != TPM2_RH_ENDORSEMENT && parent != TPM2_RH_PLATFORM) { + _gnutls_debug_log("tpm2: Invalid TPM2 parent handle 0x%08x\n", + parent); + return gnutls_assert_val(GNUTLS_E_TPM_ERROR); + } + + info->parent = parent; rc = Tss2_MU_TPM2B_PRIVATE_Unmarshal(privdata->data, privdata->size, NULL, &info->priv); @@ -781,9 +804,6 @@ void release_tpm2_ctx(struct tpm2_info_st *info) sizeof(info->ownerauth.buffer)); zeroize_key(info->userauth.buffer, sizeof(info->userauth.buffer)); - if (info->tcti_ctx) { - Tss2_TctiLdr_Finalize(&info->tcti_ctx); - } gnutls_free(info); } } diff --git a/tests/seccomp.c b/tests/seccomp.c index ed14d00298..210fc9f9a3 100644 --- a/tests/seccomp.c +++ b/tests/seccomp.c @@ -98,6 +98,9 @@ int disable_system_calls(void) ADD_SYSCALL(sigreturn, 0); ADD_SYSCALL(rt_sigreturn, 0); + /* used by gl_once_t implementation with pthread */ + ADD_SYSCALL(futex, 0); + ret = seccomp_load(ctx); if (ret < 0) { fprintf(stderr, "could not load seccomp filter"); -- cgit v1.2.1