• 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 #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 
20 class EnumerateModulesModel;
21 class FilePath;
22 class ListValue;
23 
24 // A helper class that implements the enumerate module functionality on the File
25 // thread.
26 class 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.
230 class 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.
suspected_bad_modules_detected()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.
confirmed_bad_modules_detected()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.
set_limited_mode(bool limited_mode)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