summaryrefslogtreecommitdiffstats
path: root/src/util/support
diff options
context:
space:
mode:
authorAlexandra Ellwood <lxs@mit.edu>2008-03-21 19:04:40 +0000
committerAlexandra Ellwood <lxs@mit.edu>2008-03-21 19:04:40 +0000
commitcb44e7b91175854d3ca668ec043a48f02b2c37e8 (patch)
tree5828743390bb17471f753cad02a87fedacd34e0c /src/util/support
parent858c809105b5d66f1b2c8b2d3c305216a594e19c (diff)
downloadkrb5-cb44e7b91175854d3ca668ec043a48f02b2c37e8.tar.gz
krb5-cb44e7b91175854d3ca668ec043a48f02b2c37e8.tar.xz
krb5-cb44e7b91175854d3ca668ec043a48f02b2c37e8.zip
Protect CFBundle calls with mutexes
CFBundles are refcounted and the recounts are not threadsafe. Protect CFBundles used for loading bundled plugins with a mutex to prevent crashes when multiple threads are loading and unloading the same plugin. As part of this we use thread-safe dlopen/dlsym/dlclose for the actual loading and unloading and just use CFBundle to get the path to the actual executable. This reduces the number of places we need to wrap CFBundles with mutexes and the amount of Mac-specific code in the plugin code. ticket: new git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20285 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/util/support')
-rw-r--r--src/util/support/plugins.c165
1 files changed, 84 insertions, 81 deletions
diff --git a/src/util/support/plugins.c b/src/util/support/plugins.c
index 99d3aea57..77b3745f7 100644
--- a/src/util/support/plugins.c
+++ b/src/util/support/plugins.c
@@ -31,9 +31,6 @@
#if USE_DLOPEN
#include <dlfcn.h>
#endif
-#if USE_CFBUNDLE
-#include <CoreFoundation/CoreFoundation.h>
-#endif
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
@@ -51,6 +48,16 @@
#include "k5-platform.h"
+#if USE_DLOPEN && USE_CFBUNDLE
+#include <CoreFoundation/CoreFoundation.h>
+
+/* Currently CoreFoundation only exists on the Mac so we just use
+ * pthreads directly to avoid creating empty function calls on other
+ * platforms. If a thread initializer ever gets created in the common
+ * plugin code, move this there */
+static pthread_mutex_t krb5int_bundle_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
#include <stdarg.h>
static void Tprintf (const char *fmt, ...)
{
@@ -66,10 +73,7 @@ struct plugin_file_handle {
#if USE_DLOPEN
void *dlhandle;
#endif
-#if USE_CFBUNDLE
- CFBundleRef bundle;
-#endif
-#if !defined (USE_DLOPEN) && !defined (USE_CFBUNDLE)
+#if !defined (USE_DLOPEN)
char dummy;
#endif
};
@@ -95,14 +99,83 @@ krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct
}
#if USE_DLOPEN
- if (!err && (statbuf.st_mode & S_IFMT) == S_IFREG) {
+ if (!err && ((statbuf.st_mode & S_IFMT) == S_IFREG
+#if USE_CFBUNDLE
+ || (statbuf.st_mode & S_IFMT) == S_IFDIR
+#endif /* USE_CFBUNDLE */
+ )) {
void *handle = NULL;
+
+#if USE_CFBUNDLE
+ char executablepath[MAXPATHLEN];
+
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+ int lock_err = 0;
+ CFStringRef pluginString = NULL;
+ CFURLRef pluginURL = NULL;
+ CFBundleRef pluginBundle = NULL;
+ CFURLRef executableURL = NULL;
+
+ /* Lock around CoreFoundation calls since objects are refcounted
+ * and the refcounts are not thread-safe. Using pthreads directly
+ * because this code is Mac-specific */
+ lock_err = pthread_mutex_lock(&krb5int_bundle_mutex);
+ if (lock_err) { err = lock_err; }
+
+ if (!err) {
+ pluginString = CFStringCreateWithCString (kCFAllocatorDefault,
+ filepath,
+ kCFStringEncodingASCII);
+ if (pluginString == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault,
+ pluginString,
+ kCFURLPOSIXPathStyle,
+ true);
+ if (pluginURL == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
+ if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
+ }
+
+ if (!err) {
+ executableURL = CFBundleCopyExecutableURL (pluginBundle);
+ if (executableURL == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ if (!CFURLGetFileSystemRepresentation (executableURL,
+ true, /* absolute */
+ (UInt8 *)executablepath,
+ sizeof (executablepath))) {
+ err = ENOMEM;
+ }
+ }
+
+ if (!err) {
+ /* override the path the caller passed in */
+ filepath = executablepath;
+ }
+
+ if (executableURL != NULL) { CFRelease (executableURL); }
+ if (pluginBundle != NULL) { CFRelease (pluginBundle); }
+ if (pluginURL != NULL) { CFRelease (pluginURL); }
+ if (pluginString != NULL) { CFRelease (pluginString); }
+
+ /* unlock after CFRelease calls since they modify refcounts */
+ if (!lock_err) { pthread_mutex_unlock (&krb5int_bundle_mutex); }
+ }
+#endif /* USE_CFBUNDLE */
+
#ifdef RTLD_GROUP
#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | RTLD_GROUP)
#else
#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL)
#endif
-
if (!err) {
handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS);
if (handle == NULL) {
@@ -121,49 +194,7 @@ krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct
if (handle != NULL) { dlclose (handle); }
}
-#endif
-
-#if USE_CFBUNDLE
- if (!err && (statbuf.st_mode & S_IFMT) == S_IFDIR) {
- CFStringRef pluginPath = NULL;
- CFURLRef pluginURL = NULL;
- CFBundleRef pluginBundle = NULL;
-
- if (!err) {
- pluginPath = CFStringCreateWithCString (kCFAllocatorDefault, filepath,
- kCFStringEncodingASCII);
- if (pluginPath == NULL) { err = ENOMEM; }
- }
-
- if (!err) {
- pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pluginPath,
- kCFURLPOSIXPathStyle, true);
- if (pluginURL == NULL) { err = ENOMEM; }
- }
-
- if (!err) {
- pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
- if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
- }
-
- if (!err) {
- if (!CFBundleIsExecutableLoaded (pluginBundle)) {
- int loaded = CFBundleLoadExecutable (pluginBundle);
- if (!loaded) { err = ENOENT; } /* XXX need better error */
- }
- }
-
- if (!err) {
- got_plugin = 1;
- htmp->bundle = pluginBundle;
- pluginBundle = NULL; /* htmp->bundle takes ownership */
- }
-
- if (pluginBundle != NULL) { CFRelease (pluginBundle); }
- if (pluginURL != NULL) { CFRelease (pluginURL); }
- if (pluginPath != NULL) { CFRelease (pluginPath); }
- }
-#endif
+#endif /* USE_DLOPEN */
if (!err && !got_plugin) {
err = ENOENT; /* no plugin or no way to load plugins */
@@ -201,29 +232,6 @@ krb5int_get_plugin_sym (struct plugin_file_handle *h,
}
#endif
-#if USE_CFBUNDLE
- if (!err && !sym && (h->bundle != NULL)) {
- CFStringRef cfsymname = NULL;
-
- if (!err) {
- cfsymname = CFStringCreateWithCString (kCFAllocatorDefault, csymname,
- kCFStringEncodingASCII);
- if (cfsymname == NULL) { err = ENOMEM; }
- }
-
- if (!err) {
- if (isfunc) {
- sym = CFBundleGetFunctionPointerForName (h->bundle, cfsymname);
- } else {
- sym = CFBundleGetDataPointerForName (h->bundle, cfsymname);
- }
- if (sym == NULL) { err = ENOENT; } /* XXX */
- }
-
- if (cfsymname != NULL) { CFRelease (cfsymname); }
- }
-#endif
-
if (!err && (sym == NULL)) {
err = ENOENT; /* unimplemented */
}
@@ -261,11 +269,6 @@ krb5int_close_plugin (struct plugin_file_handle *h)
#if USE_DLOPEN
if (h->dlhandle != NULL) { dlclose(h->dlhandle); }
#endif
-#if USE_CFBUNDLE
- /* Do not call CFBundleUnloadExecutable because it's not ref counted.
- * CFRelease will unload the bundle if the internal refcount goes to zero. */
- if (h->bundle != NULL) { CFRelease (h->bundle); }
-#endif
free (h);
}
@@ -339,7 +342,7 @@ krb5int_plugin_file_handle_array_free (struct plugin_file_handle **harray)
}
#if TARGET_OS_MAC
-#define FILEEXTS { "", ".bundle", ".so", NULL }
+#define FILEEXTS { "", ".bundle", ".dylib", ".so", NULL }
#elif defined(_WIN32)
#define FILEEXTS { "", ".dll", NULL }
#else