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