Home | History | Annotate | Download | only in browser
      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.
    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.
    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.
    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.
    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