bug 1496736 - check if we actually have a new key DB before removing the old one r=jcj
authorDana Keeler <dkeeler@mozilla.com>
Mon, 22 Oct 2018 19:52:10 +0000
changeset 490824 2d51f2e8955bb87cedf26a3c6d474735d31757cd
parent 490823 0289f2a3bdab2c2b12bd6bc3998bfc4db109a0fd
child 490825 bb628db881452e7a667b1961af9eef2fcb5b4fd2
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjcj
bugs1496736, 1475775
milestone65.0a1
bug 1496736 - check if we actually have a new key DB before removing the old one r=jcj In bug 1475775, we added code to remove the old NSS key DB if the user has set a password on the grounds that the old DB could potentially be unencrypted and contain secrets. However, we did so with the assumption that we were using the new DB, which is not necessarily true when the system has been configured to always use the old DB, as with some RedHat products. This patch checks for the existence of the new DB before proceeding with deleting the old DB. Technically this isn't sufficient, because the new DB could be present even if we're not using it. However, we've already gone far into "this configuration isn't supported" territory. Differential Revision: https://phabricator.services.mozilla.com/D9318
security/manager/ssl/nsNSSComponent.cpp
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1679,16 +1679,50 @@ AttemptToRenameBothPKCS11ModuleDBVersion
   nsresult rv = AttemptToRenamePKCS11ModuleDB(profilePath,
                                               legacyModuleDBFilename);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return AttemptToRenamePKCS11ModuleDB(profilePath, sqlModuleDBFilename);
 }
 
+// Helper function to take a path and a file name and create a handle for the
+// file in that location, if it exists.
+static nsresult
+GetFileIfExists(const nsACString& path, const nsACString& filename,
+                /* out */ nsIFile** result)
+{
+  MOZ_ASSERT(result);
+  if (!result) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  *result = nullptr;
+  nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
+  if (!file) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = file->InitWithNativePath(path);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = file->AppendNative(filename);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  bool exists;
+  rv = file->Exists(&exists);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (exists) {
+    file.forget(result);
+  }
+  return NS_OK;
+}
+
 // When we changed from the old dbm database format to the newer sqlite
 // implementation, the upgrade process left behind the existing files. Suppose a
 // user had not set a password for the old key3.db (which is about 99% of
 // users). After upgrading, both the old database and the new database are
 // unprotected. If the user then sets a password for the new database, the old
 // one will not be protected. In this scenario, we should probably just remove
 // the old database (it would only be relevant if the user downgraded to a
 // version of Firefox before 58, but we have to trade this off against the
@@ -1706,32 +1740,42 @@ MaybeCleanUpOldNSSFiles(const nsACString
   // Unfortunately we can't now tell the difference between "there already was a
   // password when the upgrade happened" and "there was not a password but then
   // the user added one after upgrading".
   bool hasPassword = PK11_NeedLogin(slot.get()) &&
                      !PK11_NeedUserInit(slot.get());
   if (!hasPassword) {
     return;
   }
-  nsCOMPtr<nsIFile> dbFile = do_CreateInstance("@mozilla.org/file/local;1");
-  if (!dbFile) {
-    return;
-  }
-  nsresult rv = dbFile->InitWithNativePath(profilePath);
+  NS_NAMED_LITERAL_CSTRING(newKeyDBFilename, "key4.db");
+  nsCOMPtr<nsIFile> newDBFile;
+  nsresult rv = GetFileIfExists(profilePath, newKeyDBFilename,
+                                getter_AddRefs(newDBFile));
   if (NS_FAILED(rv)) {
     return;
   }
-  NS_NAMED_LITERAL_CSTRING(keyDBFilename, "key3.db");
-  rv = dbFile->AppendNative(keyDBFilename);
+  // If the new key DB file doesn't exist, we don't want to remove the old DB
+  // file. This can happen if the system is configured to use the old DB format
+  // even though we're a version of Firefox that expects to use the new format.
+  if (!newDBFile) {
+    return;
+  }
+  NS_NAMED_LITERAL_CSTRING(oldKeyDBFilename, "key3.db");
+  nsCOMPtr<nsIFile> oldDBFile;
+  rv = GetFileIfExists(profilePath, oldKeyDBFilename,
+                       getter_AddRefs(oldDBFile));
   if (NS_FAILED(rv)) {
     return;
   }
+  if (!oldDBFile) {
+    return;
+  }
   // Since this isn't a directory, the `recursive` argument to `Remove` is
   // irrelevant.
-  Unused << dbFile->Remove(false);
+  Unused << oldDBFile->Remove(false);
 }
 #endif // ifndef ANDROID
 
 // Given a profile directory, attempt to initialize NSS. If nocertdb is true,
 // (or if we don't have a profile directory) simply initialize NSS in no DB mode
 // and return. Otherwise, first attempt to initialize in read/write mode, and
 // then read-only mode if that fails. If both attempts fail, we may be failing
 // to initialize an NSS DB collection that has FIPS mode enabled. Attempt to