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