1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_
6 #define CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "base/memory/scoped_refptr.h"
12 #include "base/observer_list.h"
13 #include "base/sequence_checker.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "chrome/browser/win/conflicts/module_info.h"
17 #include "chrome/browser/win/conflicts/module_inspector.h"
18 #include "chrome/browser/win/conflicts/third_party_metrics_recorder.h"
19 #include "content/public/common/process_type.h"
20 
21 class ModuleDatabaseObserver;
22 
23 namespace base {
24 class FilePath;
25 class SequencedTaskRunner;
26 }  // namespace base
27 
28 #if defined(GOOGLE_CHROME_BUILD)
29 class ModuleLoadAttemptLogListener;
30 class PrefChangeRegistrar;
31 class PrefRegistrySimple;
32 class ThirdPartyConflictsManager;
33 
34 namespace base {
35 struct OnTaskRunnerDeleter;
36 }
37 #endif  // defined(GOOGLE_CHROME_BUILD)
38 
39 // A class that keeps track of all modules loaded across Chrome processes.
40 //
41 // It is also the main class behind third-party modules tracking, and owns the
42 // different classes that required to identify incompatible applications and
43 // record metrics.
44 //
45 // This is effectively a singleton, but doesn't use base::Singleton. The intent
46 // is for the object to be created when Chrome is single-threaded, and for it
47 // be set as the process-wide singleton via SetInstance.
48 class ModuleDatabase : public ModuleDatabaseEventSource {
49  public:
50   // Structures for maintaining information about modules.
51   using ModuleMap = std::map<ModuleInfoKey, ModuleInfoData>;
52   using ModuleInfo = ModuleMap::value_type;
53 
54   // The Module Database becomes idle after this timeout expires without any
55   // module events.
56   static constexpr base::TimeDelta kIdleTimeout =
57       base::TimeDelta::FromSeconds(10);
58 
59   // Creates the ModuleDatabase. Must be created and set on the sequence
60   // returned by GetTaskRunner().
61   explicit ModuleDatabase(bool third_party_blocking_policy_enabled);
62   ~ModuleDatabase() override;
63 
64   // Returns the SequencedTaskRunner on which the ModuleDatabase lives. Can be
65   // called on any thread.
66   static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
67 
68   // Retrieves the singleton global instance of the ModuleDatabase. Must only be
69   // called on the sequence returned by GetTaskRunner().
70   static ModuleDatabase* GetInstance();
71 
72   // Sets the global instance of the ModuleDatabase. Ownership is passed to the
73   // global instance and deliberately leaked, unless manually cleaned up. This
74   // has no locking and should be called when Chrome is single threaded.
75   static void SetInstance(std::unique_ptr<ModuleDatabase> module_database);
76 
77   // Initializes the ModuleLoadAttemptLogListener instance. This function is a
78   // noop on non-GOOGLE_CHROME_BUILD configurations because it is used only for
79   // third-party software blocking, which is only enabled in Google Chrome
80   // builds.
81   void StartDrainingModuleLoadAttemptsLog();
82 
83   // Returns true if the ModuleDatabase is idle. This means that no modules are
84   // currently being inspected, and no new module events have been observed in
85   // the last 10 seconds.
86   bool IsIdle();
87 
88   // Indicates that a new registered shell extension was found.
89   void OnShellExtensionEnumerated(const base::FilePath& path,
90                                   uint32_t size_of_image,
91                                   uint32_t time_date_stamp);
92 
93   // Indicates that all shell extensions have been enumerated.
94   void OnShellExtensionEnumerationFinished();
95 
96   // Indicates that a new registered input method editor was found.
97   void OnImeEnumerated(const base::FilePath& path,
98                        uint32_t size_of_image,
99                        uint32_t time_date_stamp);
100 
101   // Indicates that all input method editors have been enumerated.
102   void OnImeEnumerationFinished();
103 
104   // Indicates that a module has been loaded. The data passed to this function
105   // is taken as gospel, so if it originates from a remote process it should be
106   // independently validated first. (In practice, see ModuleEventSinkImpl for
107   // details of where this happens.)
108   void OnModuleLoad(content::ProcessType process_type,
109                     const base::FilePath& module_path,
110                     uint32_t module_size,
111                     uint32_t module_time_date_stamp);
112 
113   // Forwards the module load event to the ModuleDatabase global instance via
114   // OnModuleLoad() on the ModuleDatabase task runner. Can be called on any
115   // threads. Provided for convenience.
116   static void HandleModuleLoadEvent(content::ProcessType process_type,
117                                     const base::FilePath& module_path,
118                                     uint32_t module_size,
119                                     uint32_t module_time_date_stamp);
120 
121   void OnModuleBlocked(const base::FilePath& module_path,
122                        uint32_t module_size,
123                        uint32_t module_time_date_stamp);
124 
125   // Marks the module as added to the module blacklist cache, which means it
126   // will be blocked on the next browser launch.
127   void OnModuleAddedToBlacklist(const base::FilePath& module_path,
128                                 uint32_t module_size,
129                                 uint32_t module_time_date_stamp);
130 
131   // TODO(chrisha): Module analysis code, and various accessors for use by
132   // chrome://conflicts.
133 
134   // Adds or removes an observer.
135   // Note that when adding an observer, OnNewModuleFound() will immediately be
136   // called once for all modules that are already loaded before returning to the
137   // caller. In addition, if the ModuleDatabase is currently idle,
138   // OnModuleDatabaseIdle() will also be invoked.
139   //
140   // ModuleDatabaseEventSource:
141   void AddObserver(ModuleDatabaseObserver* observer) override;
142   void RemoveObserver(ModuleDatabaseObserver* observer) override;
143 
144   // Raises the priority of module inspection tasks to ensure the
145   // ModuleDatabase becomes idle ASAP.
146   void IncreaseInspectionPriority();
147 
148 #if defined(GOOGLE_CHROME_BUILD)
149   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
150 
151   // Returns false if third-party modules blocking is disabled via
152   // administrative policy.
153   static bool IsThirdPartyBlockingPolicyEnabled();
154 
155   // Disables the blocking of third-party modules in the browser process. It is
156   // safe to invoke this function from any thread.
157   // This function is meant to be used only as a workaround for the in-process
158   // printing code that may require that third-party DLLs be successfully
159   // loaded into the process to work correctly.
160   // TODO(pmonette): Remove this workaround when printing is moved to a utility
161   //                 process. See https://crbug.com/892294.
162   static void DisableThirdPartyBlocking();
163 
164   // Destroys the |third_party_conflicts_manager_| instance. Invoked by
165   // the |pref_change_registrar_| when it detects that the policy was disabled.
166   // Note: This is distinct from OnThirdPartyBlockingDisabled(). When the policy
167   //       is disabled, the |third_party_conflicts_manager_| is destroyed as if
168   //       it was never initialized.
169   void OnThirdPartyBlockingPolicyDisabled();
170 
171   // Accessor for the third party conflicts manager.
172   // Returns null if both the tracking of incompatible applications and the
173   // blocking of third-party modules are disabled.
174   // Do not hold a pointer to the manager because it can be destroyed if the
175   // ThirdPartyBlocking policy is later disabled.
third_party_conflicts_manager()176   ThirdPartyConflictsManager* third_party_conflicts_manager() {
177     return third_party_conflicts_manager_.get();
178   }
179 #endif
180 
181  private:
182   friend class TestModuleDatabase;
183   friend class ModuleDatabaseTest;
184   friend class ModuleEventSinkImplTest;
185 
186   ModuleInfo* CreateModuleInfo(const base::FilePath& module_path,
187                                uint32_t module_size,
188                                uint32_t module_time_date_stamp);
189 
190   // Finds or creates a mutable ModuleInfo entry. Returns true if the module
191   // info was created.
192   bool FindOrCreateModuleInfo(const base::FilePath& module_path,
193                               uint32_t module_size,
194                               uint32_t module_time_date_stamp,
195                               ModuleInfo** module_info);
196 
197   // Returns true if the enumeration of the IMEs and the shell extensions is
198   // finished.
199   //
200   // To avoid sending an improperly tagged module to an observer (in case a race
201   // condition happens and the module is loaded before the enumeration is done),
202   // it's important that this function returns true before any calls to
203   // OnNewModuleFound() is made.
204   bool RegisteredModulesEnumerated();
205 
206   // Called when RegisteredModulesEnumerated() becomes true. Notifies the
207   // observers of each already inspected modules and checks if the idle state
208   // should be entered.
209   void OnRegisteredModulesEnumerated();
210 
211   // Callback for ModuleInspector.
212   void OnModuleInspected(const ModuleInfoKey& module_key,
213                          ModuleInspectionResult inspection_result);
214 
215   // If the ModuleDatabase is truly idle, calls EnterIdleState().
216   void OnDelayExpired();
217 
218   // Notifies the observers that ModuleDatabase is now idle.
219   void EnterIdleState();
220 
221   // Notifies the |observer| of already found and inspected modules via
222   // OnNewModuleFound().
223   void NotifyLoadedModules(ModuleDatabaseObserver* observer);
224 
225 #if defined(GOOGLE_CHROME_BUILD)
226   // Called by DisableThirdPartyBlocking() to disable the analysis of loaded
227   // modules.
228   // Note: This is distinct from OnThirdPartyBlockingPolicyDisabled() because
229   //       they have a different effect. OnThirdPartyBlockingDisabled() keeps
230   //       the |third_party_conflicts_manager_| instance alive.
231   // TODO(pmonette): Remove this workaround when printing is moved to a utility
232   //                 process. See https://crbug.com/892294.
233   void OnThirdPartyBlockingDisabled();
234 
235   // Initializes the ThirdPartyConflictsManager, which controls showing warnings
236   // for incompatible applications that inject into Chrome and the blocking of
237   // third-party modules. The manager is only initialized if either or both of
238   // the ThirdPartyModulesBlocking and IncompatibleApplicationsWarning features
239   // are enabled.
240   void MaybeInitializeThirdPartyConflictsManager(
241       bool third_party_blocking_policy_enabled);
242 #endif
243 
244   // A map of all known modules.
245   ModuleMap modules_;
246 
247   base::RetainingOneShotTimer idle_timer_;
248 
249   // Indicates if the ModuleDatabase has started processing module load events.
250   bool has_started_processing_;
251 
252   // Indicates if all shell extensions have been enumerated.
253   bool shell_extensions_enumerated_;
254 
255   // Indicates if all input method editors have been enumerated.
256   bool ime_enumerated_;
257 
258 #if defined(GOOGLE_CHROME_BUILD)
259   std::unique_ptr<ModuleLoadAttemptLogListener>
260       module_load_attempt_log_listener_;
261 
262   // Observes the ThirdPartyBlockingEnabled group policy on the UI thread.
263   std::unique_ptr<PrefChangeRegistrar, base::OnTaskRunnerDeleter>
264       pref_change_registrar_;
265 #endif
266 
267   // Inspects new modules on a blocking task runner.
268   ModuleInspector module_inspector_;
269 
270   // Holds observers.
271   base::ObserverList<ModuleDatabaseObserver>::Unchecked observer_list_;
272 
273 #if defined(GOOGLE_CHROME_BUILD)
274   std::unique_ptr<ThirdPartyConflictsManager> third_party_conflicts_manager_;
275 #endif
276 
277   // Records metrics on third-party modules.
278   ThirdPartyMetricsRecorder third_party_metrics_;
279 
280   SEQUENCE_CHECKER(sequence_checker_);
281 
282   DISALLOW_COPY_AND_ASSIGN(ModuleDatabase);
283 };
284 
285 #endif  // CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_
286