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

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