]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
locks: use once execution for on-demand initialization of globals
authorDaiki Ueno <ueno@gnu.org>
Sun, 14 Nov 2021 13:57:15 +0000 (14:57 +0100)
committerDaiki Ueno <ueno@gnu.org>
Wed, 17 Nov 2021 07:08:29 +0000 (08:08 +0100)
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 <ueno@gnu.org>
lib/global.c
lib/kx.c
lib/locks.c
lib/locks.h
lib/tpm2.c
lib/tpm2.h
lib/tpm2_esys.c
tests/seccomp.c

index a6a23ab532784f1e5b739285be5d7be03ab6d9f5..77039d9dedc072d64879223a775f1707b4ad6d3b 100644 (file)
@@ -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 {
index d69e1ef0c1a24426bfeb7c1c9d30ddd45145b160..b016779e3f42b572cc038a88d97bd8e9013169e1 100644 (file)
--- 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];
index 3c05e4d98852b38868858b8b4ca7c96b1d646d0f..146a80613280ee65f8fa02a73817d113a713a3c0 100644 (file)
@@ -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;
+}
index b48d2e702b2ff83ededd5169f49bbb49a33962bf..a1ff0fa9d7782f054d8a76cd3020cc2c837527b2 100644 (file)
@@ -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 */
index 5c293a553c1314ddbb853a8a187f8d9484eb9308..076cc7f4077b7f84cb9674399e6936e3fddd981c 100644 (file)
@@ -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();
+}
index b55c2e1331d8550a549770addd485dc993d6ca37..e40dc01df707f4c37be095f857c6a3e6c5dda3bb 100644 (file)
 
 #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,
index d219faf1e0b44f835d2b3a9191ad59bc7007de4f..93e54413ba4a40a384a79236d1d8137aeadef440 100644 (file)
 #include <string.h>
 
 #include "tpm2.h"
+#include "locks.h"
 
 #include <tss2/tss2_mu.h>
 #include <tss2/tss2_esys.h>
 #include <tss2/tss2_tctildr.h>
 
 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);
        }
 }
index ed14d002983a9c122bd972a60ede8c07de4f109e..210fc9f9a347caaac45688a41b95bd6f4f63f8b5 100644 (file)
@@ -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");