Bug 1915008 - leak mResultTask if dispatch fails in certificate verification r=jschanck

Differential Revision: https://phabricator.services.mozilla.com/D221381
This commit is contained in:
Dana Keeler
2024-09-09 20:55:21 +00:00
parent b6a880c1f7
commit c554bb14cd
4 changed files with 67 additions and 50 deletions

View File

@@ -741,17 +741,15 @@ SSLServerCertVerificationJob::Run() {
// Runs on a cert verification thread and only on parent process.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_LOG(
gPIPNSSLog, LogLevel::Debug,
("[%" PRIx64 "] SSLServerCertVerificationJob::Run\n", mAddrForLogging));
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%" PRIx64 "] SSLServerCertVerificationJob::Run", mAddrForLogging));
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
if (!certVerifier) {
PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
// We can't release this off the STS thread because some parts of it
// are not threadsafe. Just leak the mResultTask
// are not threadsafe. Just leak mResultTask.
Unused << mResultTask.forget();
return NS_OK;
return NS_ERROR_FAILURE;
}
TimeStamp jobStartTime = TimeStamp::Now();
@@ -761,7 +759,7 @@ SSLServerCertVerificationJob::Run() {
bool madeOCSPRequests = false;
nsTArray<nsTArray<uint8_t>> builtChainBytesArray;
nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
Result rv = AuthCertificate(
Result result = AuthCertificate(
*certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName,
mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo,
mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus,
@@ -769,25 +767,30 @@ SSLServerCertVerificationJob::Run() {
madeOCSPRequests);
TimeDuration elapsed = TimeStamp::Now() - jobStartTime;
if (rv == Success) {
if (result == Success) {
mozilla::glean::cert_verification_time::success.AccumulateRawDuration(
elapsed);
Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
mResultTask->Dispatch(
nsresult rv = mResultTask->Dispatch(
std::move(builtChainBytesArray), std::move(mPeerCertChain),
TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
certificateTransparencyInfo),
evStatus, true, 0,
nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET,
isCertChainRootBuiltInRoot, mProviderFlags, madeOCSPRequests);
return NS_OK;
if (NS_FAILED(rv)) {
// We can't release this off the STS thread because some parts of it
// are not threadsafe. Just leak mResultTask.
Unused << mResultTask.forget();
}
return rv;
}
mozilla::glean::cert_verification_time::failure.AccumulateRawDuration(
elapsed);
PRErrorCode error = MapResultToPRErrorCode(rv);
PRErrorCode error = MapResultToPRErrorCode(result);
nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory =
nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
@@ -796,16 +799,22 @@ SSLServerCertVerificationJob::Run() {
overridableErrorCategory);
// NB: finalError may be 0 here, in which the connection will continue.
mResultTask->Dispatch(
nsresult rv = mResultTask->Dispatch(
std::move(builtChainBytesArray), std::move(mPeerCertChain),
nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE,
EVStatus::NotEV, false, finalError, overridableErrorCategory,
// If the certificate verifier returned Result::ERROR_BAD_CERT_DOMAIN, a
// chain was built, so isCertChainRootBuiltInRoot is valid and
// potentially useful. Otherwise, assume no chain was built.
rv == Result::ERROR_BAD_CERT_DOMAIN ? isCertChainRootBuiltInRoot : false,
result == Result::ERROR_BAD_CERT_DOMAIN ? isCertChainRootBuiltInRoot
: false,
mProviderFlags, madeOCSPRequests);
return NS_OK;
if (NS_FAILED(rv)) {
// We can't release this off the STS thread because some parts of it
// are not threadsafe. Just leak mResultTask.
Unused << mResultTask.forget();
}
return rv;
}
// Takes information needed for cert verification, does some consistency
@@ -1029,7 +1038,7 @@ SSLServerCertVerificationResult::SSLServerCertVerificationResult(
nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET),
mProviderFlags(0) {}
void SSLServerCertVerificationResult::Dispatch(
nsresult SSLServerCertVerificationResult::Dispatch(
nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
@@ -1075,11 +1084,12 @@ void SSLServerCertVerificationResult::Dispatch(
if (!stsTarget) {
// This has to be released on STS; just leak it
Unused << mSocketControl.forget();
return;
return NS_ERROR_FAILURE;
}
rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to dispatch SSLServerCertVerificationResult");
return rv;
}
NS_IMETHODIMP

View File

@@ -44,15 +44,15 @@ class BaseSSLServerCertVerificationResult {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void Dispatch(nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus,
EVStatus aEVStatus, bool aSucceeded,
PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot,
uint32_t aProviderFlags, bool aMadeOCSPRequests) = 0;
[[nodiscard]] virtual nsresult Dispatch(
nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
bool aSucceeded, PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
bool aMadeOCSPRequests) = 0;
};
// Dispatched to the STS thread to notify the infoObject of the verification
@@ -70,14 +70,15 @@ class SSLServerCertVerificationResult final
explicit SSLServerCertVerificationResult(CommonSocketControl* socketControl);
void Dispatch(nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
bool aSucceeded, PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
bool aMadeOCSPRequests) override;
[[nodiscard]] nsresult Dispatch(
nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
bool aSucceeded, PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
bool aMadeOCSPRequests) override;
private:
~SSLServerCertVerificationResult() = default;

View File

@@ -46,11 +46,16 @@ ipc::IPCResult VerifySSLServerCertChild::RecvOnVerifySSLServerCertFinished(
certBytesArray.AppendElement(std::move(cert.data()));
}
mResultTask->Dispatch(std::move(certBytesArray), std::move(mPeerCertChain),
aCertTransparencyStatus, aEVStatus, aSucceeded,
aFinalError, aOverridableErrorCategory,
aIsBuiltCertChainRootBuiltInRoot, mProviderFlags,
aMadeOCSPRequests);
nsresult rv = mResultTask->Dispatch(
std::move(certBytesArray), std::move(mPeerCertChain),
aCertTransparencyStatus, aEVStatus, aSucceeded, aFinalError,
aOverridableErrorCategory, aIsBuiltCertChainRootBuiltInRoot,
mProviderFlags, aMadeOCSPRequests);
if (NS_FAILED(rv)) {
// We can't release this off the STS thread because some parts of it are
// not threadsafe. Just leak mResultTask.
Unused << mResultTask.forget();
}
return IPC_OK();
}

View File

@@ -57,14 +57,15 @@ class IPCServerCertVerificationResult final
VerifySSLServerCertParent* aParent)
: mTarget(aTarget), mParent(aParent) {}
void Dispatch(nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
bool aSucceeded, PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
bool aMadeOCSPRequests) override;
[[nodiscard]] nsresult Dispatch(
nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
bool aSucceeded, PRErrorCode aFinalError,
nsITransportSecurityInfo::OverridableErrorCategory
aOverridableErrorCategory,
bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
bool aMadeOCSPRequests) override;
private:
~IPCServerCertVerificationResult() = default;
@@ -73,7 +74,7 @@ class IPCServerCertVerificationResult final
RefPtr<VerifySSLServerCertParent> mParent;
};
void IPCServerCertVerificationResult::Dispatch(
nsresult IPCServerCertVerificationResult::Dispatch(
nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
@@ -89,7 +90,7 @@ void IPCServerCertVerificationResult::Dispatch(
}
}
nsresult nrv = mTarget->Dispatch(
nsresult rv = mTarget->Dispatch(
NS_NewRunnableFunction(
"psm::VerifySSLServerCertParent::OnVerifiedSSLServerCert",
[parent(mParent), builtCertChain{std::move(builtCertChain)},
@@ -102,8 +103,8 @@ void IPCServerCertVerificationResult::Dispatch(
aIsBuiltCertChainRootBuiltInRoot, aMadeOCSPRequests);
}),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(nrv));
Unused << nrv;
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return rv;
}
} // anonymous namespace