From 20e003a63d14edabd59e40e5d0b8ed2f11f8c9b8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 18 Jun 2020 08:41:02 +0200 Subject: [PATCH] dlsym: fix the race when snd_libdir_origin is freed snd_dlobj_cache_cleanup() function frees snd_libdir_origin, but the pointer may be used again in snd_dlpath(). BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1847508 Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index ca94b123..1a60e0dd 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -34,14 +34,21 @@ #endif #include +#if defined(HAVE_LIBDL) && defined(__GLIBC__) && !defined(__UCLIBC__) +#define DL_ORIGIN_AVAILABLE 1 +#endif + #ifndef DOC_HIDDEN #ifndef PIC struct snd_dlsym_link *snd_dlsym_start = NULL; #endif +#ifdef DL_ORIGIN_AVAILABLE +static int snd_libdir_plugin_dir_set = 0; static char *snd_libdir_origin = NULL; #endif +#endif -#ifdef HAVE_LIBPTHREAD +#if defined(DL_ORIGIN_AVAILABLE) && defined(HAVE_LIBPTHREAD) static pthread_mutex_t snd_dlpath_mutex = PTHREAD_MUTEX_INITIALIZER; static inline void snd_dlpath_lock(void) @@ -68,11 +75,9 @@ static inline void snd_dlpath_unlock(void) {} */ int snd_dlpath(char *path, size_t path_len, const char *name) { -#ifdef HAVE_LIBDL -#if defined(__GLIBC__) && !defined(__UCLIBC__) - static int plugin_dir_set = 0; +#ifdef DL_ORIGIN_AVAILABLE snd_dlpath_lock(); - if (!plugin_dir_set) { + if (!snd_libdir_plugin_dir_set) { struct link_map *links; Dl_info info; char origin[PATH_MAX]; @@ -83,15 +88,17 @@ int snd_dlpath(char *path, size_t path_len, const char *name) if (access(path, X_OK) == 0) snd_libdir_origin = strdup(origin); } - plugin_dir_set = 1; + snd_libdir_plugin_dir_set = 1; } - snd_dlpath_unlock(); -#endif -#endif - if (snd_libdir_origin) + if (snd_libdir_origin) { snprintf(path, path_len, "%s/alsa-lib/%s", snd_libdir_origin, name); - else + } else { snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name); + } + snd_dlpath_unlock(); +#else + snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name); +#endif return 0; } @@ -440,7 +447,13 @@ void snd_dlobj_cache_cleanup(void) free((void *)c->lib); /* shut up gcc warning */ free(c); } - free(snd_libdir_origin); snd_dlobj_unlock(); +#ifdef DL_ORIGIN_AVAILABLE + snd_dlpath_lock(); + snd_libdir_plugin_dir_set = 0; + free(snd_libdir_origin); + snd_libdir_origin = NULL; + snd_dlpath_unlock(); +#endif } #endif -- 2.47.1