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