diff --git a/openldap-nss-init-threadsafe.patch b/openldap-nss-init-threadsafe.patch new file mode 100644 index 0000000..6ef0976 --- /dev/null +++ b/openldap-nss-init-threadsafe.patch @@ -0,0 +1,217 @@ +NSS_Init* functions are not thread safe + +The NSS_InitContext et. al, and their corresponding shutdown functions, +are not thread safe. There can only be one thread at a time calling +these functions. Protect the calls with a mutex. Create the mutex +using a PR_CallOnce to ensure that the mutex is only created once and +not used before created. Move the registration of the nss shutdown +callback to also use a PR_CallOnce. Removed the call to +SSL_ClearSessionCache() because it is always called at shutdown, and we must +not call it more than once. + +Resolves: #731112 +Author: Rich Megginson +Upstream ITS: #7022 +--- + libraries/libldap/tls_m.c | 98 +++++++++++++++++++++++++++++++++++++++++--- + 1 files changed, 91 insertions(+), 7 deletions(-) + +diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c +index 997b3eb..30c8a76 100644 +--- a/libraries/libldap/tls_m.c ++++ b/libraries/libldap/tls_m.c +@@ -130,9 +130,29 @@ static int tlsm_init( void ); + + #ifdef LDAP_R_COMPILE + ++/* it doesn't seem guaranteed that a client will call ++ tlsm_thr_init in a non-threaded context - so we have ++ to wrap the mutex creation in a prcallonce ++*/ ++static ldap_pvt_thread_mutex_t tlsm_init_mutex; ++static PRCallOnceType tlsm_init_mutex_callonce = {0,0}; ++ ++static PRStatus PR_CALLBACK ++tlsm_thr_init_callonce( void ) ++{ ++ if ( ldap_pvt_thread_mutex_init( &tlsm_init_mutex ) ) { ++ Debug( LDAP_DEBUG_ANY, ++ "TLS: could not create mutex for moznss initialization: %d\n", errno, 0, 0 ); ++ return PR_FAILURE; ++ } ++ ++ return PR_SUCCESS; ++} ++ + static void + tlsm_thr_init( void ) + { ++ ( void )PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce ); + } + + #endif /* LDAP_R_COMPILE */ +@@ -1079,7 +1099,6 @@ tlsm_nss_shutdown_cb( void *appData, void *nssData ) + SECStatus rc = SECSuccess; + + SSL_ShutdownServerSessionIDCache(); +- SSL_ClearSessionCache(); + + if ( pem_module ) { + SECMOD_UnloadUserModule( pem_module ); +@@ -1089,6 +1108,24 @@ tlsm_nss_shutdown_cb( void *appData, void *nssData ) + return rc; + } + ++static PRCallOnceType tlsm_register_shutdown_callonce = {0,0}; ++static PRStatus PR_CALLBACK ++tlsm_register_nss_shutdown_cb( void ) ++{ ++ if ( SECSuccess == NSS_RegisterShutdown( tlsm_nss_shutdown_cb, ++ NULL ) ) { ++ return PR_SUCCESS; ++ } ++ return PR_FAILURE; ++} ++ ++static PRStatus ++tlsm_register_nss_shutdown( void ) ++{ ++ return PR_CallOnce( &tlsm_register_shutdown_callonce, ++ tlsm_register_nss_shutdown_cb ); ++} ++ + static int + tlsm_init_pem_module( void ) + { +@@ -1529,6 +1566,12 @@ tlsm_deferred_init( void *arg ) + initParams.length = sizeof( initParams ); + #endif /* HAVE_NSS_INITCONTEXT */ + ++#ifdef LDAP_R_COMPILE ++ if ( PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce ) ) { ++ return -1; ++ } ++#endif /* LDAP_R_COMPILE */ ++ + #ifndef HAVE_NSS_INITCONTEXT + if ( !NSS_IsInitialized() ) { + #endif /* HAVE_NSS_INITCONTEXT */ +@@ -1556,6 +1599,10 @@ tlsm_deferred_init( void *arg ) + } + + tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix ); ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_LOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ ++ + #ifdef HAVE_NSS_INITCONTEXT + #ifdef INITCONTEXT_HACK + if ( !NSS_IsInitialized() && ctx->tc_is_server ) { +@@ -1574,6 +1621,10 @@ tlsm_deferred_init( void *arg ) + rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY ); + #endif + ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_UNLOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ ++ + if ( rc != SECSuccess ) { + errcode = PORT_GetError(); + if ( securitydirs[ii] != lt->lt_cacertdir) { +@@ -1597,6 +1648,9 @@ tlsm_deferred_init( void *arg ) + } + + if ( errcode ) { /* no moznss db found, or not using moznss db */ ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_LOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ + #ifdef HAVE_NSS_INITCONTEXT + int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB; + #ifdef INITCONTEXT_HACK +@@ -1615,6 +1669,9 @@ tlsm_deferred_init( void *arg ) + #else + rc = NSS_NoDB_Init( NULL ); + #endif ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_UNLOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ + if ( rc != SECSuccess ) { + errcode = PORT_GetError(); + Debug( LDAP_DEBUG_ANY, +@@ -1628,13 +1685,22 @@ tlsm_deferred_init( void *arg ) + #endif + + /* initialize the PEM module */ ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_LOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ + if ( tlsm_init_pem_module() ) { ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_UNLOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ + errcode = PORT_GetError(); + Debug( LDAP_DEBUG_ANY, + "TLS: could not initialize moznss PEM module - error %d:%s.\n", + errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ); + return -1; + } ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_UNLOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ + + if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) { + /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode +@@ -1669,10 +1735,13 @@ tlsm_deferred_init( void *arg ) + PK11_SetPasswordFunc( tlsm_pin_prompt ); + + /* register cleanup function */ +- /* delete the old one, if any */ +- NSS_UnregisterShutdown( tlsm_nss_shutdown_cb, NULL ); +- NSS_RegisterShutdown( tlsm_nss_shutdown_cb, NULL ); +- ++ if ( tlsm_register_nss_shutdown() ) { ++ errcode = PORT_GetError(); ++ Debug( LDAP_DEBUG_ANY, ++ "TLS: could not register NSS shutdown function: %d:%s\n", ++ errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ); ++ return -1; ++ } + #ifndef HAVE_NSS_INITCONTEXT + } + #endif /* HAVE_NSS_INITCONTEXT */ +@@ -1884,6 +1953,9 @@ tlsm_clientauth_init( tlsm_ctx *ctx ) + static void + tlsm_destroy( void ) + { ++#ifdef LDAP_R_COMPILE ++ ldap_pvt_thread_mutex_destroy( &tlsm_init_mutex ); ++#endif + } + + static tls_ctx * +@@ -1949,8 +2021,20 @@ tlsm_ctx_free ( tls_ctx *ctx ) + PL_strfree( c->tc_slotname ); + tlsm_free_pem_objs( c ); + #ifdef HAVE_NSS_INITCONTEXT +- if (c->tc_initctx) +- NSS_ShutdownContext( c->tc_initctx ); ++ if ( c->tc_initctx ) { ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_LOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ ++ if ( NSS_ShutdownContext( c->tc_initctx ) ) { ++ PRErrorCode errcode = PR_GetError(); ++ Debug( LDAP_DEBUG_ANY, ++ "TLS: could not shutdown NSS - error %d:%s.\n", ++ errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ); ++ } ++#ifdef LDAP_R_COMPILE ++ LDAP_MUTEX_UNLOCK( &tlsm_init_mutex ); ++#endif /* LDAP_R_COMPILE */ ++ } + c->tc_initctx = NULL; + #endif /* HAVE_NSS_INITCONTEXT */ + #ifdef LDAP_R_COMPILE +-- +1.7.1 + diff --git a/openldap.spec b/openldap.spec index 27ef48f..2228687 100644 --- a/openldap.spec +++ b/openldap.spec @@ -30,6 +30,7 @@ Patch4: openldap-smbk5pwd-overlay.patch Patch5: openldap-ldaprc-currentdir.patch Patch6: openldap-userconfig-setgid.patch Patch7: openldap-nss-free-peer-cert.patch +Patch8: openldap-nss-init-threadsafe.patch # patches for the evolution library (see README.evolution) Patch200: openldap-evolution-ntlm.patch @@ -130,6 +131,7 @@ pushd openldap-%{version} %patch5 -p1 -b .ldaprc-currentdir %patch6 -p1 -b .userconfig-setgid %patch7 -p1 -b .nss-free-peer-cert +%patch8 -p1 -b .nss-init-threadsafe cp %{_datadir}/libtool/config/config.{sub,guess} build/ @@ -655,6 +657,7 @@ exit 0 %changelog * Wed Aug 24 2011 Jan Vcelak 2.4.26-2 - security hardening: library needs partial RELRO support added (#733071) +- fix: NSS_Init* functions are not thread safe (#731112) * Sun Aug 14 2011 Rex Dieter - 2.4.26-1.1 - Rebuilt for rpm (#728707)