diff -up nss/lib/pk11wrap/pk11util.c.race nss/lib/pk11wrap/pk11util.c
--- nss/lib/pk11wrap/pk11util.c.race 2017-01-13 17:43:25.829686952 +0100
+++ nss/lib/pk11wrap/pk11util.c 2017-01-13 17:47:56.374041802 +0100
@@ -1297,7 +1297,7 @@ SECMOD_HasRemovableSlots(SECMODModule *m
*/
static SECStatus
secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass,
- const char *sendSpec)
+ const char *sendSpec, PRBool needlock)
{
CK_OBJECT_HANDLE dummy;
CK_ATTRIBUTE template[2];
@@ -1312,16 +1312,16 @@ secmod_UserDBOp(PK11SlotInfo *slot, CK_O
PORT_Assert(attrs - template <= 2);
- PK11_EnterSlotMonitor(slot);
+ if (needlock) PK11_EnterSlotMonitor(slot);
crv = PK11_CreateNewObject(slot, slot->session,
template, attrs - template, PR_FALSE, &dummy);
- PK11_ExitSlotMonitor(slot);
+ if (needlock) PK11_ExitSlotMonitor(slot);
if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv));
return SECFailure;
}
- return SECMOD_UpdateSlotList(slot->module);
+ return SECSuccess;
}
/*
@@ -1330,11 +1330,20 @@ secmod_UserDBOp(PK11SlotInfo *slot, CK_O
static PRBool
secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID)
{
- PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
+ PK11SlotInfo *slot = SECMOD_FindSlotByID(mod, slotID);
if (slot) {
- PRBool present = PK11_IsPresent(slot);
+ CK_SLOT_INFO slotInfo;
+ CK_RV crv;
+ /* check if the slot is present, skip any slot reinit stuff,
+ * or cached present values, or locking. (we don't need to lock
+ * even if the module is not thread safe because we are already
+ * holding the module refLock, which is the same as the slot
+ * sessionLock if the module isn't thread safe. */
+ crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo);
PK11_FreeSlot(slot);
- if (present) {
+ if ((crv == CKR_OK) &&
+ ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT)) {
+ /* slot is present, so it's not empty */
return PR_FALSE;
}
}
@@ -1390,24 +1399,29 @@ SECMOD_OpenNewSlot(SECMODModule *mod, co
char *sendSpec;
SECStatus rv;
+ PZ_Lock(mod->refLock); /* don't reuse a slot on the fly */
slotID = secmod_FindFreeSlot(mod);
if (slotID == (CK_SLOT_ID)-1) {
+ PZ_Unlock(mod->refLock);
return NULL;
}
if (mod->slotCount == 0) {
+ PZ_Unlock(mod->refLock);
return NULL;
}
/* just grab the first slot in the module, any present slot should work */
slot = PK11_ReferenceSlot(mod->slots[0]);
if (slot == NULL) {
+ PZ_Unlock(mod->refLock);
return NULL;
}
/* we've found the slot, now build the moduleSpec */
escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']');
if (escSpec == NULL) {
+ PZ_Unlock(mod->refLock);
PK11_FreeSlot(slot);
return NULL;
}
@@ -1416,16 +1430,26 @@ SECMOD_OpenNewSlot(SECMODModule *mod, co
if (sendSpec == NULL) {
/* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
+ PZ_Unlock(mod->refLock);
PK11_FreeSlot(slot);
PORT_SetError(SEC_ERROR_NO_MEMORY);
return NULL;
}
- rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec);
+ rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec,
+ /* If the module isn't thread safe, the slot sessionLock == mod->refLock
+ * since we already hold the refLock we don't need to lock the sessionLock
+ */
+ mod->isThreadSafe);
+ PZ_Unlock(mod->refLock);
PR_smprintf_free(sendSpec);
PK11_FreeSlot(slot);
if (rv != SECSuccess) {
return NULL;
}
+ rv = SECMOD_UpdateSlotList(mod); /* don't call holding the mod->reflock */
+ if (rv != SECSuccess) {
+ return NULL;
+ }
slot = SECMOD_FindSlotByID(mod, slotID);
if (slot) {
@@ -1558,7 +1582,7 @@ SECMOD_CloseUserDB(PK11SlotInfo *slot)
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
- rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec);
+ rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec, PR_TRUE);
PR_smprintf_free(sendSpec);
/* if we are in the delay period for the "isPresent" call, reset
* the delay since we know things have probably changed... */