Coverage for /Syzygy/instrument/transforms/asan_transform.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%49490.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Implementation of the SyzyAsan instrumentation transform.
  16    :  
  17    :  #ifndef SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
  18    :  #define SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
  19    :  
  20    :  #include <map>
  21    :  #include <set>
  22    :  #include <string>
  23    :  #include <utility>
  24    :  #include <vector>
  25    :  
  26    :  #include "base/strings/string_piece.h"
  27    :  #include "syzygy/block_graph/filterable.h"
  28    :  #include "syzygy/block_graph/iterate.h"
  29    :  #include "syzygy/block_graph/analysis/liveness_analysis.h"
  30    :  #include "syzygy/block_graph/analysis/memory_access_analysis.h"
  31    :  #include "syzygy/block_graph/transforms/iterative_transform.h"
  32    :  #include "syzygy/block_graph/transforms/named_transform.h"
  33    :  #include "syzygy/common/asan_parameters.h"
  34    :  #include "syzygy/instrument/transforms/asan_interceptor_filter.h"
  35    :  #include "syzygy/instrument/transforms/asan_intercepts.h"
  36    :  #include "syzygy/pe/transforms/pe_add_imports_transform.h"
  37    :  
  38    :  namespace instrument {
  39    :  namespace transforms {
  40    :  
  41    :  // This class implements the transformation applied to each basic block.
  42    :  class AsanBasicBlockTransform
  43    :      : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
  44    :            AsanBasicBlockTransform>,
  45    :        public block_graph::Filterable {
  46    :   public:
  47    :    // Represent the different kind of access to the memory.
  48    :    enum MemoryAccessMode {
  49    :      kNoAccess,
  50    :      kReadAccess,
  51    :      kWriteAccess,
  52    :      kInstrAccess,
  53    :      kRepzAccess,
  54    :      kRepnzAccess,
  55    :    };
  56    :  
  57    :    enum StackAccessMode {
  58    :      kUnsafeStackAccess,
  59    :      kSafeStackAccess,
  60    :    };
  61    :  
  62    :    // Contains memory access information.
  63    :    struct MemoryAccessInfo {
  64    :      MemoryAccessMode mode;
  65    :      uint8_t size;
  66    :      uint16_t opcode;
  67    :      // True iff we need to save the flags for this access.
  68    :      bool save_flags;
  69    :    };
  70    :  
  71    :    typedef block_graph::BlockGraph BlockGraph;
  72    :    typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
  73    :    typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
  74    :    typedef MemoryAccessInfo AsanHookMapEntryKey;
  75    :    // Map of hooks to Asan check access functions.
  76    :    typedef std::map<AsanHookMapEntryKey, BlockGraph::Reference> AsanHookMap;
  77    :    typedef std::map<MemoryAccessMode, BlockGraph::Reference> AsanDefaultHookMap;
  78    :  
  79    :    // Constructor.
  80    :    // @param check_access_hooks References to the various check access functions.
  81    :    //     The hooks are assumed to be direct references for COFF images, and
  82    :    //     indirect references for PE images.
  83    :    explicit AsanBasicBlockTransform(AsanHookMap* check_access_hooks) :
  84    :        check_access_hooks_(check_access_hooks),
  85    :        debug_friendly_(false),
  86    :        dry_run_(false),
  87    :        instrumentation_happened_(false),
  88    :        instrumentation_rate_(1.0),
  89    :        remove_redundant_checks_(false),
  90  E :        use_liveness_analysis_(false) {
  91  E :      DCHECK(check_access_hooks != NULL);
  92  E :    }
  93    :  
  94    :    // @name Accessors and mutators.
  95    :    // @{
  96    :    bool debug_friendly() const { return debug_friendly_; }
  97  E :    void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
  98    :  
  99  E :    bool use_liveness_analysis() { return use_liveness_analysis_; }
 100  E :    void set_use_liveness_analysis(bool use_liveness_analysis) {
 101  E :      use_liveness_analysis_ = use_liveness_analysis;
 102  E :    }
 103    :  
 104  E :    bool remove_redundant_checks() const { return remove_redundant_checks_; }
 105  E :    void set_remove_redundant_checks(bool remove_redundant_checks) {
 106  E :      remove_redundant_checks_ = remove_redundant_checks;
 107  E :    }
 108    :  
 109    :    // The instrumentation rate must be in the range [0, 1], inclusive.
 110  E :    double instrumentation_rate() const { return instrumentation_rate_; }
 111    :    void set_instrumentation_rate(double instrumentation_rate);
 112    :  
 113    :    // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
 114    :    // only signals if any instrumentation would have happened on the block.
 115    :    // @returns true iff the instrumenter is in dry run mode.
 116  E :    bool dry_run() const { return dry_run_; }
 117    :    // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
 118    :    // only signals if any instrumentation would have happened on the block.
 119    :    // @param dry_run true iff dry run mode is on.
 120  E :    void set_dry_run(bool dry_run) { dry_run_ = dry_run; }
 121    :  
 122    :    // If at least one instrumentation happened during a transform, or would have
 123    :    // happened during a dry run transform, this returns true.
 124    :    // @returns true iff an instrumentation happened (or would have happened, in
 125    :    //     case of a dry run).
 126  E :    bool instrumentation_happened() const { return instrumentation_happened_; }
 127    :    // @}
 128    :  
 129    :    // The transform name.
 130    :    static const char kTransformName[];
 131    :  
 132    :    // @name BasicBlockSubGraphTransformInterface method.
 133    :    bool TransformBasicBlockSubGraph(
 134    :        const TransformPolicyInterface* policy,
 135    :        BlockGraph* block_graph,
 136    :        BasicBlockSubGraph* basic_block_subgraph) override;
 137    :  
 138    :   protected:
 139    :    // Instruments the memory accesses in a basic block.
 140    :    // @param basic_block The basic block to be instrumented.
 141    :    // @param stack_mode Give some assumptions to the transformation on stack
 142    :    //     frame manipulations inside @p basic_block. The transformation assume a
 143    :    //     standard calling convention, unless specified by this parameter.
 144    :    //     (note: Unsafe blocks may be produced with the compiler flag
 145    :    //     frame-pointer-omission).
 146    :    // @param image_format The format of the image being instrumented. The details
 147    :    //     of how we invoke the hooks vary depending on this.
 148    :    // @returns true on success, false otherwise.
 149    :    bool InstrumentBasicBlock(block_graph::BasicCodeBlock* basic_block,
 150    :                              StackAccessMode stack_mode,
 151    :                              BlockGraph::ImageFormat image_format);
 152    :  
 153    :   private:
 154    :    // Liveness analysis and liveness information for this subgraph.
 155    :    block_graph::analysis::LivenessAnalysis liveness_;
 156    :  
 157    :    // Memory accesses value numbering.
 158    :    block_graph::analysis::MemoryAccessAnalysis memory_accesses_;
 159    :  
 160    :    // The references to the Asan access check import entries.
 161    :    AsanHookMap* check_access_hooks_;
 162    :  
 163    :    // Activate the overwriting of source range for created instructions.
 164    :    bool debug_friendly_;
 165    :  
 166    :    // Instead of instrumenting the basic blocks, run in dry run mode and just
 167    :    // signal whether there would be an instrumentation in the block.
 168    :    bool dry_run_;
 169    :  
 170    :    // Controls the rate at which reads/writes are instrumented. This is
 171    :    // implemented using random sampling.
 172    :    double instrumentation_rate_;
 173    :  
 174    :    // If any instrumentation happened during a transform, or would have happened
 175    :    // during a dry run transform, this member is set to true.
 176    :    bool instrumentation_happened_;
 177    :  
 178    :    // When activated, a redundancy elimination is performed to minimize the
 179    :    // memory checks added by this transform.
 180    :    bool remove_redundant_checks_;
 181    :  
 182    :    // Set iff we should use the liveness analysis to do smarter instrumentation.
 183    :    bool use_liveness_analysis_;
 184    :  
 185    :    DISALLOW_COPY_AND_ASSIGN(AsanBasicBlockTransform);
 186    :  };
 187    :  
 188    :  // This runs Asan basic block transform in dry run mode and prepares the block
 189    :  // for hot patching if Asan would instrument it. Doing these two things in a
 190    :  // single basic block transform avoids running basic block decomposer twice.
 191    :  class HotPatchingAsanBasicBlockTransform
 192    :      : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
 193    :            AsanBasicBlockTransform>,
 194    :        public block_graph::Filterable {
 195    :   public:
 196    :    typedef block_graph::BlockGraph BlockGraph;
 197    :    typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
 198    :    typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
 199    :  
 200    :    // Construct a HotPatchingAsanBasicBlockTransform.
 201    :    // @param asan_bb_transform An Asan basic block transform that will be run
 202    :    //     to check if an instrumentation would happen.
 203    :    // @pre the transform in the parameter must be in dry run mode.
 204    :    HotPatchingAsanBasicBlockTransform(
 205    :        AsanBasicBlockTransform* asan_bb_transform);
 206    :  
 207    :    // @name BasicBlockSubGraphTransformInterface method.
 208    :    bool TransformBasicBlockSubGraph(
 209    :        const TransformPolicyInterface* policy,
 210    :        BlockGraph* block_graph,
 211    :        BasicBlockSubGraph* basic_block_subgraph) override;
 212    :  
 213    :    // Check if the block in the subgraph was prepared for hot patching during
 214    :    // the last run of TransformBasicBlockSubGraph.
 215    :    // @returns true if the prepared the block for hot patching, false if the
 216    :    //     block needs no Asan instrumentation.
 217  E :    bool prepared_for_hot_patching() {
 218  E :      return prepared_for_hot_patching_;
 219  E :    }
 220    :  
 221    :   private:
 222    :    AsanBasicBlockTransform* asan_bb_transform_;
 223    :  
 224    :    bool prepared_for_hot_patching_;
 225    :  
 226    :    DISALLOW_COPY_AND_ASSIGN(HotPatchingAsanBasicBlockTransform);
 227    :  };
 228    :  
 229    :  class AsanTransform
 230    :      : public block_graph::transforms::IterativeTransformImpl<AsanTransform>,
 231    :        public block_graph::Filterable {
 232    :   public:
 233    :    typedef block_graph::BlockGraph BlockGraph;
 234    :    typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
 235    :    typedef AsanBasicBlockTransform::MemoryAccessMode MemoryAccessMode;
 236    :    typedef std::set<BlockGraph::Block*, BlockGraph::BlockIdLess> BlockSet;
 237    :  
 238    :    // Initialize a new AsanTransform instance.
 239    :    AsanTransform();
 240    :  
 241    :    ~AsanTransform();
 242    :  
 243    :    // @name IterativeTransformImpl implementation.
 244    :    // @{
 245    :    bool PreBlockGraphIteration(const TransformPolicyInterface* policy,
 246    :                                BlockGraph* block_graph,
 247    :                                BlockGraph::Block* header_block);
 248    :    bool OnBlock(const TransformPolicyInterface* policy,
 249    :                 BlockGraph* block_graph,
 250    :                 BlockGraph::Block* block);
 251    :    bool PostBlockGraphIteration(const TransformPolicyInterface* policy,
 252    :                                 BlockGraph* block_graph,
 253    :                                 BlockGraph::Block* header_block);
 254    :    // @}
 255    :  
 256    :    // @name Accessors and mutators.
 257    :    // @{
 258  E :    void set_instrument_dll_name(const base::StringPiece& instrument_dll_name) {
 259  E :      instrument_dll_name.CopyToString(&asan_dll_name_);
 260  E :    }
 261    :    // Name of the asan_rtl DLL we import. The |instrument_dll_name_| member is
 262    :    // empty by default, in that case |kSyzyAsanDll| will be returned if hot
 263    :    // patching mode is disabled and |kSyzyAsanHpDll| will be returned in hot
 264    :    // patching mode.
 265    :    // @returns the name of the runtime library of the instrumentation.
 266    :    base::StringPiece instrument_dll_name() const;
 267    :  
 268  E :    bool debug_friendly() const { return debug_friendly_; }
 269  E :    void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
 270    :  
 271  E :    bool use_interceptors() const { return use_interceptors_; }
 272  E :    void set_use_interceptors(bool use_interceptors) {
 273  E :      use_interceptors_ = use_interceptors;
 274  E :    }
 275    :  
 276  E :    bool use_liveness_analysis() const { return use_liveness_analysis_; }
 277  E :    void set_use_liveness_analysis(bool use_liveness_analysis) {
 278  E :      use_liveness_analysis_ = use_liveness_analysis;
 279  E :    }
 280    :  
 281  E :    bool remove_redundant_checks() const { return remove_redundant_checks_; }
 282  E :    void set_remove_redundant_checks(bool remove_redundant_checks) {
 283  E :      remove_redundant_checks_ = remove_redundant_checks;
 284  E :    }
 285    :  
 286    :    // The instrumentation rate must be in the range [0, 1], inclusive.
 287  E :    double instrumentation_rate() const { return instrumentation_rate_; }
 288    :    void set_instrumentation_rate(double instrumentation_rate);
 289    :  
 290    :    // Asan RTL parameters.
 291  E :    const common::InflatedAsanParameters* asan_parameters() const {
 292  E :      return asan_parameters_;
 293  E :    }
 294    :    void set_asan_parameters(
 295  E :        const common::InflatedAsanParameters* asan_parameters) {
 296  E :      asan_parameters_ = asan_parameters;
 297  E :    }
 298    :    // @}
 299    :  
 300    :    // Checks if the transform is in hot patching mode.
 301    :    // @returns true iff in hot patching mode.
 302  E :    bool hot_patching() const {
 303  E :      return hot_patching_;
 304  E :    }
 305    :    // If this flag is true, running the transformation prepares the module to
 306    :    // be used by the hot patching Asan runtime.
 307    :    // @param hot_patching The new value of the flag.
 308  E :    void set_hot_patching(bool hot_patching) {
 309  E :      hot_patching_ = hot_patching;
 310  E :    }
 311    :  
 312    :    // The name of the DLL that is imported by default if hot patching mode is
 313    :    // inactive.
 314    :    static const char kSyzyAsanDll[];
 315    :  
 316    :    // The name of the DLL that is imported by default in hot patching mode.
 317    :    static const char kSyzyAsanHpDll[];
 318    :  
 319    :    // The transform name.
 320    :    static const char kTransformName[];
 321    :  
 322    :    // The hooks stub name.
 323    :    static const char kAsanHookStubName[];
 324    :  
 325    :   protected:
 326    :    // PreBlockGraphIteration uses this to find the block of the _heap_init
 327    :    // function and the data block of _crtheap. This information is used by
 328    :    // PatchCRTHeapInitialization. Also, the block of _heap_init is skipped by
 329    :    // OnBlock.
 330    :    // Calling this initializes heap_init_block_ and crtheap_block_ members.
 331    :    // @param block_graph The block graph to be searched.
 332    :    // @pre Both heap_init_block_ and crtheap_block_ must be nullptr.
 333    :    // @note If either heap_init_block_ and crtheap_block_ is not found, both are
 334    :    //     set to nullptr.
 335    :    void FindHeapInitAndCrtHeapBlocks(BlockGraph* block_graph);
 336    :  
 337    :    // Decides if we should skip a Block in OnBlock. A block is skipped if
 338    :    // either
 339    :    //   - it is the block of _heap_init,
 340    :    //   - it is in the static_intercepted_blocks_ set,
 341    :    //   - it is not safe to BB-decompose.
 342    :    // @param policy The policy object that tells if a block is safe to
 343    :    //     BB-decompose.
 344    :    // @param block The block to examine.
 345    :    // @returns true iff the block should be skipped.
 346    :    bool ShouldSkipBlock(const TransformPolicyInterface* policy,
 347    :                         BlockGraph::Block* block);
 348    :  
 349    :    // @name PE-specific methods.
 350    :    // @{
 351    :    // Finds statically linked functions that need to be intercepted. Called in
 352    :    // PreBlockGraphTransform. Fills the static_intercepted_blocks_ set.
 353    :    // Blocks in this set are skipped in OnBlock and intercepted in
 354    :    // PeInterceptFunctions.
 355    :    // @param intercepts The Asan intercepts.
 356    :    // @param block_graph The block graph to search in.
 357    :    void PeFindStaticallyLinkedFunctionsToIntercept(
 358    :        const AsanIntercept* intercepts,
 359    :        BlockGraph* block_graph);
 360    :  
 361    :    // Invoked when instrumenting a PE image. Intercepts all relevant import
 362    :    // and statically linked functions found in the image. The intercepts to be
 363    :    // used are exposed for unittesting.
 364    :    bool PeInterceptFunctions(const AsanIntercept* intercepts,
 365    :                              const TransformPolicyInterface* policy,
 366    :                              BlockGraph* block_graph,
 367    :                              BlockGraph::Block* header_block);
 368    :  
 369    :    // Injects runtime parameters into the image.
 370    :    bool PeInjectAsanParameters(const TransformPolicyInterface* policy,
 371    :                                BlockGraph* block_graph,
 372    :                                BlockGraph::Block* header_block);
 373    :    // @}
 374    :  
 375    :    // @name COFF-specific methods.
 376    :    // @{
 377    :    // Invoked when instrumenting a COFF image. Intercepts all relevant functions
 378    :    // via symbol renaming, redirecting to Asan instrumented versions. The
 379    :    // intercepts to be used are exposed for unittesting.
 380    :    bool CoffInterceptFunctions(const AsanIntercept* intercepts,
 381    :                                const TransformPolicyInterface* policy,
 382    :                                BlockGraph* block_graph,
 383    :                                BlockGraph::Block* header_block);
 384    :    // @}
 385    :  
 386    :    // Name of the asan_rtl DLL we import. Do not access this directly, use the
 387    :    // instrument_dll_name() getter that provides default values.
 388    :    std::string asan_dll_name_;
 389    :  
 390    :    // Activate the overwriting of source range for created instructions.
 391    :    bool debug_friendly_;
 392    :  
 393    :    // Set iff we should use the liveness analysis to do smarter instrumentation.
 394    :    bool use_liveness_analysis_;
 395    :  
 396    :    // When activated, a redundancy elimination is performed to minimize the
 397    :    // memory checks added by this transform.
 398    :    bool remove_redundant_checks_;
 399    :  
 400    :    // Set iff we should use the functions interceptors.
 401    :    bool use_interceptors_;
 402    :  
 403    :    // Controls the rate at which reads/writes are instrumented. This is
 404    :    // implemented using random sampling.
 405    :    double instrumentation_rate_;
 406    :  
 407    :    // Asan RTL parameters that will be injected into the instrumented image.
 408    :    // These will be found by the RTL and used to control its behaviour. Allows
 409    :    // for setting parameters at instrumentation time that vary from the defaults.
 410    :    // These can still be overridden by configuring the RTL via an environment
 411    :    // variable.
 412    :    const common::InflatedAsanParameters* asan_parameters_;
 413    :  
 414    :    // References to the different Asan check access import entries. Valid after
 415    :    // successful PreBlockGraphIteration.
 416    :    AsanBasicBlockTransform::AsanHookMap check_access_hooks_ref_;
 417    :  
 418    :    // Block containing any injected runtime parameters. Valid in PE mode after
 419    :    // a successful PostBlockGraphIteration. This is a unittesting seam.
 420    :    block_graph::BlockGraph::Block* asan_parameters_block_;
 421    :  
 422    :    // Vector of CRT heap initialization blocks. These are determined during
 423    :    // PreBlockGraphIteration.
 424    :    std::vector<BlockGraph::Block*> heap_init_blocks_;
 425    :  
 426    :    // Statically linked functions that need to be intercepted. Populated by
 427    :    // PeFindStaticallyLinkedFunctionsToIntercept. Block in this set are skipped
 428    :    // in OnBlock and intercepted in PeInterceptFunctions.
 429    :    // This is a set because OnBlock needs fast lookup. We sort by the BlockID
 430    :    // to have a consistent output in PeInterceptFunctions.
 431    :    BlockSet static_intercepted_blocks_;
 432    :  
 433    :    // If this flag is true, running the transformation prepares the module to
 434    :    // be used by the hot patching Asan runtime.
 435    :    bool hot_patching_;
 436    :  
 437    :    // In hot patching mode, this vector is used to collect the blocks prepared
 438    :    // for hot patching in the OnBlock method and insert them to the hot patching
 439    :    // metadata stream in the PostBlockGraphIteration.
 440    :    std::vector<BlockGraph::Block*> hot_patched_blocks_;
 441    :  
 442    :   private:
 443    :    DISALLOW_COPY_AND_ASSIGN(AsanTransform);
 444    :  };
 445    :  
 446    :  bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
 447    :                 const AsanBasicBlockTransform::MemoryAccessInfo& right);
 448    :  
 449    :  }  // namespace transforms
 450    :  }  // namespace instrument
 451    :  
 452    :  #endif  // SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_

Coverage information generated Thu Jan 14 17:40:38 2016.