Use a more fine-grained lock in by_dir.c

Different BY_DIR_ENTRYs don't need to share a lock. Also switch some
code to use OPENSSL_strndup.

Change-Id: I3809e001afb9577bb96aab214e80e173900356fe
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/66012
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c
index 5eca97b..d49220d 100644
--- a/crypto/x509/by_dir.c
+++ b/crypto/x509/by_dir.c
@@ -72,6 +72,7 @@
 } BY_DIR_HASH;
 
 typedef struct lookup_dir_entry_st {
+  CRYPTO_MUTEX lock;
   char *dir;
   int dir_type;
   STACK_OF(BY_DIR_HASH) *hashes;
@@ -156,6 +157,7 @@
 
 static void by_dir_entry_free(BY_DIR_ENTRY *ent) {
   if (ent != NULL) {
+    CRYPTO_MUTEX_cleanup(&ent->lock);
     OPENSSL_free(ent->dir);
     sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free);
     OPENSSL_free(ent);
@@ -215,15 +217,12 @@
       if (!ent) {
         return 0;
       }
+      CRYPTO_MUTEX_init(&ent->lock);
       ent->dir_type = type;
       ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
-      ent->dir = OPENSSL_malloc(len + 1);
-      if (!ent->dir || !ent->hashes) {
-        by_dir_entry_free(ent);
-        return 0;
-      }
-      OPENSSL_strlcpy(ent->dir, ss, len + 1);
-      if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
+      ent->dir = OPENSSL_strndup(ss, len);
+      if (ent->dir == NULL || ent->hashes == NULL ||
+          !sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
         by_dir_entry_free(ent);
         return 0;
       }
@@ -232,10 +231,6 @@
   return 1;
 }
 
-// g_ent_hashes_lock protects the |hashes| member of all |BY_DIR_ENTRY|
-// objects.
-static CRYPTO_MUTEX g_ent_hashes_lock = CRYPTO_MUTEX_INIT;
-
 static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
                                X509_OBJECT *ret) {
   union {
@@ -300,7 +295,7 @@
       }
       if (type == X509_LU_CRL && ent->hashes) {
         htmp.hash = h;
-        CRYPTO_MUTEX_lock_read(&g_ent_hashes_lock);
+        CRYPTO_MUTEX_lock_read(&ent->lock);
         if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp)) {
           hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
           k = hent->suffix;
@@ -308,7 +303,7 @@
           hent = NULL;
           k = 0;
         }
-        CRYPTO_MUTEX_unlock_read(&g_ent_hashes_lock);
+        CRYPTO_MUTEX_unlock_read(&ent->lock);
       } else {
         k = 0;
         hent = NULL;
@@ -341,7 +336,7 @@
       // If a CRL, update the last file suffix added for this
 
       if (type == X509_LU_CRL) {
-        CRYPTO_MUTEX_lock_write(&g_ent_hashes_lock);
+        CRYPTO_MUTEX_lock_write(&ent->lock);
         // Look for entry again in case another thread added an entry
         // first.
         if (!hent) {
@@ -354,14 +349,14 @@
         if (!hent) {
           hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
           if (hent == NULL) {
-            CRYPTO_MUTEX_unlock_write(&g_ent_hashes_lock);
+            CRYPTO_MUTEX_unlock_write(&ent->lock);
             ok = 0;
             goto finish;
           }
           hent->hash = h;
           hent->suffix = k;
           if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
-            CRYPTO_MUTEX_unlock_write(&g_ent_hashes_lock);
+            CRYPTO_MUTEX_unlock_write(&ent->lock);
             OPENSSL_free(hent);
             ok = 0;
             goto finish;
@@ -371,7 +366,7 @@
           hent->suffix = k;
         }
 
-        CRYPTO_MUTEX_unlock_write(&g_ent_hashes_lock);
+        CRYPTO_MUTEX_unlock_write(&ent->lock);
       }
 
       if (tmp != NULL) {