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 #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