|
|
74fc46 |
# HG changeset patch
|
|
|
74fc46 |
# User Robert Relyea <rrelyea@redhat.com>
|
|
|
74fc46 |
# Date 1516007838 -3600
|
|
|
74fc46 |
# Mon Jan 15 10:17:18 2018 +0100
|
|
|
74fc46 |
# Node ID 33d9c969cd6548c335ce43fa8909b96ef323f670
|
|
|
74fc46 |
# Parent db32ef3be38eb06a91babbcbb48285284d704dbd
|
|
|
74fc46 |
Bug 1054373, Crash in PK11_DoesMechanism due to race condition, r=rsleevi
|
|
|
74fc46 |
|
|
|
74fc46 |
diff --git a/lib/dev/devslot.c b/lib/dev/devslot.c
|
|
|
74fc46 |
--- a/lib/dev/devslot.c
|
|
|
74fc46 |
+++ b/lib/dev/devslot.c
|
|
|
74fc46 |
@@ -33,6 +33,8 @@ nssSlot_Destroy(
|
|
|
74fc46 |
if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) {
|
|
|
74fc46 |
PK11_FreeSlot(slot->pk11slot);
|
|
|
74fc46 |
PZ_DestroyLock(slot->base.lock);
|
|
|
74fc46 |
+ PZ_DestroyCondVar(slot->isPresentCondition);
|
|
|
74fc46 |
+ PZ_DestroyLock(slot->isPresentLock);
|
|
|
74fc46 |
return nssArena_Destroy(slot->base.arena);
|
|
|
74fc46 |
}
|
|
|
74fc46 |
}
|
|
|
74fc46 |
@@ -117,35 +119,61 @@ nssSlot_IsTokenPresent(
|
|
|
74fc46 |
nssSession *session;
|
|
|
74fc46 |
CK_SLOT_INFO slotInfo;
|
|
|
74fc46 |
void *epv;
|
|
|
74fc46 |
+ PRBool isPresent = PR_FALSE;
|
|
|
74fc46 |
+
|
|
|
74fc46 |
/* permanent slots are always present unless they're disabled */
|
|
|
74fc46 |
if (nssSlot_IsPermanent(slot)) {
|
|
|
74fc46 |
return !PK11_IsDisabled(slot->pk11slot);
|
|
|
74fc46 |
}
|
|
|
74fc46 |
+
|
|
|
74fc46 |
/* avoid repeated calls to check token status within set interval */
|
|
|
74fc46 |
+ PZ_Lock(slot->isPresentLock);
|
|
|
74fc46 |
if (within_token_delay_period(slot)) {
|
|
|
74fc46 |
- return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
|
|
|
74fc46 |
+ CK_FLAGS ckFlags = slot->ckFlags;
|
|
|
74fc46 |
+ PZ_Unlock(slot->isPresentLock);
|
|
|
74fc46 |
+ return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
|
|
|
74fc46 |
}
|
|
|
74fc46 |
+ PZ_Unlock(slot->isPresentLock);
|
|
|
74fc46 |
|
|
|
74fc46 |
- /* First obtain the slot info */
|
|
|
74fc46 |
+ /* First obtain the slot epv before we set up the condition
|
|
|
74fc46 |
+ * variable, so we can just return if we couldn't get it. */
|
|
|
74fc46 |
epv = slot->epv;
|
|
|
74fc46 |
if (!epv) {
|
|
|
74fc46 |
return PR_FALSE;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
+
|
|
|
74fc46 |
+ /* set up condition so only one thread is active in this part of the code at a time */
|
|
|
74fc46 |
+ PZ_Lock(slot->isPresentLock);
|
|
|
74fc46 |
+ while (slot->inIsPresent) {
|
|
|
74fc46 |
+ PR_WaitCondVar(slot->isPresentCondition, 0);
|
|
|
74fc46 |
+ }
|
|
|
74fc46 |
+ /* if we were one of multiple threads here, the first thread will have
|
|
|
74fc46 |
+ * given us the answer, no need to make more queries of the token. */
|
|
|
74fc46 |
+ if (within_token_delay_period(slot)) {
|
|
|
74fc46 |
+ CK_FLAGS ckFlags = slot->ckFlags;
|
|
|
74fc46 |
+ PZ_Unlock(slot->isPresentLock);
|
|
|
74fc46 |
+ return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
|
|
|
74fc46 |
+ }
|
|
|
74fc46 |
+ /* this is the winning thread, block all others until we've determined
|
|
|
74fc46 |
+ * if the token is present and that it needs initialization. */
|
|
|
74fc46 |
+ slot->inIsPresent = PR_TRUE;
|
|
|
74fc46 |
+ PZ_Unlock(slot->isPresentLock);
|
|
|
74fc46 |
+
|
|
|
74fc46 |
nssSlot_EnterMonitor(slot);
|
|
|
74fc46 |
ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
|
|
|
74fc46 |
nssSlot_ExitMonitor(slot);
|
|
|
74fc46 |
if (ckrv != CKR_OK) {
|
|
|
74fc46 |
slot->token->base.name[0] = 0; /* XXX */
|
|
|
74fc46 |
- slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_FALSE;
|
|
|
74fc46 |
+ isPresent = PR_FALSE;
|
|
|
74fc46 |
+ goto done;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
slot->ckFlags = slotInfo.flags;
|
|
|
74fc46 |
/* check for the presence of the token */
|
|
|
74fc46 |
if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
|
|
|
74fc46 |
if (!slot->token) {
|
|
|
74fc46 |
/* token was never present */
|
|
|
74fc46 |
- slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_FALSE;
|
|
|
74fc46 |
+ isPresent = PR_FALSE;
|
|
|
74fc46 |
+ goto done;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
session = nssToken_GetDefaultSession(slot->token);
|
|
|
74fc46 |
if (session) {
|
|
|
74fc46 |
@@ -167,15 +195,15 @@ nssSlot_IsTokenPresent(
|
|
|
74fc46 |
slot->token->base.name[0] = 0; /* XXX */
|
|
|
74fc46 |
/* clear the token cache */
|
|
|
74fc46 |
nssToken_Remove(slot->token);
|
|
|
74fc46 |
- slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_FALSE;
|
|
|
74fc46 |
+ isPresent = PR_FALSE;
|
|
|
74fc46 |
+ goto done;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
/* token is present, use the session info to determine if the card
|
|
|
74fc46 |
* has been removed and reinserted.
|
|
|
74fc46 |
*/
|
|
|
74fc46 |
session = nssToken_GetDefaultSession(slot->token);
|
|
|
74fc46 |
if (session) {
|
|
|
74fc46 |
- PRBool isPresent = PR_FALSE;
|
|
|
74fc46 |
+ PRBool tokenRemoved;
|
|
|
74fc46 |
nssSession_EnterMonitor(session);
|
|
|
74fc46 |
if (session->handle != CK_INVALID_SESSION) {
|
|
|
74fc46 |
CK_SESSION_INFO sessionInfo;
|
|
|
74fc46 |
@@ -187,12 +215,12 @@ nssSlot_IsTokenPresent(
|
|
|
74fc46 |
session->handle = CK_INVALID_SESSION;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
}
|
|
|
74fc46 |
- isPresent = session->handle != CK_INVALID_SESSION;
|
|
|
74fc46 |
+ tokenRemoved = (session->handle == CK_INVALID_SESSION);
|
|
|
74fc46 |
nssSession_ExitMonitor(session);
|
|
|
74fc46 |
/* token not removed, finished */
|
|
|
74fc46 |
- if (isPresent) {
|
|
|
74fc46 |
- slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_TRUE;
|
|
|
74fc46 |
+ if (!tokenRemoved) {
|
|
|
74fc46 |
+ isPresent = PR_TRUE;
|
|
|
74fc46 |
+ goto done;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
}
|
|
|
74fc46 |
/* the token has been removed, and reinserted, or the slot contains
|
|
|
74fc46 |
@@ -203,15 +231,27 @@ nssSlot_IsTokenPresent(
|
|
|
74fc46 |
nssToken_Remove(slot->token);
|
|
|
74fc46 |
/* token has been removed, need to refresh with new session */
|
|
|
74fc46 |
nssrv = nssSlot_Refresh(slot);
|
|
|
74fc46 |
+ isPresent = PR_TRUE;
|
|
|
74fc46 |
if (nssrv != PR_SUCCESS) {
|
|
|
74fc46 |
slot->token->base.name[0] = 0; /* XXX */
|
|
|
74fc46 |
slot->ckFlags &= ~CKF_TOKEN_PRESENT;
|
|
|
74fc46 |
- /* TODO: insert a barrier here to avoid reordering of the assingments */
|
|
|
74fc46 |
- slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_FALSE;
|
|
|
74fc46 |
+ isPresent = PR_FALSE;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
+done:
|
|
|
74fc46 |
+ /* Once we've set up the condition variable,
|
|
|
74fc46 |
+ * Before returning, it's necessary to:
|
|
|
74fc46 |
+ * 1) Set the lastTokenPing time so that any other threads waiting on this
|
|
|
74fc46 |
+ * initialization and any future calls within the initialization window
|
|
|
74fc46 |
+ * return the just-computed status.
|
|
|
74fc46 |
+ * 2) Indicate we're complete, waking up all other threads that may still
|
|
|
74fc46 |
+ * be waiting on initialization can progress.
|
|
|
74fc46 |
+ */
|
|
|
74fc46 |
+ PZ_Lock(slot->isPresentLock);
|
|
|
74fc46 |
slot->lastTokenPing = PR_IntervalNow();
|
|
|
74fc46 |
- return PR_TRUE;
|
|
|
74fc46 |
+ slot->inIsPresent = PR_FALSE;
|
|
|
74fc46 |
+ PR_NotifyAllCondVar(slot->isPresentCondition);
|
|
|
74fc46 |
+ PZ_Unlock(slot->isPresentLock);
|
|
|
74fc46 |
+ return isPresent;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
|
|
|
74fc46 |
NSS_IMPLEMENT void *
|
|
|
74fc46 |
@@ -229,7 +269,7 @@ nssSlot_GetToken(
|
|
|
74fc46 |
|
|
|
74fc46 |
if (nssSlot_IsTokenPresent(slot)) {
|
|
|
74fc46 |
/* Even if a token should be present, check `slot->token` too as it
|
|
|
74fc46 |
- * might be gone already. This would happen mostly on shutdown. */
|
|
|
74fc46 |
+ * might be gone already. This would happen mostly on shutdown. */
|
|
|
74fc46 |
nssSlot_EnterMonitor(slot);
|
|
|
74fc46 |
if (slot->token)
|
|
|
74fc46 |
rvToken = nssToken_AddRef(slot->token);
|
|
|
74fc46 |
diff --git a/lib/dev/devt.h b/lib/dev/devt.h
|
|
|
74fc46 |
--- a/lib/dev/devt.h
|
|
|
74fc46 |
+++ b/lib/dev/devt.h
|
|
|
74fc46 |
@@ -81,6 +81,9 @@ struct NSSSlotStr {
|
|
|
74fc46 |
PZLock *lock;
|
|
|
74fc46 |
void *epv;
|
|
|
74fc46 |
PK11SlotInfo *pk11slot;
|
|
|
74fc46 |
+ PZLock *isPresentLock;
|
|
|
74fc46 |
+ PRCondVar *isPresentCondition;
|
|
|
74fc46 |
+ PRBool inIsPresent;
|
|
|
74fc46 |
};
|
|
|
74fc46 |
|
|
|
74fc46 |
struct nssSessionStr {
|
|
|
74fc46 |
diff --git a/lib/pk11wrap/dev3hack.c b/lib/pk11wrap/dev3hack.c
|
|
|
74fc46 |
--- a/lib/pk11wrap/dev3hack.c
|
|
|
74fc46 |
+++ b/lib/pk11wrap/dev3hack.c
|
|
|
74fc46 |
@@ -120,6 +120,9 @@ nssSlot_CreateFromPK11SlotInfo(NSSTrustD
|
|
|
74fc46 |
/* Grab the slot name from the PKCS#11 fixed-length buffer */
|
|
|
74fc46 |
rvSlot->base.name = nssUTF8_Duplicate(nss3slot->slot_name, td->arena);
|
|
|
74fc46 |
rvSlot->lock = (nss3slot->isThreadSafe) ? NULL : nss3slot->sessionLock;
|
|
|
74fc46 |
+ rvSlot->isPresentLock = PZ_NewLock(nssiLockOther);
|
|
|
74fc46 |
+ rvSlot->isPresentCondition = PR_NewCondVar(rvSlot->isPresentLock);
|
|
|
74fc46 |
+ rvSlot->inIsPresent = PR_FALSE;
|
|
|
74fc46 |
return rvSlot;
|
|
|
74fc46 |
}
|
|
|
74fc46 |
|