]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
locks: rework rwlock primitives
authorDaiki Ueno <ueno@gnu.org>
Sun, 14 Nov 2021 15:39:29 +0000 (16:39 +0100)
committerDaiki Ueno <ueno@gnu.org>
Wed, 17 Nov 2021 06:38:35 +0000 (07:38 +0100)
Remove GNUTLS_STATIC_RWLOCK_*LOCK macros and respect return values of
rwlock primitives.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/locks.c
lib/locks.h
lib/priority.c

index 67f4e1b329f764efa264c74fb9f1dc31e66807e4..3c05e4d98852b38868858b8b4ca7c96b1d646d0f 100644 (file)
@@ -90,3 +90,30 @@ gnutls_static_mutex_unlock(gnutls_static_mutex_t lock)
        }
        return 0;
 }
+
+int
+gnutls_rwlock_rdlock(gnutls_rwlock_t rwlock)
+{
+       if (unlikely(glthread_rwlock_rdlock(rwlock))) {
+               return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
+       }
+       return 0;
+}
+
+int
+gnutls_rwlock_wrlock(gnutls_rwlock_t rwlock)
+{
+       if (unlikely(glthread_rwlock_wrlock(rwlock))) {
+               return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
+       }
+       return 0;
+}
+
+int
+gnutls_rwlock_unlock(gnutls_rwlock_t rwlock)
+{
+       if (unlikely(glthread_rwlock_unlock(rwlock))) {
+               return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
+       }
+       return 0;
+}
index 99bf083fd168ad2a32e51ebf464b8ba5eda17913..b48d2e702b2ff83ededd5169f49bbb49a33962bf 100644 (file)
@@ -43,9 +43,15 @@ typedef gl_lock_t *gnutls_static_mutex_t;
 int gnutls_static_mutex_lock(gnutls_static_mutex_t lock);
 int gnutls_static_mutex_unlock(gnutls_static_mutex_t lock);
 
-#define GNUTLS_STATIC_RWLOCK(rwlock) gl_rwlock_define_initialized(static, rwlock)
-#define GNUTLS_STATIC_RWLOCK_RDLOCK gl_rwlock_rdlock
-#define GNUTLS_STATIC_RWLOCK_WRLOCK gl_rwlock_wrlock
-#define GNUTLS_STATIC_RWLOCK_UNLOCK gl_rwlock_unlock
+/* Unlike static mutexes, static rwlocks can be locked/unlocked with
+ * the functions defined below, because there is no way to replace
+ * those functions.
+ */
+#define GNUTLS_RWLOCK(rwlock) gl_rwlock_define_initialized(static, rwlock)
+typedef gl_rwlock_t *gnutls_rwlock_t;
+
+int gnutls_rwlock_rdlock(gnutls_rwlock_t rwlock);
+int gnutls_rwlock_wrlock(gnutls_rwlock_t rwlock);
+int gnutls_rwlock_unlock(gnutls_rwlock_t rwlock);
 
 #endif /* GNUTLS_LIB_LOCKS_H */
index e45c6aa11d8be1b8b18465cf1390ba132330798d..2851d514743e623aefeb270d69f67f70393f890a 100644 (file)
@@ -1012,7 +1012,7 @@ struct cfg {
 };
 
 /* Lock for reading and writing system_wide_config */
-GNUTLS_STATIC_RWLOCK(system_wide_config_rwlock);
+GNUTLS_RWLOCK(system_wide_config_rwlock);
 static struct cfg system_wide_config;
 
 static unsigned fail_on_invalid_config = 0;
@@ -1308,13 +1308,17 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co
        return 1;
 }
 
-static void _gnutls_update_system_priorities(void)
+static int _gnutls_update_system_priorities(void)
 {
-       int ret = 0;
+       int ret, err = 0;
        struct stat sb;
        FILE *fp;
 
-       GNUTLS_STATIC_RWLOCK_RDLOCK(system_wide_config_rwlock);
+       ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);
+       if (ret < 0) {
+               return gnutls_assert_val(ret);
+       }
+
        if (stat(system_priority_file, &sb) < 0) {
                _gnutls_debug_log("cfg: unable to access: %s: %d\n",
                                  system_priority_file, errno);
@@ -1328,9 +1332,12 @@ static void _gnutls_update_system_priorities(void)
                goto out;
        }
 
