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

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