From 7d12a23186b0e5abd3b51457fb39bd7ce85ddd1d Mon Sep 17 00:00:00 2001 From: "wtc%netscape.com" Date: Tue, 5 Feb 2002 23:41:36 +0000 Subject: [PATCH] Bugzilla bug 121523: checked in Kirk Erickson's session lock fix. Modified Files: lib/pk11wrap/pk11slot.c lib/softoken/pkcs11.c lib/softoken/pkcs11i.h lib/softoken/pkcs11u.c --- security/nss/lib/pk11wrap/pk11slot.c | 4 +- security/nss/lib/softoken/pkcs11.c | 76 +++++++++++++++++++--------- security/nss/lib/softoken/pkcs11i.h | 42 +++++++++++++-- security/nss/lib/softoken/pkcs11u.c | 20 +++----- 4 files changed, 98 insertions(+), 44 deletions(-) diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index 82a48c68d86f..76b63971c1a6 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -3632,10 +3632,10 @@ PK11_GenerateRandom(unsigned char *data,int len) { slot = PK11_GetBestSlot(CKM_FAKE_RANDOM,NULL); if (slot == NULL) return SECFailure; - PK11_EnterSlotMonitor(slot); + if (!slot->isInternal) PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session,data, (CK_ULONG)len); - PK11_ExitSlotMonitor(slot); + if (!slot->isInternal) PK11_ExitSlotMonitor(slot); PK11_FreeSlot(slot); return (crv != CKR_OK) ? SECFailure : SECSuccess; } diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 10585e447f1c..ca989449a4f6 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -1983,12 +1983,19 @@ PK11_SlotInit(char *configdir,pk11_token_parameters *params) } #ifdef PKCS11_USE_THREADS - slot->sessionLock = PZ_NewLock(nssILockSession); - if (slot->sessionLock == NULL) return CKR_HOST_MEMORY; + slot->slotLock = PZ_NewLock(nssILockSession); + if (slot->slotLock == NULL) return CKR_HOST_MEMORY; + for (i=0; i < NUMBER_OF_SESSION_LOCKS; i++) { + slot->sessionLock[i] = PZ_NewLock(nssILockSession); + if (slot->sessionLock[i] == NULL) return CKR_HOST_MEMORY; + } slot->objectLock = PZ_NewLock(nssILockObject); if (slot->objectLock == NULL) return CKR_HOST_MEMORY; #else - slot->sessionLock = NULL; + slot->slotLock = NULL; + for (i=0; i < NUMBER_OF_SESSION_LOCKS; i++) { + slot->sessionLock[i] = NULL; + } slot->objectLock = NULL; #endif for(i=0; i < SESSION_HASH_SIZE; i++) { @@ -2067,9 +2074,15 @@ pk11_DestroySlotData(PK11Slot *slot) int i; #ifdef PKCS11_USE_THREADS - if (slot->sessionLock) { - PZ_DestroyLock(slot->sessionLock); - slot->sessionLock = NULL; + if (slot->slotLock) { + PZ_DestroyLock(slot->slotLock); + slot->slotLock = NULL; + } + for (i=0; i < NUMBER_OF_SESSION_LOCKS; i++) { + if (slot->sessionLock[i]) { + PZ_DestroyLock(slot->sessionLock[i]); + slot->sessionLock[i] = NULL; + } } if (slot->objectLock) { PZ_DestroyLock(slot->objectLock); @@ -2665,21 +2678,23 @@ CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, flags | CKF_SERIAL_SESSION); if (session == NULL) return CKR_HOST_MEMORY; - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) sessionID = slot->sessionIDCount++ | (slot->index << 24); if (slot->readOnly && (flags & CKF_RW_SESSION)) { /* NETSCAPE_SLOT_ID is Read ONLY */ session->info.flags &= ~CKF_RW_SESSION; } - - session->handle = sessionID; - pk11_update_state(slot, session); - pk11queue_add(session, sessionID, slot->head, SESSION_HASH_SIZE); slot->sessionCount++; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount++; } - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) + + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,sessionID));) + session->handle = sessionID; + pk11_update_state(slot, session); + pk11queue_add(session, sessionID, slot->head, SESSION_HASH_SIZE); + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,sessionID));) *phSession = sessionID; return CKR_OK; @@ -2692,16 +2707,25 @@ CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession) PK11Slot *slot; PK11Session *session; SECItem *pw = NULL; + PRBool sessionFound; session = pk11_SessionFromHandle(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; slot = pk11_SlotFromSession(session); + sessionFound = PR_FALSE; /* lock */ - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,hSession));) if (pk11queue_is_queued(session,hSession,slot->head,SESSION_HASH_SIZE)) { + sessionFound = PR_TRUE; pk11queue_delete(session,hSession,slot->head,SESSION_HASH_SIZE); session->refCount--; /* can't go to zero while we hold the reference */ + PORT_Assert(session->refCount > 0); + } + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,hSession));) + + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) + if (sessionFound) { slot->sessionCount--; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount--; @@ -2712,7 +2736,7 @@ CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession) slot->isLoggedIn = PR_FALSE; slot->password = NULL; } - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) pk11_FreeSession(session); if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); @@ -2732,11 +2756,11 @@ CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID) if (slot == NULL) return CKR_SLOT_ID_INVALID; /* first log out the card */ - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) pw = slot->password; slot->isLoggedIn = PR_FALSE; slot->password = NULL; - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); /* now close all the current sessions */ @@ -2746,7 +2770,7 @@ CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID) * will guarrenteed be close, and no session will be partially closed */ for (i=0; i < SESSION_HASH_SIZE; i++) { do { - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,i));) session = slot->head[i]; /* hand deque */ /* this duplicates function of NSC_close session functions, but @@ -2756,12 +2780,16 @@ CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID) slot->head[i] = session->next; if (session->next) session->next->prev = NULL; session->next = session->prev = NULL; + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,i));) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) slot->sessionCount--; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount--; } + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) + } else { + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,i));) } - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) if (session) pk11_FreeSession(session); } while (session != NULL); } @@ -2836,12 +2864,12 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, /* should this be a fixed password? */ if (ulPinLen == 0) { SECItem *pw; - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) pw = slot->password; slot->password = NULL; slot->isLoggedIn = PR_TRUE; slot->ssoLoggedIn = (PRBool)(userType == CKU_SO); - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) pk11_update_all_states(slot); SECITEM_ZfreeItem(pw,PR_TRUE); return CKR_OK; @@ -2861,11 +2889,11 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, if (nsslowkey_CheckKeyDBPassword(handle,pin) == SECSuccess) { SECItem *tmp; - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) tmp = slot->password; slot->isLoggedIn = PR_TRUE; slot->password = pin; - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) if (tmp) SECITEM_ZfreeItem(tmp, PR_TRUE); /* update all sessions */ @@ -2891,12 +2919,12 @@ CK_RV NSC_Logout(CK_SESSION_HANDLE hSession) if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN; - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(slot->slotLock);) pw = slot->password; slot->isLoggedIn = PR_FALSE; slot->ssoLoggedIn = PR_FALSE; slot->password = NULL; - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(slot->slotLock);) if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); pk11_update_all_states(slot); diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h index 0efc99068130..a42a41794d68 100644 --- a/security/nss/lib/softoken/pkcs11i.h +++ b/security/nss/lib/softoken/pkcs11i.h @@ -107,13 +107,35 @@ #define ATTRIBUTE_HASH_SIZE 32 #define SESSION_OBJECT_HASH_SIZE 32 #define TOKEN_OBJECT_HASH_SIZE 1024 -#define SESSION_HASH_SIZE 512 +#define SESSION_HASH_SIZE 1024 #define MAX_OBJECT_LIST_SIZE 800 /* how many objects to keep on the free list * before we start freeing them */ #endif #define MAX_KEY_LEN 256 - +/* + * LOG2_BUCKETS_PER_SESSION_LOCK must be a prime number. + * With SESSION_HASH_SIZE=1024, LOG2 can be 9, 5, 1, or 0. + * With SESSION_HASH_SIZE=4096, LOG2 can be 11, 9, 5, 1, or 0. + * + * HASH_SIZE LOG2_BUCKETS_PER BUCKETS_PER_LOCK NUMBER_OF_BUCKETS + * 1024 9 512 2 + * 1024 5 32 32 + * 1024 1 2 512 + * 1024 0 1 1024 + * 4096 11 2048 2 + * 4096 9 512 8 + * 4096 5 32 128 + * 4096 1 2 2048 + * 4096 0 1 4096 + */ +#define LOG2_BUCKETS_PER_SESSION_LOCK 1 +#define BUCKETS_PER_SESSION_LOCK (1 << (LOG2_BUCKETS_PER_SESSION_LOCK)) +#define NUMBER_OF_SESSION_LOCKS (SESSION_HASH_SIZE/BUCKETS_PER_SESSION_LOCK) +/* NOSPREAD sessionID to hash table index macro has been slower. */ +#if 0 +#define NOSPREAD +#endif #ifdef PKCS11_USE_THREADS #define PK11_USE_THREADS(x) x @@ -304,7 +326,6 @@ struct PK11SessionStr { PK11Session *prev; CK_SESSION_HANDLE handle; int refCount; - PZLock *refLock; PZLock *objectLock; int objectIDCount; CK_SESSION_INFO info; @@ -323,7 +344,8 @@ struct PK11SessionStr { */ struct PK11SlotStr { CK_SLOT_ID slotID; - PZLock *sessionLock; + PZLock *slotLock; + PZLock *sessionLock[NUMBER_OF_SESSION_LOCKS]; PZLock *objectLock; SECItem *password; PRBool hasTokens; @@ -428,6 +450,18 @@ struct PK11SSLMACInfoStr { (element)->next = NULL; \ (element)->prev = NULL; \ +/* sessionID (handle) is used to determine session lock bucket */ +#ifdef NOSPREAD +/* NOSPREAD: (ID>>L2LPB) & (perbucket-1) */ +#define PK11_SESSION_LOCK(slot,handle) \ + ((slot)->sessionLock[((handle) >> LOG2_BUCKETS_PER_SESSION_LOCK) \ + & (NUMBER_OF_SESSION_LOCKS-1)]) +#else +/* SPREAD: ID & (perbucket-1) */ +#define PK11_SESSION_LOCK(slot,handle) \ + ((slot)->sessionLock[(handle) & (NUMBER_OF_SESSION_LOCKS-1)]) +#endif + /* expand an attribute & secitem structures out */ #define pk11_attr_expand(ap) (ap)->type,(ap)->pValue,(ap)->ulValueLen #define pk11_item_expand(ip) (ip)->data,(ip)->len diff --git a/security/nss/lib/softoken/pkcs11u.c b/security/nss/lib/softoken/pkcs11u.c index 04322563432d..423f82b6afc4 100644 --- a/security/nss/lib/softoken/pkcs11u.c +++ b/security/nss/lib/softoken/pkcs11u.c @@ -2320,11 +2320,11 @@ pk11_update_all_states(PK11Slot *slot) PK11Session *session; for (i=0; i < SESSION_HASH_SIZE; i++) { - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,i));) for (session = slot->head[i]; session; session = session->next) { pk11_update_state(slot,session); } - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,i));) } } @@ -2371,19 +2371,12 @@ pk11_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, session->search = NULL; session->objectIDCount = 1; #ifdef PKCS11_USE_THREADS - session->refLock = PZ_NewLock(nssILockRefLock); - if (session->refLock == NULL) { - PORT_Free(session); - return NULL; - } session->objectLock = PZ_NewLock(nssILockObject); if (session->objectLock == NULL) { - PK11_USE_THREADS(PZ_DestroyLock(session->refLock);) PORT_Free(session); return NULL; } #else - session->refLock = NULL; session->objectLock = NULL; #endif session->objects[0] = NULL; @@ -2415,7 +2408,6 @@ pk11_DestroySession(PK11Session *session) pk11_DeleteObject(session,op->parent); } PK11_USE_THREADS(PZ_DestroyLock(session->objectLock);) - PK11_USE_THREADS(PZ_DestroyLock(session->refLock);) if (session->enc_context) { pk11_FreeContext(session->enc_context); } @@ -2442,10 +2434,10 @@ pk11_SessionFromHandle(CK_SESSION_HANDLE handle) PK11Slot *slot = pk11_SlotFromSessionHandle(handle); PK11Session *session; - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,handle));) pk11queue_find(session,handle,slot->head,SESSION_HASH_SIZE); if (session) session->refCount++; - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,handle));) return (session); } @@ -2459,10 +2451,10 @@ pk11_FreeSession(PK11Session *session) PRBool destroy = PR_FALSE; PK11_USE_THREADS(PK11Slot *slot = pk11_SlotFromSession(session);) - PK11_USE_THREADS(PZ_Lock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Lock(PK11_SESSION_LOCK(slot,session->handle));) if (session->refCount == 1) destroy = PR_TRUE; session->refCount--; - PK11_USE_THREADS(PZ_Unlock(slot->sessionLock);) + PK11_USE_THREADS(PZ_Unlock(PK11_SESSION_LOCK(slot,session->handle));) if (destroy) pk11_DestroySession(session); }