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.
5 #ifndef CHROME_BROWSER_ENUMERATE_MODULES_MODEL_WIN_H_
6 #define CHROME_BROWSER_ENUMERATE_MODULES_MODEL_WIN_H_
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"
19 class EnumerateModulesModel
;
26 // A helper class that implements the enumerate module functionality on the File
28 class ModuleEnumerator
: public base::RefCountedThreadSafe
<ModuleEnumerator
> {
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
35 LOADED_MODULE
= 1 << 0,
36 SHELL_EXTENSION
= 1 << 1,
37 WINSOCK_MODULE_REGISTRATION
= 1 << 2,
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).
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
49 // The module is not on the blacklist. Assume it is good.
51 // Module is a suspected bad module.
53 // Module is a bad bad dog.
57 // A bitmask with the possible resolutions for bad modules.
58 enum RecommendedAction
{
60 INVESTIGATING
= 1 << 0,
68 // Which Windows OS is affected.
69 enum OperatingSystem
{
74 // The structure we populate when enumerating modules.
77 Module(const Module
& rhs
);
78 Module(ModuleType type
,
80 const base::string16
& location
,
81 const base::string16
& name
,
82 const base::string16
& product_name
,
83 const base::string16
& description
,
84 const base::string16
& version
,
85 const base::string16
& digital_signer
,
86 RecommendedAction recommended_action
);
89 // The type of module found
91 // The module status (benign/bad/etc).
93 // The module path, not including filename.
94 base::string16 location
;
95 // The name of the module (filename).
97 // The name of the product the module belongs to.
98 base::string16 product_name
;
99 // The module file description.
100 base::string16 description
;
101 // The module version.
102 base::string16 version
;
103 // The signer of the digital certificate for the module.
104 base::string16 digital_signer
;
105 // The help tips bitmask.
106 RecommendedAction recommended_action
;
107 // The duplicate count within each category of modules.
109 // Whether this module has been normalized (necessary before checking it
110 // against blacklist).
114 // A vector typedef of all modules enumerated.
115 typedef std::vector
<Module
> ModulesVector
;
117 // A structure we populate with the blacklist entries.
118 struct BlacklistEntry
{
119 const char* filename
;
120 const char* location
;
121 const char* desc_or_signer
;
122 const char* version_from
; // Version where conflict started.
123 const char* version_to
; // First version that works.
124 OperatingSystem os
; // Bitmask, representing what OS this entry applies to.
125 RecommendedAction help_tip
;
128 // A static function that normalizes the module information in the |module|
129 // struct. Module information needs to be normalized before comparing against
130 // the blacklist. This is because the same module can be described in many
131 // different ways, ie. file paths can be presented in long/short name form,
132 // and are not case sensitive on Windows. Also, the version string returned
133 // can include appended text, which we don't want to use during comparison
134 // against the blacklist.
135 static void NormalizeModule(Module
* module
);
137 // A static function that checks whether |module| has been |blacklisted|.
138 static ModuleStatus
Match(const Module
& module
,
139 const BlacklistEntry
& blacklisted
);
141 explicit ModuleEnumerator(EnumerateModulesModel
* observer
);
143 // Start scanning the loaded module list (if a scan is not already in
144 // progress). This function does not block while reading the module list
145 // (unless we are in limited_mode, see below), and will notify when done
146 // through the MODULE_LIST_ENUMERATED notification.
147 // The process will also send MODULE_INCOMPATIBILITY_BADGE_CHANGE to let
148 // observers know when it is time to update the wrench menu badge.
149 // When in |limited_mode|, this function will not leverage the File thread
150 // to run asynchronously and will therefore block until scanning is done
151 // (and will also not send out any notifications).
152 void ScanNow(ModulesVector
* list
, bool limited_mode
);
155 FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest
, CollapsePath
);
157 friend class base::RefCountedThreadSafe
<ModuleEnumerator
>;
160 // The (currently) hard coded blacklist of known bad modules.
161 static const BlacklistEntry kModuleBlacklist
[];
163 // This function does the actual file scanning work on the FILE thread (or
164 // block the main thread when in limited_mode). It enumerates all loaded
165 // modules in the process and other modules of interest, such as the
166 // registered Winsock LSP modules and stores them in |enumerated_modules_|.
167 // It then normalizes the module info and matches them against a blacklist
168 // of known bad modules. Finally, it calls ReportBack to let the observer
172 // Enumerate all modules loaded into the Chrome process.
173 void EnumerateLoadedModules();
175 // Enumerate all registered Windows shell extensions.
176 void EnumerateShellExtensions();
178 // Enumerate all registered Winsock LSP modules.
179 void EnumerateWinsockModules();
181 // Reads the registered shell extensions found under |parent| key in the
183 void ReadShellExtensions(HKEY parent
);
185 // Given a |module|, initializes the structure and loads additional
186 // information using the location field of the module.
187 void PopulateModuleInformation(Module
* module
);
189 // Checks the module list to see if a |module| of the same type, location
190 // and name has been added before and if so, increments its duplication
191 // counter. If it doesn't appear in the list, it is added.
192 void AddToListWithoutDuplicating(const Module
&);
194 // Builds up a vector of path values mapping to environment variable,
195 // with pairs like [c:\windows\, %systemroot%]. This is later used to
196 // collapse paths like c:\windows\system32 into %systemroot%\system32, which
197 // we can use for comparison against our blacklist (which uses only env vars).
198 // NOTE: The vector will not contain an exhaustive list of environment
199 // variables, only the ones currently found on the blacklist or ones that are
200 // likely to appear there.
201 void PreparePathMappings();
203 // For a given |module|, collapse the path from c:\windows to %systemroot%,
204 // based on the |path_mapping_| vector.
205 void CollapsePath(Module
* module
);
207 // Takes each module in the |enumerated_modules_| vector and matches it
208 // against a fixed blacklist of bad and suspected bad modules.
209 void MatchAgainstBlacklist();
211 // This function executes on the UI thread when the scanning and matching
212 // process is done. It notifies the observer.
215 // Given a filename, returns the Subject (who signed it) retrieved from
216 // the digital signature (Authenticode).
217 base::string16
GetSubjectNameFromDigitalSignature(
218 const base::FilePath
& filename
);
220 // The typedef for the vector that maps a regular file path to %env_var%.
221 typedef std::vector
< std::pair
<base::string16
, base::string16
> > PathMapping
;
223 // The vector of paths to %env_var%, used to account for differences in
224 // where people keep there files, c:\windows vs. d:\windows, etc.
225 PathMapping path_mapping_
;
227 // The vector containing all the enumerated modules (loaded and modules of
229 ModulesVector
* enumerated_modules_
;
231 // The observer, who needs to be notified when we are done.
232 EnumerateModulesModel
* observer_
;
234 // See limited_mode below.
237 // The thread that we need to call back on to report that we are done.
238 content::BrowserThread::ID callback_thread_id_
;
240 DISALLOW_COPY_AND_ASSIGN(ModuleEnumerator
);
243 // This is a singleton class that enumerates all modules loaded into Chrome,
244 // both currently loaded modules (called DLLs on Windows) and modules 'of
245 // interest', such as WinSock LSP modules. This class also marks each module
246 // as benign or suspected bad or outright bad, using a supplied blacklist that
247 // is currently hard-coded.
249 // To use this class, grab the singleton pointer and call ScanNow().
250 // Then wait to get notified through MODULE_LIST_ENUMERATED when the list is
253 // This class can be used on the UI thread as it asynchronously offloads the
254 // file work over to the FILE thread and reports back to the caller with a
256 class EnumerateModulesModel
{
258 // UMA histogram constants.
259 enum UmaModuleConflictHistogramOptions
{
260 ACTION_BUBBLE_SHOWN
= 0,
261 ACTION_BUBBLE_LEARN_MORE
,
262 ACTION_MENU_LEARN_MORE
,
263 ACTION_BOUNDARY
, // Must be the last value.
266 static EnumerateModulesModel
* GetInstance();
268 // Returns true if we should show the conflict notification. The conflict
269 // notification is only shown once during the lifetime of the process.
270 bool ShouldShowConflictWarning() const;
272 // Called when the user has acknowledged the conflict notification.
273 void AcknowledgeConflictNotification();
275 // Returns the number of suspected bad modules found in the last scan.
276 // Returns 0 if no scan has taken place yet.
277 int suspected_bad_modules_detected() const {
278 return suspected_bad_modules_detected_
;
281 // Returns the number of confirmed bad modules found in the last scan.
282 // Returns 0 if no scan has taken place yet.
283 int confirmed_bad_modules_detected() const {
284 return confirmed_bad_modules_detected_
;
287 // Returns how many modules to notify the user about.
288 int modules_to_notify_about() const {
289 return modules_to_notify_about_
;
292 // Set to true when we the scanning process can not rely on certain Chrome
293 // services to exists.
294 void set_limited_mode(bool limited_mode
) {
295 limited_mode_
= limited_mode
;
298 // Checks to see if a scanning task should be started and sets one off, if so.
299 void MaybePostScanningTask();
301 // Asynchronously start the scan for the loaded module list, except when in
302 // limited_mode (in which case it blocks).
305 // Gets the whole module list as a ListValue.
306 base::ListValue
* GetModuleList() const;
308 // Gets the Help Center URL for the first *notable* conflict module that we've
309 // elected to notify the user about.
310 GURL
GetFirstNotableConflict();
313 friend struct DefaultSingletonTraits
<EnumerateModulesModel
>;
314 friend class ModuleEnumerator
;
316 EnumerateModulesModel();
317 virtual ~EnumerateModulesModel();
319 // Called on the UI thread when the helper class is done scanning.
322 // Constructs a Help Center article URL for help with a particular module.
323 // The module must have the SEE_LINK attribute for |recommended_action| set,
324 // otherwise this returns a blank string.
325 GURL
ConstructHelpCenterUrl(const ModuleEnumerator::Module
& module
) const;
327 // The vector containing all the modules enumerated. Will be normalized and
328 // any bad modules will be marked.
329 ModuleEnumerator::ModulesVector enumerated_modules_
;
331 // The object responsible for enumerating the modules on the File thread.
332 scoped_refptr
<ModuleEnumerator
> module_enumerator_
;
334 // When this singleton object is constructed we go and fire off this timer to
335 // start scanning for modules after a certain amount of time has passed.
336 base::OneShotTimer
<EnumerateModulesModel
> check_modules_timer_
;
338 // While normally |false|, this mode can be set to indicate that the scanning
339 // process should not rely on certain services normally available to Chrome,
340 // such as the resource bundle and the notification system, not to mention
341 // having multiple threads. This mode is useful during diagnostics, which
342 // runs without firing up all necessary Chrome services first.
345 // True if we are currently scanning for modules.
348 // Whether the conflict notification has been acknowledged by the user.
349 bool conflict_notification_acknowledged_
;
351 // The number of confirmed bad modules (not including suspected bad ones)
352 // found during last scan.
353 int confirmed_bad_modules_detected_
;
355 // The number of bad modules the user needs to be aggressively notified about.
356 int modules_to_notify_about_
;
358 // The number of suspected bad modules (not including confirmed bad ones)
359 // found during last scan.
360 int suspected_bad_modules_detected_
;
362 DISALLOW_COPY_AND_ASSIGN(EnumerateModulesModel
);
365 #endif // CHROME_BROWSER_ENUMERATE_MODULES_MODEL_WIN_H_