1// Copyright (c) 2011 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_ENUMERATE_MODULES_MODEL_WIN_H_
6#define CHROME_BROWSER_ENUMERATE_MODULES_MODEL_WIN_H_
7#pragma once
8
9#include <utility>
10#include <vector>
11
12#include "base/gtest_prod_util.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/singleton.h"
15#include "base/string16.h"
16#include "base/timer.h"
17#include "content/browser/browser_thread.h"
18#include "googleurl/src/gurl.h"
19
20class EnumerateModulesModel;
21class FilePath;
22class ListValue;
23
24// A helper class that implements the enumerate module functionality on the File
25// thread.
26class ModuleEnumerator : public base::RefCountedThreadSafe<ModuleEnumerator> {
27 public:
28  // What type of module we are dealing with. Loaded modules are modules we
29  // detect as loaded in the process at the time of scanning. The others are
30  // modules of interest and may or may not be loaded in the process at the
31  // time of scan.
32  enum ModuleType {
33    LOADED_MODULE               = 1 << 0,
34    SHELL_EXTENSION             = 1 << 1,
35    WINSOCK_MODULE_REGISTRATION = 1 << 2,
36  };
37
38  // The blacklist status of the module. Suspected Bad modules have been
39  // partially matched (ie. name matches and location, but not description)
40  // whereas Confirmed Bad modules have been identified further (ie.
41  // AuthentiCode signer matches).
42  enum ModuleStatus {
43    // This is returned by the matching function when comparing against the
44    // blacklist and the module does not match the current entry in the
45    // blacklist.
46    NOT_MATCHED,
47    // The module is not on the blacklist. Assume it is good.
48    GOOD,
49    // Module is a suspected bad module.
50    SUSPECTED_BAD,
51    // Module is a bad bad dog.
52    CONFIRMED_BAD,
53  };
54
55  // A bitmask with the possible resolutions for bad modules.
56  enum RecommendedAction {
57    NONE          = 0,
58    INVESTIGATING = 1 << 0,
59    UNINSTALL     = 1 << 1,
60    DISABLE       = 1 << 2,
61    UPDATE        = 1 << 3,
62    SEE_LINK      = 1 << 4,
63  };
64
65  // The structure we populate when enumerating modules.
66  struct Module {
67    // The type of module found
68    ModuleType type;
69    // The module status (benign/bad/etc).
70    ModuleStatus status;
71    // The module path, not including filename.
72    string16 location;
73    // The name of the module (filename).
74    string16 name;
75    // The name of the product the module belongs to.
76    string16 product_name;
77    // The module file description.
78    string16 description;
79    // The module version.
80    string16 version;
81    // The signer of the digital certificate for the module.
82    string16 digital_signer;
83    // The help tips bitmask.
84    RecommendedAction recommended_action;
85    // The duplicate count within each category of modules.
86    int duplicate_count;
87    // Whether this module has been normalized (necessary before checking it
88    // against blacklist).
89    bool normalized;
90  };
91
92  // A vector typedef of all modules enumerated.
93  typedef std::vector<Module> ModulesVector;
94
95  // A structure we populate with the blacklist entries.
96  struct BlacklistEntry {
97    const char* filename;
98    const char* location;
99    const char* desc_or_signer;
100    const char* version_from;  // Version where conflict started.
101    const char* version_to;    // First version that works.
102    RecommendedAction help_tip;
103  };
104
105  // A static function that normalizes the module information in the |module|
106  // struct. Module information needs to be normalized before comparing against
107  // the blacklist. This is because the same module can be described in many
108  // different ways, ie. file paths can be presented in long/short name form,
109  // and are not case sensitive on Windows. Also, the version string returned
110  // can include appended text, which we don't want to use during comparison
111  // against the blacklist.
112  static void NormalizeModule(Module* module);
113
114  // A static function that checks whether |module| has been |blacklisted|.
115  static ModuleStatus Match(const Module& module,
116                            const BlacklistEntry& blacklisted);
117
118  explicit ModuleEnumerator(EnumerateModulesModel* observer);
119  ~ModuleEnumerator();
120
121  // Start scanning the loaded module list (if a scan is not already in
122  // progress). This function does not block while reading the module list
123  // (unless we are in limited_mode, see below), and will notify when done
124  // through the MODULE_LIST_ENUMERATED notification.
125  // The process will also send MODULE_INCOMPATIBILITY_BADGE_CHANGE to let
126  // observers know when it is time to update the wrench menu badge.
127  // When in |limited_mode|, this function will not leverage the File thread
128  // to run asynchronously and will therefore block until scanning is done
129  // (and will also not send out any notifications).
130  void ScanNow(ModulesVector* list, bool limited_mode);
131
132 private:
133  FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest, CollapsePath);
134
135  // The (currently) hard coded blacklist of known bad modules.
136  static const BlacklistEntry kModuleBlacklist[];
137
138  // This function does the actual file scanning work on the FILE thread (or
139  // block the main thread when in limited_mode). It enumerates all loaded
140  // modules in the process and other modules of interest, such as the
141  // registered Winsock LSP modules and stores them in |enumerated_modules_|.
142  // It then normalizes the module info and matches them against a blacklist
143  // of known bad modules. Finally, it calls ReportBack to let the observer
144  // know we are done.
145  void ScanImpl();
146
147  // Enumerate all modules loaded into the Chrome process.
148  void EnumerateLoadedModules();
149
150  // Enumerate all registered Windows shell extensions.
151  void EnumerateShellExtensions();
152
153  // Enumerate all registered Winsock LSP modules.
154  void EnumerateWinsockModules();
155
156  // Reads the registered shell extensions found under |parent| key in the
157  // registry.
158  void ReadShellExtensions(HKEY parent);
159
160  // Given a |module|, initializes the structure and loads additional
161  // information using the location field of the module.
162  void PopulateModuleInformation(Module* module);
163
164  // Checks the module list to see if a |module| of the same type, location
165  // and name has been added before and if so, increments its duplication
166  // counter. If it doesn't appear in the list, it is added.
167  void AddToListWithoutDuplicating(const Module&);
168
169  // Builds up a vector of path values mapping to environment variable,
170  // with pairs like [c:\windows\, %systemroot%]. This is later used to
171  // collapse paths like c:\windows\system32 into %systemroot%\system32, which
172  // we can use for comparison against our blacklist (which uses only env vars).
173  // NOTE: The vector will not contain an exhaustive list of environment
174  // variables, only the ones currently found on the blacklist or ones that are
175  // likely to appear there.
176  void PreparePathMappings();
177
178  // For a given |module|, collapse the path from c:\windows to %systemroot%,
179  // based on the |path_mapping_| vector.
180  void CollapsePath(Module* module);
181
182  // Takes each module in the |enumerated_modules_| vector and matches it
183  // against a fixed blacklist of bad and suspected bad modules.
184  void MatchAgainstBlacklist();
185
186  // This function executes on the UI thread when the scanning and matching
187  // process is done. It notifies the observer.
188  void ReportBack();
189
190  // Given a filename, returns the Subject (who signed it) retrieved from
191  // the digital signature (Authenticode).
192  string16 GetSubjectNameFromDigitalSignature(const FilePath& filename);
193
194  // The typedef for the vector that maps a regular file path to %env_var%.
195  typedef std::vector< std::pair<string16, string16> > PathMapping;
196
197  // The vector of paths to %env_var%, used to account for differences in
198  // where people keep there files, c:\windows vs. d:\windows, etc.
199  PathMapping path_mapping_;
200
201  // The vector containing all the enumerated modules (loaded and modules of
202  // interest).
203  ModulesVector* enumerated_modules_;
204
205  // The observer, who needs to be notified when we are done.
206  EnumerateModulesModel* observer_;
207
208  // See limited_mode below.
209  bool limited_mode_;
210
211  // The thread that we need to call back on to report that we are done.
212  BrowserThread::ID callback_thread_id_;
213
214  DISALLOW_COPY_AND_ASSIGN(ModuleEnumerator);
215};
216
217// This is a singleton class that enumerates all modules loaded into Chrome,
218// both currently loaded modules (called DLLs on Windows) and modules 'of
219// interest', such as WinSock LSP modules. This class also marks each module
220// as benign or suspected bad or outright bad, using a supplied blacklist that
221// is currently hard-coded.
222//
223// To use this class, grab the singleton pointer and call ScanNow().
224// Then wait to get notified through MODULE_LIST_ENUMERATED when the list is
225// ready.
226//
227// This class can be used on the UI thread as it asynchronously offloads the
228// file work over to the FILE thread and reports back to the caller with a
229// notification.
230class EnumerateModulesModel {
231 public:
232  static EnumerateModulesModel* GetInstance();
233
234  // Returns true if we should show the conflict notification. The conflict
235  // notification is only shown once during the lifetime of the process.
236  bool ShouldShowConflictWarning() const;
237
238  // Called when the user has acknowledged the conflict notification.
239  void AcknowledgeConflictNotification();
240
241  // Returns the number of suspected bad modules found in the last scan.
242  // Returns 0 if no scan has taken place yet.
243  int suspected_bad_modules_detected() const {
244    return suspected_bad_modules_detected_;
245  }
246
247  // Returns the number of confirmed bad modules found in the last scan.
248  // Returns 0 if no scan has taken place yet.
249  int confirmed_bad_modules_detected() const {
250    return confirmed_bad_modules_detected_;
251  }
252
253  // Set to true when we the scanning process can not rely on certain Chrome
254  // services to exists.
255  void set_limited_mode(bool limited_mode) {
256    limited_mode_ = limited_mode;
257  }
258
259  // Asynchronously start the scan for the loaded module list, except when in
260  // limited_mode (in which case it blocks).
261  void ScanNow();
262
263  // Gets the whole module list as a ListValue.
264  ListValue* GetModuleList() const;
265
266 private:
267  friend struct DefaultSingletonTraits<EnumerateModulesModel>;
268  friend class ModuleEnumerator;
269
270  EnumerateModulesModel();
271  virtual ~EnumerateModulesModel();
272
273  // Called on the UI thread when the helper class is done scanning.
274  void DoneScanning();
275
276  // Constructs a Help Center article URL for help with a particular module.
277  // The module must have the SEE_LINK attribute for |recommended_action| set,
278  // otherwise this returns a blank string.
279  GURL ConstructHelpCenterUrl(const ModuleEnumerator::Module& module) const;
280
281  // The vector containing all the modules enumerated. Will be normalized and
282  // any bad modules will be marked.
283  ModuleEnumerator::ModulesVector enumerated_modules_;
284
285  // The object responsible for enumerating the modules on the File thread.
286  scoped_refptr<ModuleEnumerator> module_enumerator_;
287
288  // When this singleton object is constructed we go and fire off this timer to
289  // start scanning for modules after a certain amount of time has passed.
290  base::OneShotTimer<EnumerateModulesModel> check_modules_timer_;
291
292  // While normally |false|, this mode can be set to indicate that the scanning
293  // process should not rely on certain services normally available to Chrome,
294  // such as the resource bundle and the notification system, not to mention
295  // having multiple threads. This mode is useful during diagnostics, which
296  // runs without firing up all necessary Chrome services first.
297  bool limited_mode_;
298
299  // True if we are currently scanning for modules.
300  bool scanning_;
301
302  // Whether the conflict notification has been acknowledged by the user.
303  bool conflict_notification_acknowledged_;
304
305  // The number of confirmed bad modules (not including suspected bad ones)
306  // found during last scan.
307  int confirmed_bad_modules_detected_;
308
309  // The number of suspected bad modules (not including confirmed bad ones)
310  // found during last scan.
311  int suspected_bad_modules_detected_;
312
313  DISALLOW_COPY_AND_ASSIGN(EnumerateModulesModel);
314};
315
316#endif  // CHROME_BROWSER_ENUMERATE_MODULES_MODEL_WIN_H_
317