Bug 1705360 - "hide" NSS DBs from meddling third party software r=jschanck,bbeurdouche

Some crash reports appear to be indicating that initializing NSS' certificate
and key databases is taking on the order of minutes in some cases, which is
unexpected. One hypothesis is that third-party software is opening these DBs at
the same time that NSS is operating on them, causing contention and thus
slowness. This patch experimentally (in Nightly only) renames these DBs in the
hopes that third-party software might not recognize them as the DBs it's
looking for, and will thus leave them alone.

Differential Revision: https://phabricator.services.mozilla.com/D126028
This commit is contained in:
Dana Keeler 2021-09-29 21:23:59 +00:00
Родитель 33e8e81aa8
Коммит 9aa0ad981f
6 изменённых файлов: 126 добавлений и 33 удалений

Просмотреть файл

@ -33,6 +33,8 @@ const LINUX = AppConstants.platform == "linux";
const WIN = AppConstants.platform == "win";
const MAC = AppConstants.platform == "macosx";
const kNSSDBPrefix = AppConstants.NIGHTLY_BUILD ? "gecko-no-share-" : "";
const kSharedFontList = SpecialPowers.getBoolPref("gfx.e10s.font-list.shared");
/* This is an object mapping string phases of startup to lists of known cases
@ -357,14 +359,20 @@ const startupPhases = {
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:cert9.db",
condition: WIN,
read: 5,
stat: 4,
path: `ProfD:cert9.db`,
condition: WIN && AppConstants.NIGHTLY_BUILD,
stat: 1,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:cert9.db",
path: `ProfD:${kNSSDBPrefix}cert9.db`,
condition: WIN,
read: 5,
stat: AppConstants.NIGHTLY_BUILD ? 5 : 4,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: `ProfD:${kNSSDBPrefix}cert9.db`,
condition: WIN,
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
canonicalize: true,
@ -372,14 +380,14 @@ const startupPhases = {
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:cert9.db-journal",
path: `ProfD:${kNSSDBPrefix}cert9.db-journal`,
condition: WIN,
canonicalize: true,
stat: 3,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:cert9.db-wal",
path: `ProfD:${kNSSDBPrefix}cert9.db-wal`,
condition: WIN,
canonicalize: true,
stat: 3,
@ -392,14 +400,20 @@ const startupPhases = {
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:key4.db",
condition: WIN,
read: 8,
stat: 4,
path: `ProfD:key4.db`,
condition: WIN && AppConstants.NIGHTLY_BUILD,
stat: 1,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:key4.db",
path: `ProfD:${kNSSDBPrefix}key4.db`,
condition: WIN,
read: 8,
stat: AppConstants.NIGHTLY_BUILD ? 5 : 4,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: `ProfD:${kNSSDBPrefix}key4.db`,
condition: WIN,
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
canonicalize: true,
@ -407,14 +421,14 @@ const startupPhases = {
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:key4.db-journal",
path: `ProfD:${kNSSDBPrefix}key4.db-journal`,
condition: WIN,
canonicalize: true,
stat: 5,
},
{
// bug 1370516 - NSS should be initialized off main thread.
path: "ProfD:key4.db-wal",
path: `ProfD:${kNSSDBPrefix}key4.db-wal`,
condition: WIN,
canonicalize: true,
stat: 5,
@ -527,13 +541,13 @@ const startupPhases = {
write: 1300,
},
{
path: "ProfD:key4.db-journal",
path: `ProfD:${kNSSDBPrefix}key4.db-journal`,
condition: WIN,
canonicalize: true,
stat: 2,
},
{
path: "ProfD:key4.db-wal",
path: `ProfD:${kNSSDBPrefix}key4.db-wal`,
condition: WIN,
canonicalize: true,
stat: 2,

Просмотреть файл

@ -171,6 +171,7 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(
"logins.json",
"key3.db",
"key4.db",
"gecko-no-share-key4.db",
]);
let formData = getFileResource(types.FORMDATA, [
"formhistory.sqlite",

Просмотреть файл

@ -1548,7 +1548,8 @@ void NSSCertDBTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension extension,
}
SECStatus InitializeNSS(const nsACString& dir, NSSDBConfig nssDbConfig,
PKCS11DBConfig pkcs11DbConfig) {
PKCS11DBConfig pkcs11DbConfig,
const char* nssDBPrefix) {
MOZ_ASSERT(NS_IsMainThread());
// The NSS_INIT_NOROOTINIT flag turns off the loading of the root certs
@ -1568,8 +1569,8 @@ SECStatus InitializeNSS(const nsACString& dir, NSSDBConfig nssDbConfig,
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("InitializeNSS(%s, %d, %d)", dbTypeAndDirectory.get(),
(int)nssDbConfig, (int)pkcs11DbConfig));
SECStatus srv =
NSS_Initialize(dbTypeAndDirectory.get(), "", "", SECMOD_DB, flags);
SECStatus srv = NSS_Initialize(dbTypeAndDirectory.get(), nssDBPrefix,
nssDBPrefix, SECMOD_DB, flags);
if (srv != SECSuccess) {
return srv;
}

Просмотреть файл

@ -49,7 +49,7 @@ enum class NetscapeStepUpPolicy : uint32_t {
};
SECStatus InitializeNSS(const nsACString& dir, NSSDBConfig nssDbConfig,
PKCS11DBConfig pkcs11DbConfig);
PKCS11DBConfig pkcs11DbConfig, const char* nssDBPrefix);
void DisableMD5();

Просмотреть файл

@ -1757,7 +1757,8 @@ static nsresult AttemptToRenamePKCS11ModuleDB(const nsACString& profilePath) {
// there anyway.
// |profilePath| is encoded in UTF-8.
static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
bool nocertdb, bool safeMode) {
bool nocertdb, bool safeMode,
const char* nssDBPrefix) {
if (nocertdb || profilePath.IsEmpty()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
@ -1778,7 +1779,7 @@ static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
PKCS11DBConfig safeModeDBConfig =
safeMode ? PKCS11DBConfig::DoNotLoadModules : PKCS11DBConfig::LoadModules;
SECStatus srv = ::mozilla::psm::InitializeNSS(
profilePath, NSSDBConfig::ReadWrite, safeModeDBConfig);
profilePath, NSSDBConfig::ReadWrite, safeModeDBConfig, nssDBPrefix);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
return NS_OK;
@ -1789,7 +1790,7 @@ static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
#endif // ifndef ANDROID
// That failed. Try read-only mode.
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadOnly,
safeModeDBConfig);
safeModeDBConfig, nssDBPrefix);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r-o mode"));
return NS_OK;
@ -1817,7 +1818,8 @@ static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
// flags causes NSS initialization to fail, so unfortunately we have to use
// read-write mode.
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadWrite,
PKCS11DBConfig::DoNotLoadModules);
PKCS11DBConfig::DoNotLoadModules,
nssDBPrefix);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("FIPS may be the problem"));
// Unload NSS so we can attempt to fix this situation for the user.
@ -1844,13 +1846,15 @@ static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
return rv;
}
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadWrite,
PKCS11DBConfig::LoadModules);
PKCS11DBConfig::LoadModules,
nssDBPrefix);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode"));
return NS_OK;
}
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadOnly,
PKCS11DBConfig::LoadModules);
PKCS11DBConfig::LoadModules,
nssDBPrefix);
if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode"));
return NS_OK;
@ -1870,6 +1874,60 @@ static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath,
return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
}
#ifdef NIGHTLY_BUILD
const char* sGeckoNSSDBPrefix = "gecko-no-share-";
#else
const char* sGeckoNSSDBPrefix = "";
#endif
#ifdef NIGHTLY_BUILD
// dbType is either "cert9.db" or "key4.db"
void MigrateOneCertDB(const nsCOMPtr<nsIFile>& profileDirectory,
const nsACString& dbType) {
nsCOMPtr<nsIFile> newDBFile;
nsresult rv = profileDirectory->Clone(getter_AddRefs(newDBFile));
if (NS_FAILED(rv)) {
return;
}
nsAutoCString newDBFilename(sGeckoNSSDBPrefix);
newDBFilename.Append(dbType);
rv = newDBFile->AppendNative(newDBFilename);
if (NS_FAILED(rv)) {
return;
}
bool exists;
rv = newDBFile->Exists(&exists);
if (NS_FAILED(rv)) {
return;
}
// If the prefixed DB already exists, don't overwrite it.
if (exists) {
return;
}
nsCOMPtr<nsIFile> oldDBFile;
rv = profileDirectory->Clone(getter_AddRefs(oldDBFile));
if (NS_FAILED(rv)) {
return;
}
rv = oldDBFile->AppendNative(dbType);
if (NS_FAILED(rv)) {
return;
}
Unused << oldDBFile->MoveToNative(nullptr, newDBFilename);
}
void MigrateToPrefixedCertDBs() {
nsCOMPtr<nsIFile> profileDirectory;
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDirectory));
if (NS_FAILED(rv)) {
return;
}
MigrateOneCertDB(profileDirectory, "cert9.db"_ns);
MigrateOneCertDB(profileDirectory, "key4.db"_ns);
}
#endif // NIGHTLY_BUILD
nsresult nsNSSComponent::InitializeNSS() {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::InitializeNSS\n"));
AUTO_PROFILER_LABEL("nsNSSComponent::InitializeNSS", OTHER);
@ -1891,6 +1949,12 @@ nsresult nsNSSComponent::InitializeNSS() {
return NS_ERROR_NOT_AVAILABLE;
}
#ifdef NIGHTLY_BUILD
if (!profileStr.IsEmpty()) {
MigrateToPrefixedCertDBs();
}
#endif
#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
SetNSSDatabaseCacheModeAsAppropriate();
#endif
@ -1910,7 +1974,8 @@ nsresult nsNSSComponent::InitializeNSS() {
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("inSafeMode: %u\n", inSafeMode));
rv = InitializeNSSWithFallbacks(profileStr, nocertdb, inSafeMode);
rv = InitializeNSSWithFallbacks(profileStr, nocertdb, inSafeMode,
sGeckoNSSDBPrefix);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to initialize NSS"));

Просмотреть файл

@ -10,13 +10,25 @@
function run_test() {
let profileDir = do_get_profile();
let certificateDBFile = profileDir.clone();
certificateDBFile.append("cert9.db");
ok(!certificateDBFile.exists(), "cert9.db should not exist beforehand");
let certificateDBName = AppConstants.NIGHTLY_BUILD
? "gecko-no-share-cert9.db"
: "cert9.db";
certificateDBFile.append(certificateDBName);
ok(
!certificateDBFile.exists(),
`${certificateDBName} should not exist beforehand`
);
let keyDBFile = profileDir.clone();
keyDBFile.append("key4.db");
ok(!keyDBFile.exists(), "key4.db should not exist beforehand");
let keyDBName = AppConstants.NIGHTLY_BUILD
? "gecko-no-share-key4.db"
: "key4.db";
keyDBFile.append(keyDBName);
ok(!keyDBFile.exists(), `${keyDBName} should not exist beforehand`);
// This should start PSM.
Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
ok(certificateDBFile.exists(), "cert9.db should exist in the profile");
ok(keyDBFile.exists(), "key4.db should exist in the profile");
ok(
certificateDBFile.exists(),
`${certificateDBName} should exist in the profile`
);
ok(keyDBFile.exists(), `${keyDBName} should exist in the profile`);
}