OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ | 5 #ifndef CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ |
6 #define CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ | 6 #define CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ |
7 | 7 |
8 #include <memory> | |
8 #include <utility> | 9 #include <utility> |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 #include "base/gtest_prod_util.h" | 12 #include "base/gtest_prod_util.h" |
12 #include "base/macros.h" | 13 #include "base/macros.h" |
13 #include "base/memory/ref_counted.h" | 14 #include "base/observer_list.h" |
14 #include "base/memory/singleton.h" | |
15 #include "base/strings/string16.h" | 15 #include "base/strings/string16.h" |
16 #include "base/timer/timer.h" | 16 #include "base/timer/timer.h" |
17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
18 #include "url/gurl.h" | 18 #include "url/gurl.h" |
19 | 19 |
20 class EnumerateModulesModel; | 20 class EnumerateModulesModel; |
21 | 21 |
22 namespace base { | 22 namespace base { |
23 class FilePath; | 23 class FilePath; |
24 class ListValue; | 24 class ListValue; |
25 } | 25 } |
26 | 26 |
27 // A helper class that implements the enumerate module functionality on the File | 27 // A helper class that implements the enumerate module functionality on the FILE |
28 // thread. | 28 // thread. Not to be used directly. |
29 class ModuleEnumerator : public base::RefCountedThreadSafe<ModuleEnumerator> { | 29 // TODO(chrisha): Move this to a separate .h and .cc. |
30 class ModuleEnumerator { | |
30 public: | 31 public: |
31 // What type of module we are dealing with. Loaded modules are modules we | 32 // 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 // 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 // modules of interest and may or may not be loaded in the process at the |
34 // time of scan. | 35 // time of scan. |
35 enum ModuleType { | 36 enum ModuleType { |
36 LOADED_MODULE = 1 << 0, | 37 LOADED_MODULE = 1 << 0, |
37 SHELL_EXTENSION = 1 << 1, | 38 SHELL_EXTENSION = 1 << 1, |
38 WINSOCK_MODULE_REGISTRATION = 1 << 2, | 39 WINSOCK_MODULE_REGISTRATION = 1 << 2, |
39 }; | 40 }; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 // The duplicate count within each category of modules. | 109 // The duplicate count within each category of modules. |
109 int duplicate_count; | 110 int duplicate_count; |
110 // Whether this module has been normalized (necessary before checking it | 111 // Whether this module has been normalized (necessary before checking it |
111 // against blacklist). | 112 // against blacklist). |
112 bool normalized; | 113 bool normalized; |
113 }; | 114 }; |
114 | 115 |
115 // A vector typedef of all modules enumerated. | 116 // A vector typedef of all modules enumerated. |
116 typedef std::vector<Module> ModulesVector; | 117 typedef std::vector<Module> ModulesVector; |
117 | 118 |
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| | 119 // A static function that normalizes the module information in the |module| |
130 // struct. Module information needs to be normalized before comparing against | 120 // struct. Module information needs to be normalized before comparing against |
131 // the blacklist. This is because the same module can be described in many | 121 // 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, | 122 // 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 | 123 // 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 | 124 // can include appended text, which we don't want to use during comparison |
135 // against the blacklist. | 125 // against the blacklist. |
136 static void NormalizeModule(Module* module); | 126 static void NormalizeModule(Module* module); |
137 | 127 |
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); | 128 explicit ModuleEnumerator(EnumerateModulesModel* observer); |
143 | 129 |
144 // Start scanning the loaded module list (if a scan is not already in | 130 // 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 | 131 // progress). This function does not block while reading the module list and |
146 // (unless we are in limited_mode, see below), and will notify when done | 132 // will notify when done by calling the DoneScanning method of |observer_|. |
147 // through the MODULE_LIST_ENUMERATED notification. | 133 void ScanNow(ModulesVector* list); |
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 | 134 |
155 private: | 135 private: |
156 FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest, CollapsePath); | 136 FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest, CollapsePath); |
157 | 137 |
158 friend class base::RefCountedThreadSafe<ModuleEnumerator>; | 138 // This function does the actual file scanning work on the FILE thread. It |
159 ~ModuleEnumerator(); | 139 // enumerates all loaded modules in the process and other modules of interest, |
160 | 140 // such as the registered Winsock LSP modules and stores them in |
161 // The (currently) hard coded blacklist of known bad modules. | 141 // |enumerated_modules_|. It then normalizes the module info and matches them |
162 static const BlacklistEntry kModuleBlacklist[]; | 142 // against a blacklist of known bad modules. Finally, notifies the observer |
163 | 143 // that the enumeration is complete by invoking DoneScanning. |
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(); | 144 void ScanImpl(); |
172 | 145 |
173 // Enumerate all modules loaded into the Chrome process. | 146 // Enumerate all modules loaded into the Chrome process. |
174 void EnumerateLoadedModules(); | 147 void EnumerateLoadedModules(); |
175 | 148 |
176 // Enumerate all registered Windows shell extensions. | 149 // Enumerate all registered Windows shell extensions. |
177 void EnumerateShellExtensions(); | 150 void EnumerateShellExtensions(); |
178 | 151 |
179 // Enumerate all registered Winsock LSP modules. | 152 // Enumerate all registered Winsock LSP modules. |
180 void EnumerateWinsockModules(); | 153 void EnumerateWinsockModules(); |
(...skipping 17 matching lines...) Expand all Loading... | |
198 // we can use for comparison against our blacklist (which uses only env vars). | 171 // 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 | 172 // 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 | 173 // variables, only the ones currently found on the blacklist or ones that are |
201 // likely to appear there. | 174 // likely to appear there. |
202 void PreparePathMappings(); | 175 void PreparePathMappings(); |
203 | 176 |
204 // For a given |module|, collapse the path from c:\windows to %systemroot%, | 177 // For a given |module|, collapse the path from c:\windows to %systemroot%, |
205 // based on the |path_mapping_| vector. | 178 // based on the |path_mapping_| vector. |
206 void CollapsePath(Module* module); | 179 void CollapsePath(Module* module); |
207 | 180 |
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 | 181 // Given a filename, returns the Subject (who signed it) retrieved from |
217 // the digital signature (Authenticode). | 182 // the digital signature (Authenticode). |
218 base::string16 GetSubjectNameFromDigitalSignature( | 183 base::string16 GetSubjectNameFromDigitalSignature( |
219 const base::FilePath& filename); | 184 const base::FilePath& filename); |
220 | 185 |
186 // Reports (via UMA) a handful of high-level metrics regarding third party | |
187 // modules in this process. Called by ScanImpl after modules have been | |
188 // enumerated and processed. | |
189 void ReportThirdPartyMetrics(); | |
190 | |
221 // The typedef for the vector that maps a regular file path to %env_var%. | 191 // 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; | 192 typedef std::vector<std::pair<base::string16, base::string16>> PathMapping; |
223 | 193 |
224 // The vector of paths to %env_var%, used to account for differences in | 194 // 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. | 195 // where people keep there files, c:\windows vs. d:\windows, etc. |
226 PathMapping path_mapping_; | 196 PathMapping path_mapping_; |
227 | 197 |
228 // The vector containing all the enumerated modules (loaded and modules of | 198 // The vector containing all the enumerated modules (loaded and modules of |
229 // interest). | 199 // interest). |
230 ModulesVector* enumerated_modules_; | 200 ModulesVector* enumerated_modules_; |
231 | 201 |
232 // The observer, who needs to be notified when we are done. | 202 // The observers, who need to be notified when the scan is complete. |
Lei Zhang
2016/08/04 14:33:32
Isn't it still only a single observer from the per
chrisha
2016/08/12 19:04:41
Yup, not sure why I changed the comment. Reverted.
| |
233 EnumerateModulesModel* observer_; | 203 EnumerateModulesModel* observer_; |
234 | 204 |
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); | 205 DISALLOW_COPY_AND_ASSIGN(ModuleEnumerator); |
242 }; | 206 }; |
243 | 207 |
244 // This is a singleton class that enumerates all modules loaded into Chrome, | 208 // This is a singleton class that enumerates all modules loaded into Chrome, |
245 // both currently loaded modules (called DLLs on Windows) and modules 'of | 209 // both currently loaded modules (called DLLs on Windows) and modules 'of |
246 // interest', such as WinSock LSP modules. This class also marks each module | 210 // 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 | 211 // as benign or suspected bad or outright bad, using a supplied blacklist that |
248 // is currently hard-coded. | 212 // is currently hard-coded. |
249 // | 213 // |
250 // To use this class, grab the singleton pointer and call ScanNow(). | 214 // 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 | 215 // Then wait to get notified through MODULE_LIST_ENUMERATED when the list is |
252 // ready. | 216 // ready. |
253 // | 217 // |
254 // This class can be used on the UI thread as it asynchronously offloads the | 218 // The member functions of this class may only be used from the UI thread. The |
255 // file work over to the FILE thread and reports back to the caller with a | 219 // bulk of the work is actually performed on the FILE thread. |
256 // notification. | |
257 class EnumerateModulesModel { | 220 class EnumerateModulesModel { |
258 public: | 221 public: |
259 // UMA histogram constants. | 222 // UMA histogram constants. |
260 enum UmaModuleConflictHistogramOptions { | 223 enum UmaModuleConflictHistogramOptions { |
261 ACTION_BUBBLE_SHOWN = 0, | 224 ACTION_BUBBLE_SHOWN = 0, |
262 ACTION_BUBBLE_LEARN_MORE, | 225 ACTION_BUBBLE_LEARN_MORE, |
263 ACTION_MENU_LEARN_MORE, | 226 ACTION_MENU_LEARN_MORE, |
264 ACTION_BOUNDARY, // Must be the last value. | 227 ACTION_BOUNDARY, // Must be the last value. |
265 }; | 228 }; |
266 | 229 |
230 // Observer class used to determine when a scan has completed and when any | |
231 // associated UI elements have been dismissed. | |
232 class Observer { | |
233 public: | |
234 // Invoked when EnumerateModulesModel has completed a scan of modules. | |
235 virtual void OnScanCompleted() {} | |
236 | |
237 // Invoked when a user has acknowledged incompatible modules found in a | |
238 // module scan. | |
239 virtual void OnConflictsAcknowledged() {} | |
240 | |
241 protected: | |
242 virtual ~Observer() = default; | |
243 }; | |
244 | |
245 // Returns the singleton instance of this class. | |
267 static EnumerateModulesModel* GetInstance(); | 246 static EnumerateModulesModel* GetInstance(); |
268 | 247 |
248 // Adds an |observer| to the enumerator. Callbacks will occur on the UI | |
249 // thread. | |
250 void AddObserver(Observer* observer); | |
251 | |
252 // Removes an |observer| from the enumerator. | |
253 void RemoveObserver(Observer* observer); | |
254 | |
269 // Returns true if we should show the conflict notification. The conflict | 255 // Returns true if we should show the conflict notification. The conflict |
270 // notification is only shown once during the lifetime of the process. | 256 // notification is only shown once during the lifetime of the process. |
271 bool ShouldShowConflictWarning() const; | 257 bool ShouldShowConflictWarning() const; |
272 | 258 |
273 // Called when the user has acknowledged the conflict notification. | 259 // Called when the user has acknowledged the conflict notification. |
274 void AcknowledgeConflictNotification(); | 260 void AcknowledgeConflictNotification(); |
275 | 261 |
276 // Returns the number of suspected bad modules found in the last scan. | 262 // Returns the number of suspected bad modules found in the last scan. |
277 // Returns 0 if no scan has taken place yet. | 263 // Returns 0 if no scan has taken place yet. |
278 int suspected_bad_modules_detected() const { | 264 int suspected_bad_modules_detected() const; |
279 return suspected_bad_modules_detected_; | |
280 } | |
281 | 265 |
282 // Returns the number of confirmed bad modules found in the last scan. | 266 // Returns the number of confirmed bad modules found in the last scan. |
283 // Returns 0 if no scan has taken place yet. | 267 // Returns 0 if no scan has taken place yet. |
284 int confirmed_bad_modules_detected() const { | 268 int confirmed_bad_modules_detected() const; |
285 return confirmed_bad_modules_detected_; | |
286 } | |
287 | 269 |
288 // Returns how many modules to notify the user about. | 270 // Returns how many modules to notify the user about. |
289 int modules_to_notify_about() const { | 271 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 | 272 |
299 // Checks to see if a scanning task should be started and sets one off, if so. | 273 // Checks to see if a scanning task should be started and sets one off, if so. |
300 void MaybePostScanningTask(); | 274 void MaybePostScanningTask(); |
301 | 275 |
302 // Asynchronously start the scan for the loaded module list, except when in | 276 // Asynchronously start the scan for the loaded module list. |
303 // limited_mode (in which case it blocks). | |
304 void ScanNow(); | 277 void ScanNow(); |
305 | 278 |
306 // Gets the whole module list as a ListValue. | 279 // Gets the whole module list as a ListValue. |
307 base::ListValue* GetModuleList() const; | 280 base::ListValue* GetModuleList(); |
308 | 281 |
309 // Gets the Help Center URL for the first *notable* conflict module that we've | 282 // Returns the site to which the user should be taken when the conflict bubble |
310 // elected to notify the user about. | 283 // or app menu item is clicked. For now this is simply chrome://conflicts, |
311 GURL GetFirstNotableConflict(); | 284 // which contains detailed information about conflicts. Returns an empty URL |
285 // if there are no conficts. May only be called on UI thread. | |
286 GURL GetConflictUrl(); | |
312 | 287 |
313 private: | 288 private: |
314 friend struct base::DefaultSingletonTraits<EnumerateModulesModel>; | |
315 friend class ModuleEnumerator; | 289 friend class ModuleEnumerator; |
316 | 290 |
291 // Private to enforce singleton nature of this class. | |
317 EnumerateModulesModel(); | 292 EnumerateModulesModel(); |
318 virtual ~EnumerateModulesModel(); | 293 ~EnumerateModulesModel(); |
319 | 294 |
320 // Called on the UI thread when the helper class is done scanning. | 295 // Called on the UI thread when the helper class is done scanning. The |
296 // ModuleEnumerator that calls this must not do any work after causing this | |
297 // function to be called, as the EnumerateModulesModel may delete the | |
298 // ModuleEnumerator. | |
321 void DoneScanning(); | 299 void DoneScanning(); |
322 | 300 |
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 | 301 // The vector containing all the modules enumerated. Will be normalized and |
329 // any bad modules will be marked. | 302 // any bad modules will be marked. Written to on the FILE thread by the |
303 // |module_enumerator_|, read from on the UI thread by this class. | |
330 ModuleEnumerator::ModulesVector enumerated_modules_; | 304 ModuleEnumerator::ModulesVector enumerated_modules_; |
331 | 305 |
332 // The object responsible for enumerating the modules on the File thread. | 306 // The object responsible for enumerating the modules on the FILE thread. |
333 scoped_refptr<ModuleEnumerator> module_enumerator_; | 307 // Only used from the UI thread. This ends up internally doing its work on the |
308 // FILE thread. | |
309 std::unique_ptr<ModuleEnumerator> module_enumerator_; | |
334 | 310 |
335 // When this singleton object is constructed we go and fire off this timer to | 311 // Whether the conflict notification has been acknowledged by the user. Only |
336 // start scanning for modules after a certain amount of time has passed. | 312 // modified on the UI thread. |
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_; | 313 bool conflict_notification_acknowledged_; |
351 | 314 |
352 // The number of confirmed bad modules (not including suspected bad ones) | 315 // The number of confirmed bad modules (not including suspected bad ones) |
353 // found during last scan. | 316 // found during last scan. Only modified on the UI thread. |
354 int confirmed_bad_modules_detected_; | 317 int confirmed_bad_modules_detected_; |
355 | 318 |
356 // The number of bad modules the user needs to be aggressively notified about. | 319 // The number of bad modules the user needs to be aggressively notified about. |
320 // Only modified on the UI thread. | |
357 int modules_to_notify_about_; | 321 int modules_to_notify_about_; |
358 | 322 |
359 // The number of suspected bad modules (not including confirmed bad ones) | 323 // The number of suspected bad modules (not including confirmed bad ones) |
360 // found during last scan. | 324 // found during last scan. Only modified on the UI thread. |
361 int suspected_bad_modules_detected_; | 325 int suspected_bad_modules_detected_; |
362 | 326 |
327 base::ObserverList<Observer> observers_; | |
328 | |
363 DISALLOW_COPY_AND_ASSIGN(EnumerateModulesModel); | 329 DISALLOW_COPY_AND_ASSIGN(EnumerateModulesModel); |
364 }; | 330 }; |
365 | 331 |
366 #endif // CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ | 332 #endif // CHROME_BROWSER_WIN_ENUMERATE_MODULES_MODEL_H_ |
OLD | NEW |