|
|
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 |
{
|