-       GNUTLS_STATIC_RWLOCK_UNLOCK(system_wide_config_rwlock);
+       (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);
 
-       GNUTLS_STATIC_RWLOCK_WRLOCK(system_wide_config_rwlock);
+       ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);
+       if (ret < 0) {
+               return gnutls_assert_val(ret);
+       }
 
        /* Another thread has successfully updated the system wide config (with
         * the same modification time as checked above), while upgrading to
@@ -1350,11 +1357,11 @@ static void _gnutls_update_system_priorities(void)
                                  system_priority_file, errno);
                goto out;
        }
-       ret = ini_parse_file(fp, cfg_ini_handler, NULL);
+       err = ini_parse_file(fp, cfg_ini_handler, NULL);
        fclose(fp);
-       if (ret != 0) {
+       if (err) {
                _gnutls_debug_log("cfg: unable to parse: %s: %d\n",
-                                 system_priority_file, ret);
+                                 system_priority_file, err);
                goto out;
        }
 
@@ -1366,16 +1373,19 @@ static void _gnutls_update_system_priorities(void)
        system_priority_last_mod = sb.st_mtime;
 
  out:
-       GNUTLS_STATIC_RWLOCK_UNLOCK(system_wide_config_rwlock);
+       (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);
 
-       if (ret != 0 && fail_on_invalid_config) {
+       if (err && fail_on_invalid_config) {
                exit(1);
        }
+
+       return ret;
 }
 
 void _gnutls_load_system_priorities(void)
 {
        const char *p;
+       int ret;
 
        p = secure_getenv("GNUTLS_SYSTEM_PRIORITY_FILE");
        if (p != NULL)
@@ -1385,7 +1395,11 @@ void _gnutls_load_system_priorities(void)
        if (p != NULL && p[0] == '1' && p[1] == 0)
                fail_on_invalid_config = 1;
 
-       _gnutls_update_system_priorities();
+       ret = _gnutls_update_system_priorities();
+       if (ret < 0) {
+               _gnutls_debug_log("failed to update system priorities: %s\n",
+                                 gnutls_strerror(ret));
+       }
 }
 
 void _gnutls_unload_system_priorities(void)
@@ -1423,88 +1437,101 @@ char *_gnutls_resolve_priorities(const char* priorities)
 {
        const char *p = priorities;
        char *additional = NULL;
-       char *ret = NULL;
+       char *resolved = NULL;
        const char *ss, *ss_next;
        unsigned ss_len, ss_next_len;
        size_t n, n2 = 0;
+       int ret;
 
-       while (c_isspace(*p))
+       while (c_isspace(*p)) {
                p++;
+       }
 
-       if (*p == '@') {
-               ss = p+1;
-               additional = strchr(ss, ':');
-               if (additional != NULL) {
-                       additional++;
-               }
+       /* Cannot reduce further. */
+       if (*p != '@') {
+               return gnutls_strdup(p);
+       }
 
