blob: 7be732ea3b9cf7ac7804593782724040e8e80ad7 [file] [log] [blame]
[email protected]d80268a52011-01-06 08:57:451// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]c1bbaa82010-11-08 11:17:052// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
pmonette23c8fb7e2016-06-27 20:45:115#ifndef CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_
6#define CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_
[email protected]c1bbaa82010-11-08 11:17:057
chrisha8645b5892016-08-30 18:50:268#include <memory>
[email protected]c1bbaa82010-11-08 11:17:059#include <utility>
10#include <vector>
11
chrishacd02dc92016-10-06 20:37:1312#include "base/files/file_path.h"
[email protected]09fe8beb2010-12-16 10:03:0113#include "base/gtest_prod_util.h"
avi6846aef2015-12-26 01:09:3814#include "base/macros.h"
chrisha8645b5892016-08-30 18:50:2615#include "base/observer_list.h"
[email protected]d8830562013-06-10 22:01:5416#include "base/strings/string16.h"
[email protected]41a17c52013-06-28 00:27:5317#include "base/timer/timer.h"
chrisha2b10cfe2017-02-07 03:34:2118#include "chrome/browser/conflicts/module_info_util_win.h"
[email protected]c38831a12011-10-28 12:44:4919#include "content/public/browser/browser_thread.h"
[email protected]761fa4702013-07-02 15:25:1520#include "url/gurl.h"
[email protected]c1bbaa82010-11-08 11:17:0521
22class EnumerateModulesModel;
[email protected]f3a1c642011-07-12 19:15:0323
24namespace base {
[email protected]c1bbaa82010-11-08 11:17:0525class ListValue;
[email protected]f3a1c642011-07-12 19:15:0326}
[email protected]c1bbaa82010-11-08 11:17:0527
chrisha8645b5892016-08-30 18:50:2628// A helper class that implements the enumerate module functionality on the FILE
29// thread. Not to be used directly.
30// TODO(chrisha): Move this to a separate .h and .cc.
31class ModuleEnumerator {
[email protected]c1bbaa82010-11-08 11:17:0532 public:
33 // What type of module we are dealing with. Loaded modules are modules we
34 // detect as loaded in the process at the time of scanning. The others are
35 // modules of interest and may or may not be loaded in the process at the
36 // time of scan.
37 enum ModuleType {
[email protected]c89652892010-11-29 22:19:1838 LOADED_MODULE = 1 << 0,
39 SHELL_EXTENSION = 1 << 1,
40 WINSOCK_MODULE_REGISTRATION = 1 << 2,
[email protected]c1bbaa82010-11-08 11:17:0541 };
42
43 // The blacklist status of the module. Suspected Bad modules have been
44 // partially matched (ie. name matches and location, but not description)
45 // whereas Confirmed Bad modules have been identified further (ie.
46 // AuthentiCode signer matches).
47 enum ModuleStatus {
48 // This is returned by the matching function when comparing against the
49 // blacklist and the module does not match the current entry in the
50 // blacklist.
51 NOT_MATCHED,
52 // The module is not on the blacklist. Assume it is good.
53 GOOD,
54 // Module is a suspected bad module.
55 SUSPECTED_BAD,
56 // Module is a bad bad dog.
57 CONFIRMED_BAD,
58 };
59
60 // A bitmask with the possible resolutions for bad modules.
61 enum RecommendedAction {
62 NONE = 0,
63 INVESTIGATING = 1 << 0,
64 UNINSTALL = 1 << 1,
65 DISABLE = 1 << 2,
66 UPDATE = 1 << 3,
67 SEE_LINK = 1 << 4,
[email protected]d04126a2013-06-06 15:28:3368 NOTIFY_USER = 1 << 5,
69 };
70
[email protected]c1bbaa82010-11-08 11:17:0571 // The structure we populate when enumerating modules.
72 struct Module {
thakis3b7c20e32015-05-08 19:35:0473 Module();
74 Module(const Module& rhs);
chrishacd02dc92016-10-06 20:37:1375 // Constructor exposed for unittesting.
thakis3b7c20e32015-05-08 19:35:0476 Module(ModuleType type,
77 ModuleStatus status,
78 const base::string16& location,
79 const base::string16& name,
80 const base::string16& product_name,
81 const base::string16& description,
82 const base::string16& version,
thakis3b7c20e32015-05-08 19:35:0483 RecommendedAction recommended_action);
84 ~Module();
85
[email protected]c1bbaa82010-11-08 11:17:0586 // The type of module found
87 ModuleType type;
88 // The module status (benign/bad/etc).
89 ModuleStatus status;
90 // The module path, not including filename.
[email protected]439f1e32013-12-09 20:09:0991 base::string16 location;
[email protected]c1bbaa82010-11-08 11:17:0592 // The name of the module (filename).
[email protected]439f1e32013-12-09 20:09:0993 base::string16 name;
[email protected]c1bbaa82010-11-08 11:17:0594 // The name of the product the module belongs to.
[email protected]439f1e32013-12-09 20:09:0995 base::string16 product_name;
[email protected]c1bbaa82010-11-08 11:17:0596 // The module file description.
[email protected]439f1e32013-12-09 20:09:0997 base::string16 description;
[email protected]c1bbaa82010-11-08 11:17:0598 // The module version.
[email protected]439f1e32013-12-09 20:09:0999 base::string16 version;
[email protected]c1bbaa82010-11-08 11:17:05100 // The help tips bitmask.
101 RecommendedAction recommended_action;
[email protected]47db01d2010-11-20 10:00:19102 // The duplicate count within each category of modules.
103 int duplicate_count;
chrishacd02dc92016-10-06 20:37:13104 // The certificate info for the module.
pmonettecfe91abf2017-02-25 00:11:11105 CertificateInfo cert_info;
[email protected]c1bbaa82010-11-08 11:17:05106 };
107
108 // A vector typedef of all modules enumerated.
109 typedef std::vector<Module> ModulesVector;
110
[email protected]c1bbaa82010-11-08 11:17:05111 // A static function that normalizes the module information in the |module|
112 // struct. Module information needs to be normalized before comparing against
113 // the blacklist. This is because the same module can be described in many
114 // different ways, ie. file paths can be presented in long/short name form,
115 // and are not case sensitive on Windows. Also, the version string returned
116 // can include appended text, which we don't want to use during comparison
117 // against the blacklist.
118 static void NormalizeModule(Module* module);
119
chrisha8645b5892016-08-30 18:50:26120 // Constructs a ModuleEnumerator that will notify the provided |observer| once
121 // enumeration is complete. |observer| must outlive the ModuleEnumerator.
[email protected]c1bbaa82010-11-08 11:17:05122 explicit ModuleEnumerator(EnumerateModulesModel* observer);
[email protected]c1bbaa82010-11-08 11:17:05123
chrisha8645b5892016-08-30 18:50:26124 ~ModuleEnumerator();
125
[email protected]c1bbaa82010-11-08 11:17:05126 // Start scanning the loaded module list (if a scan is not already in
chrisha8645b5892016-08-30 18:50:26127 // progress). This function does not block while reading the module list and
128 // will notify when done by calling the DoneScanning method of |observer_|.
129 void ScanNow(ModulesVector* list);
[email protected]c1bbaa82010-11-08 11:17:05130
chrisha6949a31c2016-10-18 21:49:37131 // Sets |per_module_delay_| to zero, causing the modules to be inspected
132 // in realtime.
133 void SetPerModuleDelayToZero();
134
[email protected]c1bbaa82010-11-08 11:17:05135 private:
[email protected]09fe8beb2010-12-16 10:03:01136 FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest, CollapsePath);
137
fdorayd47164072017-02-24 14:32:49138 // This function posts a task to enumerate all modules asynchronously. Once
139 // the list of module filenames is populated, a delayed task is posted to scan
140 // the first module.
chrisha6949a31c2016-10-18 21:49:37141 void ScanImplStart();
[email protected]c1bbaa82010-11-08 11:17:05142
chrisha6949a31c2016-10-18 21:49:37143 // Inspects the module in |enumerated_modules_| at the given |index|. Gets
144 // module information, normalizes it, and collapses the path. This is an
145 // expensive operation and non-critical. Posts a delayed task to ScanImplDelay
146 // for the next module. When all modules are finished forwards directly to
147 // ScanImplFinish.
148 void ScanImplModule(size_t index);
149
150 // Collects metrics and notifies the observer that the enumeration is complete
151 // by invoking DoneScanning on the UI thread.
152 void ScanImplFinish();
153
154 // Enumerate all modules loaded into the Chrome process. Creates empty
155 // entries in |enumerated_modules_| with a populated |location| field.
[email protected]cd60d2c52010-11-19 10:35:36156 void EnumerateLoadedModules();
157
chrisha6949a31c2016-10-18 21:49:37158 // Enumerate all registered Windows shell extensions. Creates empty
159 // entries in |enumerated_modules_| with a populated |location| field.
[email protected]cd60d2c52010-11-19 10:35:36160 void EnumerateShellExtensions();
161
chrisha6949a31c2016-10-18 21:49:37162 // Enumerate all registered Winsock LSP modules. Creates empty
163 // entries in |enumerated_modules_| with a populated |location| field.
[email protected]47db01d2010-11-20 10:00:19164 void EnumerateWinsockModules();
[email protected]cd60d2c52010-11-19 10:35:36165
166 // Reads the registered shell extensions found under |parent| key in the
chrisha6949a31c2016-10-18 21:49:37167 // registry. Creates empty entries in |enumerated_modules_| with a populated
168 // |location| field.
[email protected]cd60d2c52010-11-19 10:35:36169 void ReadShellExtensions(HKEY parent);
170
171 // Given a |module|, initializes the structure and loads additional
172 // information using the location field of the module.
173 void PopulateModuleInformation(Module* module);
174
[email protected]47db01d2010-11-20 10:00:19175 // Checks the module list to see if a |module| of the same type, location
176 // and name has been added before and if so, increments its duplication
177 // counter. If it doesn't appear in the list, it is added.
178 void AddToListWithoutDuplicating(const Module&);
179
[email protected]c1bbaa82010-11-08 11:17:05180 // Builds up a vector of path values mapping to environment variable,
181 // with pairs like [c:\windows\, %systemroot%]. This is later used to
182 // collapse paths like c:\windows\system32 into %systemroot%\system32, which
183 // we can use for comparison against our blacklist (which uses only env vars).
184 // NOTE: The vector will not contain an exhaustive list of environment
185 // variables, only the ones currently found on the blacklist or ones that are
186 // likely to appear there.
187 void PreparePathMappings();
188
chrisha8645b5892016-08-30 18:50:26189 // Reports (via UMA) a handful of high-level metrics regarding third party
chrisha6949a31c2016-10-18 21:49:37190 // modules in this process. Called by ScanImplFinish.
chrisha8645b5892016-08-30 18:50:26191 void ReportThirdPartyMetrics();
192
fdorayd47164072017-02-24 14:32:49193 // The TaskRunner to perform work in the background.
194 const scoped_refptr<base::TaskRunner> background_task_runner_;
195
[email protected]c1bbaa82010-11-08 11:17:05196 // The vector of paths to %env_var%, used to account for differences in
197 // where people keep there files, c:\windows vs. d:\windows, etc.
pmonette61e93402017-03-06 22:48:48198 StringMapping path_mapping_;
[email protected]c1bbaa82010-11-08 11:17:05199
200 // The vector containing all the enumerated modules (loaded and modules of
201 // interest).
202 ModulesVector* enumerated_modules_;
203
chrisha8645b5892016-08-30 18:50:26204 // The observer, which needs to be notified when the scan is complete.
[email protected]c1bbaa82010-11-08 11:17:05205 EnumerateModulesModel* observer_;
206
chrisha6949a31c2016-10-18 21:49:37207 // The delay that is observed between module inspection tasks. This is
208 // currently 1 second, which means it takes several minutes to iterate over
209 // all modules on average.
210 base::TimeDelta per_module_delay_;
211
212 // The amount of time taken for on-disk module inspection. Reported in
213 // ScanImplFinish.
214 base::TimeDelta enumeration_inspection_time_;
215
216 // The total amount of time taken for module enumeration. Reported in
217 // ScanImplFinish.
218 base::TimeDelta enumeration_total_time_;
219
[email protected]c1bbaa82010-11-08 11:17:05220 DISALLOW_COPY_AND_ASSIGN(ModuleEnumerator);
221};
222
223// This is a singleton class that enumerates all modules loaded into Chrome,
224// both currently loaded modules (called DLLs on Windows) and modules 'of
225// interest', such as WinSock LSP modules. This class also marks each module
226// as benign or suspected bad or outright bad, using a supplied blacklist that
227// is currently hard-coded.
228//
229// To use this class, grab the singleton pointer and call ScanNow().
230// Then wait to get notified through MODULE_LIST_ENUMERATED when the list is
231// ready.
232//
chrisha8645b5892016-08-30 18:50:26233// The member functions of this class may only be used from the UI thread. The
fdorayd47164072017-02-24 14:32:49234// bulk of the work is actually performed asynchronously in TaskScheduler with
chrisha210ad102016-09-26 22:08:26235// CONTINUE_ON_SHUTDOWN semantics, as the WinCrypt functions can effectively
236// block arbitrarily during shutdown.
chrisha8645b5892016-08-30 18:50:26237//
238// TODO(chrisha): If this logic is ever extended to other platforms, then make
239// this file generic for all platforms, and remove the precompiler logic in
240// app_menu_icon_controller.*.
[email protected]c1bbaa82010-11-08 11:17:05241class EnumerateModulesModel {
242 public:
[email protected]d04126a2013-06-06 15:28:33243 // UMA histogram constants.
244 enum UmaModuleConflictHistogramOptions {
245 ACTION_BUBBLE_SHOWN = 0,
246 ACTION_BUBBLE_LEARN_MORE,
247 ACTION_MENU_LEARN_MORE,
pmonettecfe91abf2017-02-25 00:11:11248 ACTION_BOUNDARY, // Must be the last value.
[email protected]d04126a2013-06-06 15:28:33249 };
250
chrisha8645b5892016-08-30 18:50:26251 // Observer class used to determine when a scan has completed and when any
252 // associated UI elements have been dismissed.
253 class Observer {
254 public:
255 // Invoked when EnumerateModulesModel has completed a scan of modules.
256 virtual void OnScanCompleted() {}
257
258 // Invoked when a user has acknowledged incompatible modules found in a
259 // module scan.
260 virtual void OnConflictsAcknowledged() {}
261
262 protected:
263 virtual ~Observer() = default;
264 };
265
266 // Returns the singleton instance of this class.
[email protected]8e8bb6d2010-12-13 08:18:55267 static EnumerateModulesModel* GetInstance();
[email protected]c1bbaa82010-11-08 11:17:05268
chrisha8645b5892016-08-30 18:50:26269 // Adds an |observer| to the enumerator. Callbacks will occur on the UI
270 // thread.
271 void AddObserver(Observer* observer);
272
273 // Removes an |observer| from the enumerator.
274 void RemoveObserver(Observer* observer);
275
[email protected]cfc234342011-04-08 12:03:50276 // Returns true if we should show the conflict notification. The conflict
277 // notification is only shown once during the lifetime of the process.
278 bool ShouldShowConflictWarning() const;
279
280 // Called when the user has acknowledged the conflict notification.
281 void AcknowledgeConflictNotification();
282
[email protected]c1bbaa82010-11-08 11:17:05283 // Returns the number of suspected bad modules found in the last scan.
284 // Returns 0 if no scan has taken place yet.
chrisha8645b5892016-08-30 18:50:26285 int suspected_bad_modules_detected() const;
[email protected]c1bbaa82010-11-08 11:17:05286
287 // Returns the number of confirmed bad modules found in the last scan.
288 // Returns 0 if no scan has taken place yet.
chrisha8645b5892016-08-30 18:50:26289 int confirmed_bad_modules_detected() const;
[email protected]c1bbaa82010-11-08 11:17:05290
[email protected]d04126a2013-06-06 15:28:33291 // Returns how many modules to notify the user about.
chrisha8645b5892016-08-30 18:50:26292 int modules_to_notify_about() const;
[email protected]d80268a52011-01-06 08:57:45293
[email protected]d04126a2013-06-06 15:28:33294 // Checks to see if a scanning task should be started and sets one off, if so.
chrisha6949a31c2016-10-18 21:49:37295 // This will cause ScanNow to be invoked in background mode.
[email protected]d04126a2013-06-06 15:28:33296 void MaybePostScanningTask();
297
chrisha6949a31c2016-10-18 21:49:37298 // Asynchronously start the scan for the loaded module list. If
299 // |background_mode| is true the scan will happen slowly over a process of
300 // minutes, spread across dozens or even hundreds of delayed tasks. Otherwise
301 // the processing will occur in a single task.
302 void ScanNow(bool background_mode);
[email protected]c1bbaa82010-11-08 11:17:05303
304 // Gets the whole module list as a ListValue.
jdoerriecb205a52017-06-08 16:16:44305 std::unique_ptr<base::ListValue> GetModuleList();
[email protected]c1bbaa82010-11-08 11:17:05306
chrisha8645b5892016-08-30 18:50:26307 // Returns the site to which the user should be taken when the conflict bubble
308 // or app menu item is clicked. For now this is simply chrome://conflicts,
309 // which contains detailed information about conflicts. Returns an empty URL
310 // if there are no conficts. May only be called on UI thread.
311 GURL GetConflictUrl();
[email protected]d04126a2013-06-06 15:28:33312
[email protected]c1bbaa82010-11-08 11:17:05313 private:
[email protected]c1bbaa82010-11-08 11:17:05314 friend class ModuleEnumerator;
315
chrisha8645b5892016-08-30 18:50:26316 // Private to enforce singleton nature of this class.
[email protected]c1bbaa82010-11-08 11:17:05317 EnumerateModulesModel();
chrisha8645b5892016-08-30 18:50:26318 ~EnumerateModulesModel();
[email protected]c1bbaa82010-11-08 11:17:05319
chrisha8645b5892016-08-30 18:50:26320 // Called on the UI thread when the helper class is done scanning. The
321 // ModuleEnumerator that calls this must not do any work after causing this
322 // function to be called, as the EnumerateModulesModel may delete the
323 // ModuleEnumerator.
[email protected]c1bbaa82010-11-08 11:17:05324 void DoneScanning();
325
[email protected]c1bbaa82010-11-08 11:17:05326 // The vector containing all the modules enumerated. Will be normalized and
fdorayd47164072017-02-24 14:32:49327 // any bad modules will be marked. Written to from the background TaskRunner
328 // by the |module_enumerator_|, read from on the UI thread by this class.
[email protected]c1bbaa82010-11-08 11:17:05329 ModuleEnumerator::ModulesVector enumerated_modules_;
330
fdorayd47164072017-02-24 14:32:49331 // The object responsible for enumerating the modules on a background
332 // TaskRunner. Only accessed from the UI thread.
chrisha8645b5892016-08-30 18:50:26333 std::unique_ptr<ModuleEnumerator> module_enumerator_;
[email protected]c1bbaa82010-11-08 11:17:05334
chrisha8645b5892016-08-30 18:50:26335 // Whether the conflict notification has been acknowledged by the user. Only
336 // modified on the UI thread.
[email protected]cfc234342011-04-08 12:03:50337 bool conflict_notification_acknowledged_;
338
[email protected]c1bbaa82010-11-08 11:17:05339 // The number of confirmed bad modules (not including suspected bad ones)
chrisha8645b5892016-08-30 18:50:26340 // found during last scan. Only modified on the UI thread.
[email protected]c1bbaa82010-11-08 11:17:05341 int confirmed_bad_modules_detected_;
342
[email protected]d04126a2013-06-06 15:28:33343 // The number of bad modules the user needs to be aggressively notified about.
chrisha8645b5892016-08-30 18:50:26344 // Only modified on the UI thread.
[email protected]d04126a2013-06-06 15:28:33345 int modules_to_notify_about_;
346
[email protected]c1bbaa82010-11-08 11:17:05347 // The number of suspected bad modules (not including confirmed bad ones)
chrisha8645b5892016-08-30 18:50:26348 // found during last scan. Only modified on the UI thread.
[email protected]c1bbaa82010-11-08 11:17:05349 int suspected_bad_modules_detected_;
350
chrisha8645b5892016-08-30 18:50:26351 base::ObserverList<Observer> observers_;
352
[email protected]c1bbaa82010-11-08 11:17:05353 DISALLOW_COPY_AND_ASSIGN(EnumerateModulesModel);
354};
355
pmonette23c8fb7e2016-06-27 20:45:11356#endif // CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_