diff options
author | Daiki Ueno <ueno@gnu.org> | 2021-10-28 18:55:26 +0200 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2021-10-30 06:59:00 +0200 |
commit | 890c6937a3cfb4a0704bc815324221ec4cb89840 (patch) | |
tree | fd7d6cc83578d7eb4d853cb2f04558553f79e2d0 | |
parent | 05580592785a73208fb33526d72d5bfd6aa292c5 (diff) | |
download | gnutls-890c6937a3cfb4a0704bc815324221ec4cb89840.tar.gz |
priority: fix potential race in reloading system-wide config
_gnutls_update_system_priorities is called from gnutls_priority_set*
functions every time when the SYSTEM keyword is used and updates a
global variable system_wide_priority_strings if the configuration
changes. Although the critical path is protected with mtime check, it
should also hold a lock to avoid occasional race condition in
multi-thread programs. This also clears
system_wide_priority_strings_init upon unloading and before reloading
the config file (thanks to Alexander Sosedkin).
Signed-off-by: Daiki Ueno <ueno@gnu.org>
-rw-r--r-- | lib/priority.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/lib/priority.c b/lib/priority.c index 55d68d734c..cdda72d2ca 100644 --- a/lib/priority.c +++ b/lib/priority.c @@ -39,6 +39,7 @@ #include "profiles.h" #include "c-strcase.h" #include "inih/ini.h" +#include "locks.h" #include "profiles.h" #include "name_val_array.h" @@ -1000,6 +1001,8 @@ static void dummy_func(gnutls_priority_t c) #include <priority_options.h> static gnutls_certificate_verification_profiles_t system_wide_verification_profile = GNUTLS_PROFILE_UNKNOWN; +/* Lock for updating system_wide_priority_strings{,_init} */ +GNUTLS_STATIC_MUTEX(system_wide_priority_strings_mutex); static name_val_array_t system_wide_priority_strings = NULL; static unsigned system_wide_priority_strings_init = 0; static unsigned system_wide_default_priority_string = 0; @@ -1311,27 +1314,29 @@ static void _gnutls_update_system_priorities(void) struct stat sb; FILE *fp; + GNUTLS_STATIC_MUTEX_LOCK(system_wide_priority_strings_mutex); + if (stat(system_priority_file, &sb) < 0) { _gnutls_debug_log("cfg: unable to access: %s: %d\n", system_priority_file, errno); - return; + goto out; } if (system_wide_priority_strings_init != 0 && sb.st_mtime == system_priority_last_mod) { _gnutls_debug_log("cfg: system priority %s has not changed\n", system_priority_file); - return; + goto out; } - if (system_wide_priority_strings_init != 0) - _name_val_array_clear(&system_wide_priority_strings); + _name_val_array_clear(&system_wide_priority_strings); + system_wide_priority_strings_init = 0; fp = fopen(system_priority_file, "re"); if (fp == NULL) { _gnutls_debug_log("cfg: unable to open: %s: %d\n", system_priority_file, errno); - return; + goto out; } ret = ini_parse_file(fp, cfg_ini_handler, NULL); fclose(fp); @@ -1340,7 +1345,7 @@ static void _gnutls_update_system_priorities(void) system_priority_file, ret); if (fail_on_invalid_config) exit(1); - return; + goto out; } _gnutls_debug_log("cfg: loaded system priority %s mtime %lld\n", @@ -1348,6 +1353,9 @@ static void _gnutls_update_system_priorities(void) (unsigned long long)sb.st_mtime); system_priority_last_mod = sb.st_mtime; + + out: + GNUTLS_STATIC_MUTEX_UNLOCK(system_wide_priority_strings_mutex); } void _gnutls_load_system_priorities(void) @@ -1368,6 +1376,7 @@ void _gnutls_load_system_priorities(void) void _gnutls_unload_system_priorities(void) { _name_val_array_clear(&system_wide_priority_strings); + system_wide_priority_strings_init = 0; _clear_default_system_priority(); system_priority_last_mod = 0; } |