diff --git a/mozilla/security/nss/lib/ssl/sslsnce.c b/mozilla/security/nss/lib/ssl/sslsnce.c index 37a8d41cd74..94b180cef9e 100644 --- a/mozilla/security/nss/lib/ssl/sslsnce.c +++ b/mozilla/security/nss/lib/ssl/sslsnce.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslsnce.c,v 1.25 2003-03-27 03:07:47 nelsonb%netscape.com Exp $ + * $Id: sslsnce.c,v 1.26 2003-10-19 01:25:10 nelsonb%netscape.com Exp $ */ /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server @@ -64,7 +64,7 @@ * sidCacheEntry sidCacheData[ numSIDCacheEntries]; * certCacheEntry certCacheData[numCertCacheEntries]; * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; - * } sharedMemCacheData; + * } cacheMemCacheData; */ #include "nssrenam.h" #include "seccomon.h" @@ -183,7 +183,7 @@ typedef struct sidCacheSetStr sidCacheSet; struct cacheDescStr { - PRUint32 sharedMemSize; + PRUint32 cacheMemSize; PRUint32 numSIDCacheLocks; PRUint32 numSIDCacheSets; @@ -201,9 +201,12 @@ struct cacheDescStr { PRUint32 ssl2Timeout; PRUint32 ssl3Timeout; + PRUint32 numSIDCacheLocksInitialized; + /* These values are volatile, and are accessed through sharedCache-> */ PRUint32 nextCertCacheEntry; /* certCacheLock protects */ PRBool stopPolling; + PRBool everInherited; /* The private copies of these values are pointers into shared mem */ /* The copies of these values in shared memory are merely offsets */ @@ -216,11 +219,11 @@ struct cacheDescStr { SSLWrappedSymWrappingKey * keyCacheData; /* Only the private copies of these pointers are valid */ - char * sharedMem; + char * cacheMem; struct cacheDescStr * sharedCache; /* shared copy of this struct */ PRFileMap * cacheMemMap; PRThread * poller; - PRBool shared; + PRBool shared; }; typedef struct cacheDescStr cacheDesc; @@ -263,15 +266,14 @@ static sslPID myPid; static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS; /* forward static function declarations */ -static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl); +static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, + unsigned nl); static SECStatus LaunchLockPoller(cacheDesc *cache); - - struct inheritanceStr { - PRUint32 sharedMemSize; - PRUint16 fmStrLen; + PRUint32 cacheMemSize; + PRUint32 fmStrLen; }; typedef struct inheritanceStr inheritance; @@ -881,24 +883,60 @@ long gettid(void) } #endif +static void +CloseCache(cacheDesc *cache) +{ + int locks_initialized = cache->numSIDCacheLocksInitialized; + + if (cache->cacheMem) { + /* If everInherited is true, this shared cache was (and may still + ** be) in use by multiple processes. We do not wish to destroy + ** the mutexes while they are still in use. + */ + if (PR_FALSE == cache->sharedCache->everInherited) { + sidCacheLock *pLock = cache->sidCacheLocks; + for (; locks_initialized > 0; --locks_initialized, ++pLock ) { + sslMutex_Destroy(&pLock->mutex); + } + } + if (cache->shared) { + PR_MemUnmap(cache->cacheMem, cache->cacheMemSize); + } else { + PORT_Free(cache->cacheMem); + } + cache->cacheMem = NULL; + } + if (cache->cacheMemMap) { + PR_CloseFileMap(cache->cacheMemMap); + cache->cacheMemMap = NULL; + } + memset(cache, 0, sizeof *cache); +} + static SECStatus InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, PRUint32 ssl3_timeout, const char *directory, PRBool shared) { ptrdiff_t ptr; sidCacheLock *pLock; - char * sharedMem; + char * cacheMem; PRFileMap * cacheMemMap; char * cfn = NULL; /* cache file name */ int locks_initialized = 0; int locks_to_initialize = 0; PRUint32 init_time; - if (cache->sharedMem) { + if (cache->cacheMem) { /* Already done */ return SECSuccess; } + /* make sure loser can clean up properly */ + cache->shared = shared; + cache->cacheMem = cacheMem = NULL; + cache->cacheMemMap = cacheMemMap = NULL; + cache->sharedCache = (cacheDesc *)0; + cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries : DEF_SID_CACHE_ENTRIES; cache->numSIDCacheSets = @@ -915,7 +953,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, /* compute size of shared memory, and offsets of all pointers */ ptr = 0; - cache->sharedMem = (char *)ptr; + cache->cacheMem = (char *)ptr; ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT); cache->sidCacheLocks = (sidCacheLock *)ptr; @@ -951,7 +989,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - cache->sharedMemSize = ptr; + cache->cacheMemSize = ptr; cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; @@ -979,67 +1017,60 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, cache->ssl3Timeout = DEF_SSL3_TIMEOUT; } - /* Create file names */ + if (shared) { + /* Create file names */ #if defined(XP_UNIX) || defined(XP_BEOS) - /* there's some confusion here about whether PR_OpenAnonFileMap wants - ** a directory name or a file name for its first argument. - cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); - */ - cfn = PR_smprintf("%s", directory); -#endif - -#ifdef XP_WIN32 - cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, - GetCurrentThreadId()); + /* there's some confusion here about whether PR_OpenAnonFileMap wants + ** a directory name or a file name for its first argument. + cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); + */ + cfn = PR_smprintf("%s", directory); +#elif defined(XP_WIN32) + cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, + GetCurrentThreadId()); +#elif defined(XP_OS2) + cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, + gettid()); +#else +#error "Don't know how to create file name for this platform!" #endif + if (!cfn) { + goto loser; + } -#ifdef XP_OS2 - cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, - gettid()); -#endif - if (!cfn) { - goto loser; - } + /* Create cache */ + cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, + PR_PROT_READWRITE); - cache->shared = shared; - /* Create cache */ - if (PR_TRUE == shared) { - cacheMemMap = PR_OpenAnonFileMap(cfn, cache->sharedMemSize, - PR_PROT_READWRITE); + PR_smprintf_free(cfn); + if(!cacheMemMap) { + goto loser; + } + + cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize); } else { - cacheMemMap = NULL; - } - - PR_smprintf_free(cfn); - if( (PR_TRUE == shared) && (!cacheMemMap) ) { - goto loser; - } - - if (PR_TRUE == shared) { - sharedMem = PR_MemMap(cacheMemMap, 0, cache->sharedMemSize); - } else { - sharedMem = PORT_Alloc(cache->sharedMemSize); + cacheMem = PORT_Alloc(cache->cacheMemSize); } - if (! sharedMem) { + if (! cacheMem) { goto loser; } /* Initialize shared memory. This may not be necessary on all platforms */ - memset(sharedMem, 0, cache->sharedMemSize); + memset(cacheMem, 0, cache->cacheMemSize); /* Copy cache descriptor header into shared memory */ - memcpy(sharedMem, cache, sizeof *cache); + memcpy(cacheMem, cache, sizeof *cache); /* save private copies of these values */ cache->cacheMemMap = cacheMemMap; - cache->sharedMem = sharedMem; - cache->sharedCache = (cacheDesc *)sharedMem; + cache->cacheMem = cacheMem; + cache->sharedCache = (cacheDesc *)cacheMem; /* Fix pointers in our private copy of cache descriptor to point to ** spaces in shared memory */ - ptr = (ptrdiff_t)cache->sharedMem; + ptr = (ptrdiff_t)cache->cacheMem; *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; *(ptrdiff_t *)(&cache->certCacheLock) += ptr; @@ -1055,36 +1086,20 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, locks_initialized < locks_to_initialize; ++locks_initialized, ++pLock ) { - SECStatus err = sslMutex_Init(&pLock->mutex, isMultiProcess); - if (err) + SECStatus err = sslMutex_Init(&pLock->mutex, shared); + if (err) { + cache->numSIDCacheLocksInitialized = locks_initialized; goto loser; + } pLock->timeStamp = init_time; pLock->pid = 0; } + cache->numSIDCacheLocksInitialized = locks_initialized; return SECSuccess; loser: - if (cache->cacheMemMap) { - if (cache->sharedMem) { - if (locks_initialized > 0) { - pLock = cache->sidCacheLocks; - for (; locks_initialized > 0; --locks_initialized, ++pLock ) { - sslMutex_Destroy(&pLock->mutex); - } - } - if (shared) { - PR_MemUnmap(cache->sharedMem, cache->sharedMemSize); - cache->sharedMem = NULL; - } - } - if (shared) { - PR_CloseFileMap(cache->cacheMemMap); - } else { - PORT_Free(sharedMem); - } - cache->cacheMemMap = NULL; - } + CloseCache(cache); return SECFailure; } @@ -1161,9 +1176,7 @@ SSL_ConfigServerSessionIDCache( int maxCacheEntries, SECStatus SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache) { - /* if single process, close down, clean up. - ** if multi-process, TBD. - */ + CloseCache(cache); return SECSuccess; } @@ -1195,7 +1208,7 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries, isMultiProcess = PR_TRUE; result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, - ssl2_timeout, ssl3_timeout, directory, PR_TRUE); + ssl2_timeout, ssl3_timeout, directory, PR_TRUE); if (result != SECSuccess) return result; @@ -1206,7 +1219,7 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries, return SECFailure; } - inherit.sharedMemSize = cache->sharedMemSize; + inherit.cacheMemSize = cache->cacheMemSize; inherit.fmStrLen = fmStrLen; inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit); @@ -1240,6 +1253,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) { unsigned char * decoString = NULL; char * fmString = NULL; + char * myEnvString = NULL; unsigned int decoLen; ptrdiff_t ptr; inheritance inherit; @@ -1256,9 +1270,12 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) ** then isMultiProcess will already be set. ** If not, we'll set it below. */ - if (isMultiProcess) + if (isMultiProcess) { + if (cache && cache->sharedCache) { + cache->sharedCache->everInherited = PR_TRUE; + } return SECSuccess; /* already done. */ - + } ssl_sid_lookup = ServerSessionIDLookup; ssl_sid_cache = ServerSessionIDCache; ssl_sid_uncache = ServerSessionIDUncache; @@ -1270,15 +1287,15 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) return SECFailure; } } - envString = PORT_Strdup(envString); - if (!envString) + myEnvString = PORT_Strdup(envString); + if (!myEnvString) return SECFailure; - fmString = strchr(envString, ','); + fmString = strchr(myEnvString, ','); if (!fmString) goto loser; *fmString++ = 0; - decoString = ATOB_AsciiToData(envString, &decoLen); + decoString = ATOB_AsciiToData(myEnvString, &decoLen); if (!decoString) { SET_ERROR_CODE goto loser; @@ -1294,34 +1311,39 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) goto loser; } - memset(&my, 0, sizeof my); - my.sharedMemSize = inherit.sharedMemSize; + memset(cache, 0, sizeof *cache); + cache->cacheMemSize = inherit.cacheMemSize; /* Create cache */ - my.cacheMemMap = PR_ImportFileMapFromString(fmString); - if(! my.cacheMemMap) { + cache->cacheMemMap = PR_ImportFileMapFromString(fmString); + if(! cache->cacheMemMap) { goto loser; } - my.sharedMem = PR_MemMap(my.cacheMemMap, 0, my.sharedMemSize); - if (! my.sharedMem) { + cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize); + if (! cache->cacheMem) { goto loser; } - my.sharedCache = (cacheDesc *)my.sharedMem; + cache->sharedCache = (cacheDesc *)cache->cacheMem; - if (my.sharedCache->sharedMemSize != my.sharedMemSize) { + if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) { SET_ERROR_CODE goto loser; } - memcpy(cache, my.sharedCache, sizeof *cache); - cache->cacheMemMap = my.cacheMemMap; - cache->sharedMem = my.sharedMem; - cache->sharedCache = my.sharedCache; + /* We're now going to overwrite the local cache instance with the + ** shared copy of the cache struct, then update several values in + ** the local cache using the values for cache->cacheMemMap and + ** cache->cacheMem computed just above. So, we copy cache into + ** the automatic variable "my", to preserve the variables while + ** cache is overwritten. + */ + my = *cache; /* save values computed above. */ + memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */ /* Fix pointers in our private copy of cache descriptor to point to - ** spaces in shared memory + ** spaces in shared memory, whose address is now in "my". */ - ptr = (ptrdiff_t)cache->sharedMem; + ptr = (ptrdiff_t)my.cacheMem; *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; *(ptrdiff_t *)(&cache->certCacheLock) += ptr; @@ -1330,49 +1352,66 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) *(ptrdiff_t *)(&cache->certCacheData) += ptr; *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; + cache->cacheMemMap = my.cacheMemMap; + cache->cacheMem = my.cacheMem; + cache->sharedCache = (cacheDesc *)cache->cacheMem; + #ifdef WINNT /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers - When NT fibers are used in a multi-process server, a second level of - locking is needed to prevent a deadlock, in case a fiber acquires the - cross-process mutex, yields, and another fiber is later scheduled on - the same native thread and tries to acquire the cross-process mutex. - We do this by using a PRLock in the sslMutex. However, it is stored in - shared memory as part of sidCacheLocks, and we don't want to overwrite - the PRLock of the parent process. So we need to make new, private - copies of sidCacheLocks before modifying the sslMutex with our own - PRLock + ** When NT fibers are used in a multi-process server, a second level of + ** locking is needed to prevent a deadlock, in case a fiber acquires the + ** cross-process mutex, yields, and another fiber is later scheduled on + ** the same native thread and tries to acquire the cross-process mutex. + ** We do this by using a PRLock in the sslMutex. However, it is stored in + ** shared memory as part of sidCacheLocks, and we don't want to overwrite + ** the PRLock of the parent process. So we need to make new, private + ** copies of sidCacheLocks before modifying the sslMutex with our own + ** PRLock */ - newLocks = (sidCacheLock*)PORT_Alloc(sizeof(sidCacheLock)*(cache->numSIDCacheLocks + 2)); /* note from jpierre : this should be free'd in child processes when - a function is added to delete the SSL session cache in the future */ - /* fix the locks */ - for (locks_to_initialize = cache->numSIDCacheLocks + 2; - locks_initialized < locks_to_initialize; - ++locks_initialized) { - /* copy the old lock */ - memcpy(&newLocks[locks_initialized], &cache->sidCacheLocks[locks_initialized], sizeof(sidCacheLock)); - /* now, make a local PRLock in this sslMutex for this child process */ - sslMutex_2LevelInit(&newLocks[locks_initialized].mutex); - } - - /* then, make our cache object point to our new private sidCacheLocks */ - /* first the session cache */ + ** a function is added to delete the SSL session cache in the future. + */ + locks_to_initialize = cache->numSIDCacheLocks + 2; + newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize); cache->sidCacheLocks = newLocks; + if (!newLocks) + goto loser; + /* copy the old locks */ + memcpy(newLocks, cache->sidCacheLocks, + locks_to_initialize * sizeof(sidCacheLock)); + /* fix the locks */ + for (; locks_initialized < locks_to_initialize; ++locks_initialized) { + /* now, make a local PRLock in this sslMutex for this child process */ + SECStatus err; + err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex); + if (err != SECSuccess) { + cache->numSIDCacheLocksInitialized = locks_initialized; + goto loser; + } + } + cache->numSIDCacheLocksInitialized = locks_initialized; + /* also fix the key and cert cache which use the last 2 lock entries */ cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; cache->certCacheLock = cache->keyCacheLock + 1; #endif + PORT_Free(myEnvString); PORT_Free(decoString); + + /* mark that we have inherited this. */ + cache->sharedCache->everInherited = PR_TRUE; isMultiProcess = PR_TRUE; + return SECSuccess; loser: + PORT_Free(myEnvString); if (decoString) PORT_Free(decoString); + CloseCache(cache); return SECFailure; - } SECStatus