diff --git a/crypto/include/internal/x509_int.h b/crypto/include/internal/x509_int.h index 124cc533bc562c6258cf842513d876dbcb7b7e8a..1638de4c32556467a9242deb70beac4f545fd39a 100644 --- a/crypto/include/internal/x509_int.h +++ b/crypto/include/internal/x509_int.h @@ -182,6 +182,7 @@ struct x509_st { unsigned char sha1_hash[SHA_DIGEST_LENGTH]; X509_CERT_AUX *aux; CRYPTO_RWLOCK *lock; + volatile int ex_cached; } /* X509 */ ; /* diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index d804106788e3748c32fe1cad4f5a0473814feecc..5a535e2adeb6f39f9202f2770bc9a4b15a09bece 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -13,6 +13,7 @@ #include #include #include "internal/x509_int.h" +#include "internal/tsan_assist.h" static void x509v3_cache_extensions(X509 *x); @@ -353,6 +354,10 @@ static void x509v3_cache_extensions(X509 *x) X509_EXTENSION *ex; int i; + /* fast lock-free check, see end of the function for details. */ + if (tsan_load((TSAN_QUALIFIER int *)&x->ex_cached)) + return; + CRYPTO_THREAD_write_lock(x->lock); if (x->ex_flags & EXFLAG_SET) { CRYPTO_THREAD_unlock(x->lock); @@ -494,6 +499,12 @@ static void x509v3_cache_extensions(X509 *x) x509_init_sig_info(x); x->ex_flags |= EXFLAG_SET; CRYPTO_THREAD_unlock(x->lock); + /* + * It has to be placed after memory barrier, which is implied by unlock. + * Worst thing that can happen is that another thread proceeds to lock + * and checks x->ex_flags & EXFLAGS_SET. See beginning of the function. + */ + tsan_store((TSAN_QUALIFIER int *)&x->ex_cached, 1); } /*-