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