// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WIN_CONFLICTS_INCOMPATIBLE_APPLICATIONS_UPDATER_H_
#define CHROME_BROWSER_WIN_CONFLICTS_INCOMPATIBLE_APPLICATIONS_UPDATER_H_
#include <memory>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "chrome/browser/win/conflicts/installed_applications.h"
#include "chrome/browser/win/conflicts/module_database_observer.h"
#include "chrome/browser/win/conflicts/proto/module_list.pb.h"
class ModuleListFilter;
class PrefRegistrySimple;
struct CertificateInfo;
// Maintains a list of incompatible applications that are installed on the
// machine. These applications cause unwanted DLLs to be loaded into Chrome.
//
// Because the list is expensive to build, it is cached into the Local State
// file so that it is available at startup.
class IncompatibleApplicationsUpdater : public ModuleDatabaseObserver {
public:
// The decision that explains why a particular module caused an
// incompatibility warning or not.
//
// Note that this enum is very similar to the ModuleBlockingDecision in
// ModuleBlocklistCacheUpdater. This is done so that it is easier to keep the
// 2 features separate, as they can be independently enabled/disabled.
enum ModuleWarningDecision {
// No decision was taken yet for the module.
kUnknown = 0,
// A shell extension or IME that is not loaded in the process yet.
kNotLoaded,
// A module that is loaded into a process type where third-party modules are
// explicitly allowed.
kAllowedInProcessType,
// Input method editors are allowed.
kAllowedIME,
// Shell extensions are unwanted, but does not cause trigger a warning.
kAllowedShellExtension,
// Allowed because the certificate's subject of the module matches the
// certificate's subject of the executable. The certificate is not
// validated.
kAllowedSameCertificate,
// Allowed because the path of the executable is the parent of the path of
// the module.
kAllowedSameDirectory,
// Allowed because it is signed by Microsoft. The certificate is not
// validated.
kAllowedMicrosoft,
// Explicitly allowlisted by the Module List component.
kAllowedAllowlisted,
// Module analysis was interrupted using DisableModuleAnalysis(). No warning
// will be emitted for that module.
kNotAnalyzed,
// This module is already going to be blocked on next browser launch, so
// don't warn about it.
kAddedToBlocklist,
// Unwanted, but can't tie back to an installed application.
kNoTiedApplication,
// An incompatibility warning will be shown because of this module.
kIncompatible,
};
struct IncompatibleApplication {
IncompatibleApplication(
InstalledApplications::ApplicationInfo info,
std::unique_ptr<chrome::conflicts::BlocklistAction> blocklist_action);
~IncompatibleApplication();
// Needed for std::remove_if().
IncompatibleApplication(IncompatibleApplication&& incompatible_application);
IncompatibleApplication& operator=(
IncompatibleApplication&& incompatible_application);
InstalledApplications::ApplicationInfo info;
std::unique_ptr<chrome::conflicts::BlocklistAction> blocklist_action;
};
// Creates an instance of the updater.
// The parameters must outlive the lifetime of this class.
IncompatibleApplicationsUpdater(
ModuleDatabaseEventSource* module_database_event_source,
const CertificateInfo& exe_certificate_info,
scoped_refptr<ModuleListFilter> module_list_filter,
const InstalledApplications& installed_applications,
bool module_analysis_disabled);
IncompatibleApplicationsUpdater(const IncompatibleApplicationsUpdater&) =
delete;
IncompatibleApplicationsUpdater& operator=(
const IncompatibleApplicationsUpdater&) = delete;
~IncompatibleApplicationsUpdater() override;
static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
// Returns true if the tracking of incompatible applications is enabled. Can
// be called on any thread. Notably does not check the
// ThirdPartyBlockingEnabled group policy.
static bool IsWarningEnabled();
// Returns true if the cache contains at least one incompatible application.
// Only call this if IsIncompatibleApplicationsWarningEnabled() returns true.
static bool HasCachedApplications();
// Returns all the cached incompatible applications.
// Only call this if IsIncompatibleApplicationsWarningEnabled() returns true.
static std::vector<IncompatibleApplication> GetCachedApplications();
// ModuleDatabaseObserver:
void OnNewModuleFound(const ModuleInfoKey& module_key,
const ModuleInfoData& module_data) override;
void OnKnownModuleLoaded(const ModuleInfoKey& module_key,
const ModuleInfoData& module_data) override;
void OnModuleDatabaseIdle() override;
// Returns the warning decision for a module.
ModuleWarningDecision GetModuleWarningDecision(
const ModuleInfoKey& module_key) const;
// Disables the analysis of newly found modules. This is a one way switch that
// will apply until Chrome is restarted.
void DisableModuleAnalysis();
private:
const raw_ptr<ModuleDatabaseEventSource> module_database_event_source_;
const raw_ref<const CertificateInfo> exe_certificate_info_;
scoped_refptr<ModuleListFilter> module_list_filter_;
const raw_ref<const InstalledApplications> installed_applications_;
// Temporarily holds incompatible applications that were recently found.
std::vector<IncompatibleApplication> incompatible_applications_;
// Becomes false on the first call to OnModuleDatabaseIdle.
bool before_first_idle_ = true;
// Holds the warning decision for all known modules.
base::flat_map<ModuleInfoKey, ModuleWarningDecision>
module_warning_decisions_;
// Indicates if the analysis of newly found modules is disabled. Used as a
// workaround for https://crbug.com/892294.
bool module_analysis_disabled_;
SEQUENCE_CHECKER(sequence_checker_);
};
#endif // CHROME_BROWSER_WIN_CONFLICTS_INCOMPATIBLE_APPLICATIONS_UPDATER_H_