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