[Passwords] Fix a crash in HttpCredentialCleaner

HttpCredentialCleaner tried to use the PrefService in a posted task.
This caused a use-after-free when the DestroyProfileOnBrowserClose
flag was enabled.

Make CredentialsCleanerRunner a KeyedService, so its lifetime (and its
attached HttpCredentialCleaner) is tied to the Profile's lifetime,
letting us avoid the crash by using WeakPtrs.

Bug: 88586, 1141055
Change-Id: I77ebd7daa87257d562c9c12bf63681f16ffc2d10
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2511073
Commit-Queue: Nicolas Ouellet-Payeur <[email protected]>
Reviewed-by: Jan Wilken Dörrie <[email protected]>
Reviewed-by: Ioana Pandele <[email protected]>
Cr-Commit-Position: refs/heads/master@{#826437}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b2e4bb3..4ac8c772 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1059,6 +1059,8 @@
     "password_manager/chrome_biometric_authenticator.h",
     "password_manager/chrome_password_manager_client.cc",
     "password_manager/chrome_password_manager_client.h",
+    "password_manager/credentials_cleaner_runner_factory.cc",
+    "password_manager/credentials_cleaner_runner_factory.h",
     "password_manager/field_info_manager_factory.cc",
     "password_manager/field_info_manager_factory.h",
     "password_manager/password_store_factory.cc",
diff --git a/chrome/browser/password_manager/account_password_store_factory.cc b/chrome/browser/password_manager/account_password_store_factory.cc
index b6b58fb2..5fcf69b 100644
--- a/chrome/browser/password_manager/account_password_store_factory.cc
+++ b/chrome/browser/password_manager/account_password_store_factory.cc
@@ -13,6 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/password_manager/credentials_cleaner_runner_factory.h"
+#include "chrome/browser/password_manager/password_store_utils.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -202,8 +204,10 @@
             ->GetNetworkContext();
       },
       profile);
-  password_manager_util::RemoveUselessCredentials(ps, profile->GetPrefs(), 60,
-                                                  network_context_getter);
+  password_manager_util::RemoveUselessCredentials(
+      CredentialsCleanerRunnerFactory::GetForProfile(profile), ps,
+      profile->GetPrefs(), base::TimeDelta::FromSeconds(60),
+      network_context_getter);
 
 #if !defined(OS_ANDROID)
   ps->SetUnsyncedCredentialsDeletionNotifier(
diff --git a/chrome/browser/password_manager/credentials_cleaner_runner_factory.cc b/chrome/browser/password_manager/credentials_cleaner_runner_factory.cc
new file mode 100644
index 0000000..40641a9f
--- /dev/null
+++ b/chrome/browser/password_manager/credentials_cleaner_runner_factory.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/credentials_cleaner_runner_factory.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/password_manager/core/browser/credentials_cleaner_runner.h"
+#include "content/public/browser/browser_context.h"
+
+CredentialsCleanerRunnerFactory::CredentialsCleanerRunnerFactory()
+    : BrowserContextKeyedServiceFactory(
+          "CredentialsCleanerRunner",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+CredentialsCleanerRunnerFactory::~CredentialsCleanerRunnerFactory() = default;
+
+CredentialsCleanerRunnerFactory*
+CredentialsCleanerRunnerFactory::GetInstance() {
+  static base::NoDestructor<CredentialsCleanerRunnerFactory> instance;
+  return instance.get();
+}
+
+password_manager::CredentialsCleanerRunner*
+CredentialsCleanerRunnerFactory::GetForProfile(Profile* profile) {
+  return static_cast<password_manager::CredentialsCleanerRunner*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+KeyedService* CredentialsCleanerRunnerFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new password_manager::CredentialsCleanerRunner();
+}
diff --git a/chrome/browser/password_manager/credentials_cleaner_runner_factory.h b/chrome/browser/password_manager/credentials_cleaner_runner_factory.h
new file mode 100644
index 0000000..8f4a1e4
--- /dev/null
+++ b/chrome/browser/password_manager/credentials_cleaner_runner_factory.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_CREDENTIALS_CLEANER_RUNNER_FACTORY_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_CREDENTIALS_CLEANER_RUNNER_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace password_manager {
+class CredentialsCleanerRunner;
+}  // namespace password_manager
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+class Profile;
+
+// Creates instances of CredentialsCleanerRunner per Profile.
+class CredentialsCleanerRunnerFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static CredentialsCleanerRunnerFactory* GetInstance();
+  static password_manager::CredentialsCleanerRunner* GetForProfile(
+      Profile* profile);
+
+ private:
+  friend class base::NoDestructor<CredentialsCleanerRunnerFactory>;
+
+  CredentialsCleanerRunnerFactory();
+  ~CredentialsCleanerRunnerFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_CREDENTIALS_CLEANER_RUNNER_FACTORY_H_
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 7a9f696..c44781ca 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/password_manager/credentials_cleaner_runner_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -164,8 +165,10 @@
             ->GetNetworkContext();
       },
       profile);
-  password_manager_util::RemoveUselessCredentials(ps, profile->GetPrefs(), 60,
-                                                  network_context_getter);
+  password_manager_util::RemoveUselessCredentials(
+      CredentialsCleanerRunnerFactory::GetForProfile(profile), ps,
+      profile->GetPrefs(), base::TimeDelta::FromSeconds(60),
+      network_context_getter);
 
 #if defined(OS_WIN) || defined(OS_MAC) || \
     (defined(OS_LINUX) && !defined(OS_CHROMEOS))