-               /* Always try to refresh the cached data, to
-                * allow it to be updated without restarting
-                * all applications
-                */
-               _gnutls_update_system_priorities();
-
-               do {
-                       ss_next = strchr(ss, ',');
-                       if (ss_next != NULL) {
-                               if (additional && ss_next > additional)
-                                       ss_next = NULL;
-                               else
-                                       ss_next++;
-                       }
+       ss = p+1;
+       additional = strchr(ss, ':');
+       if (additional) {
+               additional++;
+       }
+
+       /* Always try to refresh the cached data, to allow it to be
+        * updated without restarting all applications.
+        */
+       ret = _gnutls_update_system_priorities();
+       if (ret < 0) {
+               _gnutls_debug_log("failed to update system priorities: %s\n",
+                                 gnutls_strerror(ret));
+       }
 
-                       if (ss_next) {
-                               ss_len = ss_next - ss - 1;
-                               ss_next_len = additional - ss_next - 1;
-                       } else if (additional) {
-                               ss_len = additional - ss - 1;
-                               ss_next_len = 0;
+       do {
+               ss_next = strchr(ss, ',');
+               if (ss_next) {
+                       if (additional && ss_next > additional) {
+                               ss_next = NULL;
                        } else {
-                               ss_len = strlen(ss);
-                               ss_next_len = 0;
+                               ss_next++;
                        }
+               }
+
+               if (ss_next) {
+                       ss_len = ss_next - ss - 1;
+                       ss_next_len = additional - ss_next - 1;
+               } else if (additional) {
+                       ss_len = additional - ss - 1;
+                       ss_next_len = 0;
+               } else {
+                       ss_len = strlen(ss);
+                       ss_next_len = 0;
+               }
 
-                       GNUTLS_STATIC_RWLOCK_RDLOCK(system_wide_config_rwlock);
-                       p = _name_val_array_value(system_wide_config.priority_strings, ss, ss_len);
+               ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);
+               if (ret < 0) {
+                       _gnutls_debug_log("cannot read system priority strings: %s\n",
+                                         gnutls_strerror(ret));
+                       break;
+               }
 
-                       _gnutls_debug_log("resolved '%.*s' to '%s', next '%.*s'\n",
-                                         ss_len, ss, S(p), ss_next_len, S(ss_next));
+               p = _name_val_array_value(system_wide_config.priority_strings,
+                                         ss, ss_len);
 
-                       if (p) {
-                               n = strlen(p);
-                               if (additional) {
-                                       n2 = strlen(additional);
-                               }
+               _gnutls_debug_log("resolved '%.*s' to '%s', next '%.*s'\n",
+                                 ss_len, ss, S(p), ss_next_len, S(ss_next));
 
-                               ret = gnutls_malloc(n+n2+1+1);
-                               if (ret) {
-                                       memcpy(ret, p, n);
-                                       if (additional != NULL) {
-                                               ret[n] = ':';
-                                               memcpy(&ret[n+1], additional, n2);
-                                               ret[n+n2+1] = 0;
-                                       } else {
-                                               ret[n] = 0;
-                                       }
+               if (p) {
+                       n = strlen(p);
+                       if (additional) {
+                               n2 = strlen(additional);
+                       }
+
+                       resolved = gnutls_malloc(n+n2+1+1);
+                       if (resolved) {
+                               memcpy(resolved, p, n);
+                               if (additional) {
+                                       resolved[n] = ':';
+                                       memcpy(&resolved[n+1], additional, n2);
+                                       resolved[n+n2+1] = 0;
+                               } else {
+                                       resolved[n] = 0;
                                }
                        }
-                       GNUTLS_STATIC_RWLOCK_UNLOCK(system_wide_config_rwlock);
+               }
 
-                       ss = ss_next;
-               } while (ss && ret == NULL);
+               (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);
 
-               if (ret == NULL) {
-                       _gnutls_debug_log("unable to resolve %s\n", priorities);
-               }
-       } else {
-               return gnutls_strdup(p);
-       }
+               ss = ss_next;
+       } while (ss && !resolved);
 
-       if (ret != NULL) {
-               _gnutls_debug_log("selected priority string: %s\n", ret);
+       if (resolved) {
+               _gnutls_debug_log("selected priority string: %s\n", resolved);
+       } else {
+               _gnutls_debug_log("unable to resolve %s\n", priorities);
        }
 
-       return ret;
+       return resolved;
 }
 
 static void add_ec(gnutls_priority_t priority_cache)
@@ -1572,7 +1599,10 @@ static int set_ciphersuite_list(gnutls_priority_t priority_cache)
 
        /* The following requires a lock so there are no inconsistencies in the
         * members of system_wide_config loaded from the config file. */
-       GNUTLS_STATIC_RWLOCK_RDLOCK(system_wide_config_rwlock);
+       ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);
+       if (ret < 0) {
+               return gnutls_assert_val(ret);
+       }
 
        /* disable key exchanges which are globally disabled */
        z = 0;
@@ -1853,7 +1883,7 @@ static int set_ciphersuite_list(gnutls_priority_t priority_cache)
        }
 
  out:
-       GNUTLS_STATIC_RWLOCK_UNLOCK(system_wide_config_rwlock);
+       gnutls_rwlock_unlock(&system_wide_config_rwlock);
        return ret;
 }