Blame SOURCES/autofs-5.0.7-fix-crash-due-to-thread-unsafe-use-of-libldap.patch

4d476f
autofs-5.0.7 - fix crash due to thread unsafe use of libldap
4d476f
4d476f
From: Leonardo Chiquitto <leonardo.lists@gmail.com>
4d476f
4d476f
Add locking around LDAP initialization calls
4d476f
4d476f
To prevent corruption inside SSL and LDAP libraries, it's necessary to
4d476f
serialize all calls to functions that initialize LDAP contexts.
4d476f
4d476f
How to reproduce the problem:
4d476f
4d476f
- Setup an LDAP server with SSL/TLS support enabled
4d476f
- Configure AutoFS to fetch the maps from LDAP
4d476f
- Make sure the OpenLDAP client library is configured to use SSL
4d476f
  connections and "usetls" is set to yes in autofs_ldap_auth.conf.
4d476f
4d476f
In one directory handled by AutoFS (an indirect mount point), trigger in
4d476f
parallel some dozens of invalid mounts (ie, try to access keys that do not
4d476f
exist in the AutoFS map). Repeat until it crashes.
4d476f
4d476f
Here it always crashes in less than 20 minutes, normally inside OpenSSL.
4d476f
Core dump inspection shows that internal SSL structures are corrupted,
4d476f
with function pointers pointing to random addresses.
4d476f
4d476f
Trying to find similar reports on the web, I found this email from an
4d476f
OpenLDAP developer (partial quote, emphasis mine) [1]:
4d476f
4d476f
"As far as I know, libldap is thread safe in the sense that multiple
4d476f
threads can use separate LDAP* handles without running into concurrency
4d476f
issues; *except for library initialization*, all accesses to common data
4d476f
(i.e. global variables) is read-only."
4d476f
4d476f
[1]http://www.openldap.org/cgi-bin/wilma_hiliter/openldap-software/200606/msg00252.html
4d476f
4d476f
AutoFS implements no locking around LDAP initialization libraries and
4d476f
it's quite common to see multiple threads executing ldap_initialize()
4d476f
or ldap_start_tls_s() at the same time.
4d476f
---
4d476f
 CHANGELOG             |    1 +
4d476f
 modules/lookup_ldap.c |   35 ++++++++++++++++++++++++++++++++++-
4d476f
 2 files changed, 35 insertions(+), 1 deletion(-)
4d476f
4d476f
--- autofs-5.0.7.orig/CHANGELOG
4d476f
+++ autofs-5.0.7/CHANGELOG
4d476f
@@ -105,6 +105,7 @@
4d476f
 - fix incorrect append options description in README.v5-release.
4d476f
 - fix mistake in assignment.
4d476f
 - use open(2) instead of access(2) to trigger dependent mounts.
4d476f
+- fix crash due to thread unsafe use of libldap.
4d476f
 
4d476f
 25/07/2012 autofs-5.0.7
4d476f
 =======================
4d476f
--- autofs-5.0.7.orig/modules/lookup_ldap.c
4d476f
+++ autofs-5.0.7/modules/lookup_ldap.c
4d476f
@@ -52,6 +52,12 @@ static struct ldap_schema common_schema[
4d476f
 };
4d476f
 static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
4d476f
 
4d476f
+/*
4d476f
+ * Initialization of LDAP and OpenSSL must be always serialized to
4d476f
+ * avoid corruption of context structures inside these libraries.
4d476f
+ */
4d476f
+pthread_mutex_t ldapinit_mutex = PTHREAD_MUTEX_INITIALIZER;
4d476f
+
4d476f
 struct ldap_search_params {
4d476f
 	struct autofs_point *ap;
4d476f
 	LDAP *ldap;
4d476f
@@ -138,6 +144,22 @@ int ldap_parse_page_control(LDAP *ldap,
4d476f
 }
4d476f
 #endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */
4d476f
 
4d476f
+static void ldapinit_mutex_lock(void)
4d476f
+{
4d476f
+	int status = pthread_mutex_lock(&ldapinit_mutex);
4d476f
+	if (status)
4d476f
+		fatal(status);
4d476f
+	return;
4d476f
+}
4d476f
+
4d476f
+static void ldapinit_mutex_unlock(void)
4d476f
+{
4d476f
+	int status = pthread_mutex_unlock(&ldapinit_mutex);
4d476f
+	if (status)
4d476f
+		fatal(status);
4d476f
+	return;
4d476f
+}
4d476f
+
4d476f
 static void uris_mutex_lock(struct lookup_context *ctxt)
4d476f
 {
4d476f
 	int status = pthread_mutex_lock(&ctxt->uris_mutex);
4d476f
@@ -198,7 +220,7 @@ int unbind_ldap_connection(unsigned logo
4d476f
 	return rv;
4d476f
 }
4d476f
 
4d476f
-LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
4d476f
+LDAP *__init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
4d476f
 {
4d476f
 	LDAP *ldap = NULL;
4d476f
 	struct timeval timeout     = { ctxt->timeout, 0 };
4d476f
@@ -276,6 +298,17 @@ LDAP *init_ldap_connection(unsigned logo
4d476f
 
4d476f
 	return ldap;
4d476f
 }
4d476f
+
4d476f
+LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
4d476f
+{
4d476f
+	LDAP *ldap;
4d476f
+
4d476f
+	ldapinit_mutex_lock();
4d476f
+	ldap = __init_ldap_connection(logopt, uri, ctxt);
4d476f
+	ldapinit_mutex_unlock();
4d476f
+
4d476f
+	return ldap;
4d476f
+}
4d476f
 
4d476f
 static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
4d476f
 {