Skip to content

Commit

Permalink
Bug 1607449 - Lock cert->nssCertificate to prevent data race. r=keeler
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D64233

--HG--
extra : moz-landing-system : lando
  • Loading branch information
Kevin Jacobs committed Nov 9, 2020
1 parent 7b9950a commit e856c01
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
30 changes: 15 additions & 15 deletions lib/certdb/certdb.c
Expand Up @@ -2908,16 +2908,16 @@ CERT_LockCertTrust(const CERTCertificate *cert)
PZ_Lock(certTrustLock);
}

static PZLock *certTempPermLock = NULL;
static PZLock *certTempPermCertLock = NULL;

/*
* Acquire the cert temp/perm lock
* Acquire the cert temp/perm/nssCert lock
*/
void
CERT_LockCertTempPerm(const CERTCertificate *cert)
{
PORT_Assert(certTempPermLock != NULL);
PZ_Lock(certTempPermLock);
PORT_Assert(certTempPermCertLock != NULL);
PZ_Lock(certTempPermCertLock);
}

SECStatus
Expand All @@ -2941,10 +2941,10 @@ cert_InitLocks(void)
}
}

if (certTempPermLock == NULL) {
certTempPermLock = PZ_NewLock(nssILockCertDB);
PORT_Assert(certTempPermLock != NULL);
if (!certTempPermLock) {
if (certTempPermCertLock == NULL) {
certTempPermCertLock = PZ_NewLock(nssILockCertDB);
PORT_Assert(certTempPermCertLock != NULL);
if (!certTempPermCertLock) {
PZ_DestroyLock(certTrustLock);
PZ_DestroyLock(certRefCountLock);
certRefCountLock = NULL;
Expand Down Expand Up @@ -2977,10 +2977,10 @@ cert_DestroyLocks(void)
rv = SECFailure;
}

PORT_Assert(certTempPermLock != NULL);
if (certTempPermLock) {
PZ_DestroyLock(certTempPermLock);
certTempPermLock = NULL;
PORT_Assert(certTempPermCertLock != NULL);
if (certTempPermCertLock) {
PZ_DestroyLock(certTempPermCertLock);
certTempPermCertLock = NULL;
} else {
rv = SECFailure;
}
Expand All @@ -2999,13 +2999,13 @@ CERT_UnlockCertTrust(const CERTCertificate *cert)
}

/*
* Free the temp/perm lock
* Free the temp/perm/nssCert lock
*/
void
CERT_UnlockCertTempPerm(const CERTCertificate *cert)
{
PORT_Assert(certTempPermLock != NULL);
PRStatus prstat = PZ_Unlock(certTempPermLock);
PORT_Assert(certTempPermCertLock != NULL);
PRStatus prstat = PZ_Unlock(certTempPermCertLock);
PORT_AssertArg(prstat == PR_SUCCESS);
}

Expand Down
14 changes: 12 additions & 2 deletions lib/certdb/stanpcertdb.c
Expand Up @@ -311,7 +311,9 @@ __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
nssPKIObject_AddInstance(&c->object, permInstance);
nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
/* reset the CERTCertificate fields */
CERT_LockCertTempPerm(cert);
cert->nssCertificate = NULL;
CERT_UnlockCertTempPerm(cert);
cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */
if (!cert) {
CERT_MapStanError();
Expand Down Expand Up @@ -808,9 +810,17 @@ CERT_DestroyCertificate(CERTCertificate *cert)
/* don't use STAN_GetNSSCertificate because we don't want to
* go to the trouble of translating the CERTCertificate into
* an NSSCertificate just to destroy it. If it hasn't been done
* yet, don't do it at all.
*/
* yet, don't do it at all
*
* cert->nssCertificate contains its own locks and refcount, but as it
* may be NULL, the pointer itself must be guarded by some other lock.
* Rather than creating a new global lock for only this purpose, share
* an existing global lock that happens to be taken near the write in
* fill_CERTCertificateFields(). The longer-term goal is to refactor
* all these global locks to be certificate-scoped. */
CERT_LockCertTempPerm(cert);
NSSCertificate *tmp = cert->nssCertificate;
CERT_UnlockCertTempPerm(cert);
if (tmp) {
/* delete the NSSCertificate */
NSSCertificate_Destroy(tmp);
Expand Down
7 changes: 5 additions & 2 deletions lib/pk11wrap/pk11cert.c
Expand Up @@ -1148,8 +1148,11 @@ PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
}

/* need to get the cert as a stan cert */
if (cert->nssCertificate) {
c = cert->nssCertificate;
CERT_LockCertTempPerm(cert);
NSSCertificate *nssCert = cert->nssCertificate;
CERT_UnlockCertTempPerm(cert);
if (nssCert) {
c = nssCert;
} else {
c = STAN_GetNSSCertificate(cert);
if (c == NULL) {
Expand Down
11 changes: 9 additions & 2 deletions lib/pki/pki3hack.c
Expand Up @@ -866,9 +866,9 @@ fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced
CERT_LockCertTempPerm(cc);
cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
cc->isperm = PR_TRUE; /* by default */
CERT_UnlockCertTempPerm(cc);
/* pointer back */
cc->nssCertificate = c;
CERT_UnlockCertTempPerm(cc);
if (trust) {
/* force the cert type to be recomputed to include trust info */
PRUint32 nsCertType = cert_ComputeCertType(cc);
Expand Down Expand Up @@ -919,7 +919,10 @@ stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate)
nss_SetError(NSS_ERROR_INTERNAL_ERROR);
goto loser;
}
if (!cc->nssCertificate || forceUpdate) {
CERT_LockCertTempPerm(cc);
NSSCertificate *nssCert = cc->nssCertificate;
CERT_UnlockCertTempPerm(cc);
if (!nssCert || forceUpdate) {
fill_CERTCertificateFields(c, cc, forceUpdate);
} else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess) {
CERTCertTrust *trust;
Expand Down Expand Up @@ -1018,7 +1021,9 @@ STAN_GetNSSCertificate(CERTCertificate *cc)
nssCryptokiInstance *instance;
nssPKIObject *pkiob;
NSSArena *arena;
CERT_LockCertTempPerm(cc);
c = cc->nssCertificate;
CERT_UnlockCertTempPerm(cc);
if (c) {
return c;
}
Expand Down Expand Up @@ -1083,7 +1088,9 @@ STAN_GetNSSCertificate(CERTCertificate *cc)
nssPKIObject_AddInstance(&c->object, instance);
}
c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc);
CERT_LockCertTempPerm(cc);
cc->nssCertificate = c;
CERT_UnlockCertTempPerm(cc);
return c;
}

Expand Down

0 comments on commit e856c01

Please sign in to comment.