obj: make new NIDs use tsan if possible
authorPauli <pauli@openssl.org>
Thu, 17 Jun 2021 02:41:36 +0000 (12:41 +1000)
committerPauli <ppzgs1@gmail.com>
Sat, 25 Sep 2021 00:39:20 +0000 (10:39 +1000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15713)

crypto/objects/obj_dat.c

index 04d116eafeef37d635556baf4c96c767580d4b0c..a146a96aadcd370d6e21aed34be56b13c6bd6c71 100644 (file)
@@ -12,6 +12,7 @@
 #include <limits.h>
 #include "internal/cryptlib.h"
 #include "internal/thread_once.h"
+#include "internal/tsan_assist.h"
 #include <openssl/lhash.h>
 #include <openssl/asn1.h>
 #include "crypto/objects.h"
 /* obj_dat.h is generated from objects.h by obj_dat.pl */
 #include "obj_dat.h"
 
+/*
+ * If we don't have suitable TSAN support, we'll use a lock for generation of
+ * new NIDs.  This will be slower of course.
+ */
+#ifndef tsan_ld_acq
+# define OBJ_USE_LOCK_FOR_NEW_NID
+#endif
+
 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn);
 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln);
 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj);
@@ -36,19 +45,41 @@ struct added_obj_st {
     ASN1_OBJECT *obj;
 };
 
-static int new_nid = NUM_NID;
 static LHASH_OF(ADDED_OBJ) *added = NULL;
 static CRYPTO_RWLOCK *ossl_obj_lock = NULL;
+#ifdef OBJ_USE_LOCK_FOR_NEW_NID
+static CRYPTO_RWLOCK *ossl_obj_nid_lock = NULL;
+#endif
 
 static CRYPTO_ONCE ossl_obj_lock_init = CRYPTO_ONCE_STATIC_INIT;
 
+static ossl_inline void objs_free_locks(void)
+{
+    CRYPTO_THREAD_lock_free(ossl_obj_lock);
+    ossl_obj_lock = NULL;
+#ifdef OBJ_USE_LOCK_FOR_NEW_NID
+    CRYPTO_THREAD_lock_free(ossl_obj_nid_lock);
+    ossl_obj_nid_lock = NULL;
+#endif
+}
+
 DEFINE_RUN_ONCE_STATIC(obj_lock_initialise)
 {
     /* Make sure we've loaded config before checking for any "added" objects */
     OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
 
     ossl_obj_lock = CRYPTO_THREAD_lock_new();
-    return ossl_obj_lock != NULL;
+    if (ossl_obj_lock == NULL)
+        return 0;
+
+#ifdef OBJ_USE_LOCK_FOR_NEW_NID
+    ossl_obj_nid_lock = CRYPTO_THREAD_lock_new();
+    if (ossl_obj_nid_lock == NULL) {
+        objs_free_locks();
+        return 0;
+    }
+#endif
+    return 1;
 }
 
 static ossl_inline int ossl_init_added_lock(void)
@@ -58,16 +89,20 @@ static ossl_inline int ossl_init_added_lock(void)
 
 static ossl_inline int ossl_obj_write_lock(int lock)
 {
+    if (!lock)
+        return 1;
     if (!ossl_init_added_lock())
         return 0;
-    return !lock || CRYPTO_THREAD_write_lock(ossl_obj_lock);
+    return CRYPTO_THREAD_write_lock(ossl_obj_lock);
 }
 
 static ossl_inline int ossl_obj_read_lock(int lock)
 {
+    if (!lock)
+        return 1;
     if (!ossl_init_added_lock())
         return 0;
-    return !lock || CRYPTO_THREAD_read_lock(ossl_obj_lock);
+    return CRYPTO_THREAD_read_lock(ossl_obj_lock);
 }
 
 static ossl_inline void ossl_obj_unlock(int lock)
@@ -190,12 +225,13 @@ void ossl_obj_cleanup_int(void)
         lh_ADDED_OBJ_free(added);
         added = NULL;
     }
-    CRYPTO_THREAD_lock_free(ossl_obj_lock);
-    ossl_obj_lock = NULL;
+    objs_free_locks();
 }
 
-static int ossl_obj_new_nid(int num, int lock)
+int OBJ_new_nid(int num)
 {
+#ifdef OBJ_USE_LOCK_FOR_NEW_NID
+    static int new_nid = NUM_NID;
     int i;
 
     if (!CRYPTO_THREAD_write_lock(ossl_obj_nid_lock)) {
@@ -204,8 +240,13 @@ static int ossl_obj_new_nid(int num, int lock)
     }
     i = new_nid;
     new_nid += num;
-    ossl_obj_unlock(lock);
+    CRYPTO_THREAD_unlock(ossl_obj_nid_lock);
     return i;
+#else
+    static TSAN_QUALIFIER int new_nid = NUM_NID;
+
+    return tsan_add(&new_nid, num);
+#endif
 }
 
 static int ossl_obj_add_object(const ASN1_OBJECT *obj, int lock)
@@ -721,7 +762,7 @@ int OBJ_create(const char *oid, const char *sn, const char *ln)
         goto err;
     }
 
-    tmpoid->nid = ossl_obj_new_nid(1, 0);
+    tmpoid->nid = OBJ_new_nid(1);
     tmpoid->sn = (char *)sn;
     tmpoid->ln = (char *)ln;
 
@@ -750,11 +791,6 @@ const unsigned char *OBJ_get0_data(const ASN1_OBJECT *obj)
     return obj->data;
 }
 
-int OBJ_new_nid(int num)
-{
-    return ossl_obj_new_nid(num, 1);
-}
-
 int OBJ_add_object(const ASN1_OBJECT *obj)
 {
     return ossl_obj_add_object(obj, 1);