summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@gnu.org>2021-11-14 14:57:15 +0100
committerDaiki Ueno <ueno@gnu.org>2021-11-17 08:08:29 +0100
commit90bbc9b76d381bccbfe370f1926941b35b5b56ec (patch)
tree0540a1ee9079cfa755b929eea86aa15c0f6f2b34
parentbcffed047f7a228cf99028eb2b8249e5a02eb2e6 (diff)
downloadgnutls-90bbc9b76d381bccbfe370f1926941b35b5b56ec.tar.gz
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 <ueno@gnu.org>
-rw-r--r--lib/global.c3
-rw-r--r--lib/kx.c25
-rw-r--r--lib/locks.c9
-rw-r--r--lib/locks.h5
-rw-r--r--lib/tpm2.c5
-rw-r--r--lib/tpm2.h11
-rw-r--r--lib/tpm2_esys.c60
-rw-r--r--tests/seccomp.c3
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 <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);
}
}
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");