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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.0%3834210.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    :  #include "syzygy/instrument/transforms/asan_transform.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "base/string_util.h"
  21    :  #include "base/stringprintf.h"
  22    :  #include "base/memory/ref_counted.h"
  23    :  #include "syzygy/block_graph/basic_block_assembler.h"
  24    :  #include "syzygy/block_graph/block_builder.h"
  25    :  #include "syzygy/block_graph/block_util.h"
  26    :  #include "syzygy/common/defs.h"
  27    :  #include "syzygy/pe/block_util.h"
  28    :  #include "syzygy/pe/pe_utils.h"
  29    :  #include "syzygy/pe/transforms/add_imports_transform.h"
  30    :  #include "third_party/distorm/files/include/mnemonics.h"
  31    :  #include "third_party/distorm/files/src/x86defs.h"
  32    :  
  33    :  namespace instrument {
  34    :  namespace transforms {
  35    :  namespace {
  36    :  
  37    :  using block_graph::BasicBlock;
  38    :  using block_graph::BasicCodeBlock;
  39    :  using block_graph::BasicBlockAssembler;
  40    :  using block_graph::BasicBlockSubGraph;
  41    :  using block_graph::BasicBlockReference;
  42    :  using block_graph::BlockBuilder;
  43    :  using block_graph::BlockGraph;
  44    :  using block_graph::Displacement;
  45    :  using block_graph::Immediate;
  46    :  using block_graph::Instruction;
  47    :  using block_graph::Operand;
  48    :  using block_graph::TypedBlock;
  49    :  using block_graph::Value;
  50    :  using block_graph::analysis::LivenessAnalysis;
  51    :  using block_graph::analysis::MemoryAccessAnalysis;
  52    :  using core::Register;
  53    :  using core::RegisterCode;
  54    :  using pe::transforms::AddImportsTransform;
  55    :  
  56    :  // A simple struct that can be used to let us access strings using TypedBlock.
  57    :  struct StringStruct {
  58    :    const char string[1];
  59    :  };
  60    :  
  61    :  typedef AddImportsTransform::ImportedModule ImportedModule;
  62    :  typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
  63    :  typedef AsanBasicBlockTransform::AsanHookMap HookMap;
  64    :  typedef std::vector<AsanBasicBlockTransform::AsanHookMapEntryKey>
  65    :      AccessHookParamVector;
  66    :  typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
  67    :  typedef TypedBlock<StringStruct> String;
  68    :  
  69    :  // Returns true iff opcode should be instrumented.
  70  E :  bool ShouldInstrumentOpcode(uint16 opcode) {
  71  E :    switch (opcode) {
  72    :      // LEA does not actually access memory.
  73    :      case I_LEA:
  74  E :        return false;
  75    :  
  76    :      // We can ignore the prefetch and clflush instructions. The instrumentation
  77    :      // will detect memory errors if and when the memory is actually accessed.
  78    :      case I_CLFLUSH:
  79    :      case I_PREFETCH:
  80    :      case I_PREFETCHNTA:
  81    :      case I_PREFETCHT0:
  82    :      case I_PREFETCHT1:
  83    :      case I_PREFETCHT2:
  84    :      case I_PREFETCHW:
  85  i :        return false;
  86    :    }
  87  E :    return true;
  88  E :  }
  89    :  
  90    :  // Computes the correct displacement, if any, for operand
  91    :  // number @p operand of @p instr.
  92    :  Displacement ComputeDisplacementForOperand(const Instruction& instr,
  93  E :                                             size_t operand) {
  94  E :    const _DInst& repr = instr.representation();
  95    :  
  96    :    DCHECK(repr.ops[operand].type == O_SMEM ||
  97  E :           repr.ops[operand].type == O_MEM);
  98    :  
  99  E :    size_t access_size_bytes = repr.ops[operand].size / 8;
 100  E :    if (repr.dispSize == 0)
 101  E :      return Displacement(access_size_bytes - 1);
 102    :  
 103  E :    BasicBlockReference reference;
 104  E :    if (instr.FindOperandReference(operand, &reference)) {
 105  E :      if (reference.referred_type() == BasicBlockReference::REFERRED_TYPE_BLOCK) {
 106    :        return Displacement(reference.block(),
 107  E :                            reference.offset() + access_size_bytes - 1);
 108  i :      } else {
 109  E :        return Displacement(reference.basic_block());
 110    :      }
 111  i :    } else {
 112  E :      return Displacement(repr.disp + access_size_bytes - 1);
 113    :    }
 114  E :  }
 115    :  
 116    :  // Returns true if operand @p op is instrumentable, e.g.
 117    :  // if it implies a memory access.
 118  E :  bool IsInstrumentable(const _Operand& op) {
 119  E :    switch (op.type) {
 120    :      case O_SMEM:
 121    :      case O_MEM:
 122  E :        return true;
 123    :  
 124    :      default:
 125  E :        return false;
 126    :    }
 127  E :  }
 128    :  
 129    :  // Returns true if opcode @p opcode is a special instruction.
 130    :  // Memory checks for special instructions (string instructions, instructions
 131    :  // with prefix, etc) are handled by calling specialized functions rather than
 132    :  // the standard memory checks.
 133  E :  bool IsSpecialInstruction(uint16_t opcode) {
 134  E :    switch (opcode) {
 135    :      case I_CMPS:
 136    :      case I_STOS:
 137    :      case I_MOVS:
 138  E :        return true;
 139    :  
 140    :      default:
 141  E :        return false;
 142    :    }
 143  E :  }
 144    :  
 145    :  // Decodes the first O_MEM or O_SMEM operand of @p instr, if any to the
 146    :  // corresponding Operand.
 147    :  bool DecodeMemoryAccess(const Instruction& instr,
 148    :      Operand* access,
 149  E :      AsanBasicBlockTransform::MemoryAccessInfo* info) {
 150  E :    DCHECK(access != NULL);
 151  E :    DCHECK(info != NULL);
 152  E :    const _DInst& repr = instr.representation();
 153    :  
 154    :    // Figure out which operand we're instrumenting.
 155  E :    size_t mem_op_id = -1;
 156  E :    if (IsInstrumentable(repr.ops[0]) && IsInstrumentable(repr.ops[1])) {
 157    :      // This happens with instructions like: MOVS [EDI], [ESI].
 158  E :      DCHECK(repr.ops[0].size == repr.ops[1].size);
 159  E :      mem_op_id = 0;
 160  E :    } else if (IsInstrumentable(repr.ops[0])) {
 161    :      // The first operand is instrumentable.
 162  E :      mem_op_id = 0;
 163  E :    } else if (IsInstrumentable(repr.ops[1])) {
 164    :      // The second operand is instrumentable.
 165  E :      mem_op_id = 1;
 166  E :    } else {
 167    :      // Neither of the first two operands is instrumentable.
 168  E :      return false;
 169    :    }
 170    :  
 171    :    // Determine the size of the access.
 172  E :    info->size = repr.ops[mem_op_id].size / 8;
 173    :  
 174    :    // Determine the kind of access (read/write/instr/repz).
 175  E :    if (FLAG_GET_PREFIX(repr.flags) & FLAG_REPNZ)
 176  i :      info->mode = AsanBasicBlockTransform::kRepnzAccess;
 177  E :    else if (FLAG_GET_PREFIX(repr.flags) & FLAG_REP)
 178  E :      info->mode = AsanBasicBlockTransform::kRepzAccess;
 179  E :    else if (IsSpecialInstruction(instr.opcode()))
 180  E :      info->mode = AsanBasicBlockTransform::kInstrAccess;
 181  E :    else if ((repr.flags & FLAG_DST_WR) && mem_op_id == 0) {
 182    :      // The first operand is written to.
 183  E :      info->mode = AsanBasicBlockTransform::kWriteAccess;
 184  E :    } else {
 185  E :      info->mode = AsanBasicBlockTransform::kReadAccess;
 186    :    }
 187    :  
 188    :    // Determine the opcode of this instruction (when needed).
 189    :    if (info->mode == AsanBasicBlockTransform::kRepnzAccess ||
 190    :        info->mode == AsanBasicBlockTransform::kRepzAccess ||
 191  E :        info->mode == AsanBasicBlockTransform::kInstrAccess) {
 192  E :      info->opcode = instr.opcode();
 193    :    }
 194    :  
 195    :    // Determine operand of the access.
 196  E :    if (repr.ops[mem_op_id].type == O_SMEM) {
 197    :      // Simple memory dereference with optional displacement.
 198  E :      Register base_reg(RegisterCode(repr.ops[mem_op_id].index - R_EAX));
 199    :      // Get the displacement for the operand.
 200  E :      Displacement displ = ComputeDisplacementForOperand(instr, mem_op_id);
 201    :  
 202  E :      *access = Operand(base_reg, displ);
 203  E :    } else if (repr.ops[0].type == O_MEM || repr.ops[1].type == O_MEM) {
 204    :      // Complex memory dereference.
 205  E :      Register index_reg(RegisterCode(repr.ops[mem_op_id].index - R_EAX));
 206  E :      core::ScaleFactor scale = core::kTimes1;
 207  E :      switch (repr.scale) {
 208    :        case 2:
 209  E :          scale = core::kTimes2;
 210  E :          break;
 211    :        case 4:
 212  E :          scale = core::kTimes4;
 213  E :          break;
 214    :        case 8:
 215  E :          scale = core::kTimes8;
 216    :          break;
 217    :        default:
 218    :          break;
 219    :      }
 220    :  
 221    :      // Get the displacement for the operand (if any).
 222  E :      Displacement displ = ComputeDisplacementForOperand(instr, mem_op_id);
 223    :  
 224    :      // Compute the full operand.
 225  E :      if (repr.base != R_NONE) {
 226  E :        Register base_reg(RegisterCode(repr.base - R_EAX));
 227  E :        if (displ.size() == core::kSizeNone) {
 228    :          // No displacement, it's a [base + index * scale] access.
 229  i :          *access = Operand(base_reg, index_reg, scale);
 230  i :        } else {
 231    :          // This is a [base + index * scale + displ] access.
 232  E :          *access = Operand(base_reg, index_reg, scale, displ);
 233    :        }
 234  E :      } else {
 235    :        // No base, this is an [index * scale + displ] access.
 236    :        // TODO(siggi): AFAIK, there's no encoding for [index * scale] without
 237    :        //    a displacement. If this assert fires, I'm proven wrong.
 238  E :        DCHECK_NE(core::kSizeNone, displ.size());
 239    :  
 240  E :        *access = Operand(index_reg, scale, displ);
 241    :      }
 242  E :    } else {
 243  i :      NOTREACHED();
 244  i :      return false;
 245    :    }
 246    :  
 247  E :    return true;
 248  E :  }
 249    :  
 250    :  // Use @p bb_asm to inject a hook to @p hook to instrument the access to the
 251    :  // address stored in the operand @p op.
 252    :  void InjectAsanHook(BasicBlockAssembler* bb_asm,
 253    :                      const AsanBasicBlockTransform::MemoryAccessInfo& info,
 254    :                      const Operand& op,
 255    :                      BlockGraph::Reference* hook,
 256  E :                      const LivenessAnalysis::State& state) {
 257  E :    DCHECK(hook != NULL);
 258    :  
 259    :    // TODO(etienneb): Use liveness information to implement more efficient hook.
 260    :  
 261    :    // Determine which kind of probe to inject.
 262    :    if (info.mode == AsanBasicBlockTransform::kReadAccess ||
 263  E :        info.mode == AsanBasicBlockTransform::kWriteAccess) {
 264    :      // The standard load/store probe assume the address is in EDX.
 265    :      // It restore the original version of EDX and cleanup the stack.
 266  E :      bb_asm->push(core::edx);
 267  E :      bb_asm->lea(core::edx, op);
 268  E :      bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
 269  E :    } else {
 270    :      // The special instruction probe take addresses directly in registers.
 271    :      // The probe doesn't have any effects on stack, registers and flags.
 272  E :      bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
 273    :    }
 274  E :  }
 275    :  
 276    :  typedef std::pair<BlockGraph::Block*, BlockGraph::Offset> ReferenceDest;
 277    :  typedef std::map<ReferenceDest, ReferenceDest> ReferenceMap;
 278    :  typedef std::set<BlockGraph::Block*> BlockSet;
 279    :  
 280    :  // For every block referencing @p dst_blocks, redirects any reference "ref" in
 281    :  // @p redirects to @p redirects[ref].
 282    :  void RedirectReferences(const BlockSet& dst_blocks,
 283  E :                          const ReferenceMap& redirects) {
 284    :    // For each block referenced by any source reference.
 285  E :    BlockSet::const_iterator dst_block_it = dst_blocks.begin();
 286  E :    for (; dst_block_it != dst_blocks.end(); ++dst_block_it) {
 287    :      // Iterate over all their referrers.
 288  E :      BlockGraph::Block* referred_block = *dst_block_it;
 289  E :      BlockGraph::Block::ReferrerSet referrers = referred_block->referrers();
 290  E :      BlockGraph::Block::ReferrerSet::iterator referrer_it = referrers.begin();
 291  E :      for (; referrer_it != referrers.end(); ++referrer_it) {
 292  E :        BlockGraph::Block* referrer = referrer_it->first;
 293    :  
 294    :        // Don't redirect references from PE parsed blocks. This actually ends up
 295    :        // redirecting the IAT entries as well in the worst case.
 296  E :        if (referrer->attributes() & BlockGraph::PE_PARSED)
 297  E :          continue;
 298    :  
 299    :        // And redirect any references that happen to match a source reference.
 300    :        BlockGraph::Block::ReferenceMap::const_iterator reference_it =
 301  E :            referrer->references().begin();
 302    :  
 303  E :        for (; reference_it != referrer->references().end(); ++reference_it) {
 304  E :          const BlockGraph::Reference& ref(reference_it->second);
 305  E :          ReferenceDest dest(std::make_pair(ref.referenced(), ref.offset()));
 306    :  
 307  E :          ReferenceMap::const_iterator it(redirects.find(dest));
 308  E :          if (it != redirects.end()) {
 309    :            BlockGraph::Reference new_reference(ref.type(),
 310    :                                                ref.size(),
 311    :                                                it->second.first,
 312    :                                                it->second.second,
 313  E :                                                0);
 314    :  
 315  E :            referrer->SetReference(reference_it->first, new_reference);
 316    :          }
 317  E :        }
 318  E :      }
 319  E :    }
 320  E :  }
 321    :  
 322    :  // Get the name of an asan check access function for an @p access_mode access.
 323    :  // @param info The memory access information, e.g. the size on a load/store,
 324    :  //     the instruction opcode and the kind of access.
 325    :  std::string GetAsanCheckAccessFunctionName(
 326  E :      AsanBasicBlockTransform::MemoryAccessInfo info) {
 327  E :    DCHECK(info.mode != AsanBasicBlockTransform::kNoAccess);
 328  E :    DCHECK(info.size != 0);
 329    :    DCHECK(info.mode == AsanBasicBlockTransform::kReadAccess ||
 330    :           info.mode == AsanBasicBlockTransform::kWriteAccess ||
 331  E :           info.opcode != 0);
 332    :  
 333  E :    const char* rep_str = NULL;
 334  E :    if (info.mode == AsanBasicBlockTransform::kRepzAccess)
 335  E :      rep_str = "_repz";
 336  E :    else if (info.mode == AsanBasicBlockTransform::kRepnzAccess)
 337  i :      rep_str = "_repnz";
 338  i :    else
 339  E :      rep_str = "";
 340    :  
 341  E :    const char* access_mode_str = NULL;
 342  E :    if (info.mode == AsanBasicBlockTransform::kReadAccess)
 343  E :      access_mode_str = "read";
 344  E :    else if (info.mode == AsanBasicBlockTransform::kWriteAccess)
 345  E :      access_mode_str = "write";
 346  E :    else
 347  E :      access_mode_str = reinterpret_cast<char*>(GET_MNEMONIC_NAME(info.opcode));
 348    :  
 349    :    std::string function_name =
 350    :        base::StringPrintf("asan_check%s_%d_byte_%s_access%s",
 351    :                            rep_str,
 352    :                            info.size,
 353    :                            access_mode_str,
 354  E :                            info.save_flags ? "" : "_no_flags");
 355  E :    StringToLowerASCII(&function_name);
 356  E :    return function_name.c_str();
 357  E :  }
 358    :  
 359    :  // Add the imports for the asan check access hooks to the block-graph.
 360    :  // @param hooks_param_vector A vector of hook parameter values.
 361    :  // @param default_stub_map Stubs for the asan check access functions.
 362    :  // @param import_module The module for which the import should be added.
 363    :  // @param check_access_hook_map The map where the reference to the imports
 364    :  //     should be stored.
 365    :  // @param block_graph The block-graph to populate.
 366    :  // @param header_block The block containing the module's DOS header of this
 367    :  //     block-graph.
 368    :  // @returns True on success, false otherwise.
 369    :  bool AddAsanCheckAccessHooks(
 370    :      const AccessHookParamVector& hook_param_vector,
 371    :      const AsanBasicBlockTransform::AsanDefaultHookMap& default_stub_map,
 372    :      ImportedModule* import_module,
 373    :      HookMap* check_access_hook_map,
 374    :      BlockGraph* block_graph,
 375  E :      BlockGraph::Block* header_block) {
 376  E :    DCHECK(import_module != NULL);
 377  E :    DCHECK(check_access_hook_map != NULL);
 378  E :    DCHECK(block_graph != NULL);
 379  E :    DCHECK(header_block != NULL);
 380    :  
 381    :    // Add the hooks to the import module.
 382    :  
 383    :    typedef std::map<AsanBasicBlockTransform::AsanHookMapEntryKey, size_t>
 384    :        HooksParamsToIdxMap;
 385  E :    HooksParamsToIdxMap hooks_params_to_idx;
 386    :  
 387  E :    AccessHookParamVector::const_iterator iter_params = hook_param_vector.begin();
 388  E :    for (; iter_params != hook_param_vector.end(); ++iter_params) {
 389    :      size_t symbol_idx = import_module->AddSymbol(
 390    :          GetAsanCheckAccessFunctionName(*iter_params),
 391  E :          ImportedModule::kAlwaysImport);
 392  E :      hooks_params_to_idx[*iter_params] = symbol_idx;
 393  E :    }
 394    :  
 395  E :    DCHECK_EQ(hooks_params_to_idx.size(), hook_param_vector.size());
 396    :  
 397    :    // Transforms the block-graph.
 398    :  
 399  E :    AddImportsTransform add_imports_transform;
 400  E :    add_imports_transform.AddModule(import_module);
 401    :  
 402  E :    if (!add_imports_transform.TransformBlockGraph(block_graph, header_block)) {
 403  i :      LOG(ERROR) << "Unable to add imports for Asan instrumentation DLL.";
 404  i :      return false;
 405    :    }
 406    :  
 407    :    // Get a reference to each hook and put it in the hooks map.
 408  E :    HooksParamsToIdxMap::iterator iter_hooks = hooks_params_to_idx.begin();
 409  E :    for (; iter_hooks != hooks_params_to_idx.end(); ++iter_hooks) {
 410  E :      BlockGraph::Reference import_reference;
 411    :      if (!import_module->GetSymbolReference(iter_hooks->second,
 412  E :                                             &import_reference)) {
 413  i :        LOG(ERROR) << "Unable to get import reference for Asan.";
 414  i :        return false;
 415    :      }
 416  E :      HookMap& hook_map = *check_access_hook_map;
 417  E :      hook_map[iter_hooks->first] = import_reference;
 418    :  
 419    :      // In a Chrome sandboxed process the NtMapViewOfSection function is
 420    :      // intercepted by the sandbox agent. This causes execution in the executable
 421    :      // before imports have been resolved, as the ntdll patch invokes into the
 422    :      // executable while resolving imports. As the Asan instrumentation directly
 423    :      // refers to the IAT entries we need to temporarily stub these function
 424    :      // until the Asan imports are resolved. To do this we need to make the IAT
 425    :      // entries for those functions point to a temporarily block and we need to
 426    :      // mark the image import descriptor for this DLL as bound.
 427    :      AsanBasicBlockTransform::AsanDefaultHookMap::const_iterator stub_reference =
 428  E :          default_stub_map.find(iter_hooks->first.mode);
 429  E :      if (stub_reference == default_stub_map.end()) {
 430  i :         LOG(ERROR) << "Could not find the default hook for "
 431    :                    << GetAsanCheckAccessFunctionName(iter_hooks->first)
 432    :                    << ".";
 433  i :        return false;
 434    :      }
 435    :  
 436    :      import_reference.referenced()->SetReference(import_reference.offset(),
 437  E :                                                  stub_reference->second);
 438  E :    }
 439    :  
 440  E :    return true;
 441  E :  }
 442    :  
 443    :  // Create a stub for the asan_check_access functions. For load/store, the stub
 444    :  // consists of a small block of code that restores the value of EDX and returns
 445    :  // to the caller. Otherwise, the stub do return.
 446    :  // @param block_graph The block-graph to populate with the stub.
 447    :  // @param stub_name The stub's name.
 448    :  // @param mode The kind of memory access.
 449    :  // @param reference Will receive the reference to the created hook.
 450    :  // @returns true on success, false otherwise.
 451    :  bool CreateHooksStub(BlockGraph* block_graph,
 452    :                       const base::StringPiece& stub_name,
 453    :                       AsanBasicBlockTransform::MemoryAccessMode mode,
 454  E :                       BlockGraph::Reference* reference) {
 455  E :    DCHECK(reference != NULL);
 456    :  
 457    :    // Find or create the section we put our thunks in.
 458    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
 459  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
 460    :  
 461  E :    if (thunk_section == NULL) {
 462  i :      LOG(ERROR) << "Unable to find or create .thunks section.";
 463  i :      return false;
 464    :    }
 465    :  
 466    :    std::string stub_name_with_id = base::StringPrintf(
 467  E :        "%.*s%d", stub_name.length(), stub_name.data(), mode);
 468    :  
 469    :    // Create the thunk for standard "load/store" (received address in EDX).
 470  E :    BasicBlockSubGraph bbsg;
 471    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 472  E :        stub_name_with_id, BlockGraph::CODE_BLOCK, thunk_section->id(), 1, 0);
 473    :  
 474  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(stub_name_with_id);
 475  E :    block_desc->basic_block_order.push_back(bb);
 476  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 477    :  
 478    :    if (mode == AsanBasicBlockTransform::kReadAccess ||
 479  E :        mode == AsanBasicBlockTransform::kWriteAccess) {
 480    :      // The thunk body restores the original value of EDX and cleans the stack on
 481    :      // return.
 482  E :      assm.mov(core::edx, Operand(core::esp, Displacement(4)));
 483  E :      assm.ret(4);
 484  E :    } else {
 485  E :      assm.ret();
 486    :    }
 487    :  
 488    :    // Condense into a block.
 489  E :    BlockBuilder block_builder(block_graph);
 490  E :    if (!block_builder.Merge(&bbsg)) {
 491  i :      LOG(ERROR) << "Failed to build thunk block.";
 492  i :      return NULL;
 493    :    }
 494    :  
 495    :    // Exactly one new block should have been created.
 496  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 497  E :    BlockGraph::Block* thunk = block_builder.new_blocks().front();
 498    :  
 499  E :    *reference = BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4, thunk, 0, 0);
 500    :  
 501  E :    return true;
 502  E :  }
 503    :  
 504    :  }  // namespace
 505    :  
 506    :  const char AsanBasicBlockTransform::kTransformName[] =
 507    :      "SyzyAsanBasicBlockTransform";
 508    :  
 509    :  bool AsanBasicBlockTransform::InstrumentBasicBlock(
 510  E :      BasicCodeBlock* basic_block, StackAccessMode stack_mode) {
 511  E :    DCHECK(basic_block != NULL);
 512    :  
 513    :    // Pre-compute liveness information for each instruction.
 514  E :    std::list<LivenessAnalysis::State> states;
 515  E :    LivenessAnalysis::State state;
 516  E :    if (use_liveness_analysis_) {
 517  E :      liveness_.GetStateAtExitOf(basic_block, &state);
 518    :  
 519    :      BasicBlock::Instructions::reverse_iterator rev_iter_inst =
 520  E :          basic_block->instructions().rbegin();
 521    :      BasicBlock::Instructions::const_reverse_iterator rev_iter_inst_end =
 522  E :          basic_block->instructions().rend();
 523  E :      for (; rev_iter_inst != rev_iter_inst_end; ++rev_iter_inst) {
 524  E :        const Instruction& instr = *rev_iter_inst;
 525  E :        liveness_.PropagateBackward(instr, &state);
 526  E :        states.push_front(state);
 527  E :      }
 528    :  
 529  E :      DCHECK_EQ(states.size(), basic_block->instructions().size());
 530    :    }
 531    :  
 532    :    // Get the memory accesses information for this basic block.
 533  E :    MemoryAccessAnalysis::State memory_state;
 534  E :    if (remove_redundant_checks_)
 535  E :      memory_accesses_.GetStateAtEntryOf(basic_block, &memory_state);
 536    :  
 537    :    // Process each instruction and inject a call to Asan when we find an
 538    :    // instrumentable memory access.
 539    :    BasicBlock::Instructions::iterator iter_inst =
 540  E :        basic_block->instructions().begin();
 541  E :    std::list<LivenessAnalysis::State>::iterator iter_state = states.begin();
 542  E :    for (; iter_inst != basic_block->instructions().end(); ++iter_inst) {
 543  E :      Operand operand(core::eax);
 544  E :      const Instruction& instr = *iter_inst;
 545  E :      const _DInst& repr = instr.representation();
 546    :  
 547    :      MemoryAccessInfo info;
 548  E :      info.mode = kNoAccess;
 549  E :      info.size = 0;
 550  E :      info.opcode = 0;
 551  E :      info.save_flags = true;
 552    :  
 553    :      // Get current instruction liveness information.
 554  E :      if (use_liveness_analysis_) {
 555  E :        state = *iter_state;
 556  E :        ++iter_state;
 557    :      }
 558    :  
 559    :      // When activated, skip redundant memory access check.
 560  E :      if (remove_redundant_checks_) {
 561  E :        bool need_memory_access_check = false;
 562  E :        if (memory_state.HasNonRedundantAccess(instr))
 563  E :          need_memory_access_check = true;
 564    :  
 565    :        // Update the memory accesses information for the current instruction.
 566  E :        memory_accesses_.PropagateForward(instr, &memory_state);
 567    :  
 568  E :        if (!need_memory_access_check)
 569  E :          continue;
 570    :      }
 571    :  
 572    :      // Insert hook for a standard instruction.
 573  E :      if (!DecodeMemoryAccess(instr, &operand, &info))
 574  E :        continue;
 575    :  
 576    :      // Bail if this is not a memory access.
 577  E :      if (info.mode == kNoAccess)
 578  i :        continue;
 579    :  
 580    :      // A basic block reference means that can be either a computed jump,
 581    :      // or a load from a case table. In either case it doesn't make sense
 582    :      // to instrument the access.
 583    :      if (operand.displacement().reference().referred_type() ==
 584  E :          BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK) {
 585  E :        continue;
 586    :      }
 587    :  
 588    :      // A block reference means this instruction is reading or writing to
 589    :      // a global variable or some such. It's viable to pad and align global
 590    :      // variables and to red-zone the padding, but without that, there's nothing
 591    :      // to gain by instrumenting these accesses.
 592    :      if (operand.displacement().reference().referred_type() ==
 593  E :          BasicBlockReference::REFERRED_TYPE_BLOCK) {
 594  E :        continue;
 595    :      }
 596    :  
 597    :      // Is this an instruction we should be instrumenting.
 598  E :      if (!ShouldInstrumentOpcode(repr.opcode))
 599  E :        continue;
 600    :  
 601    :      // If there are no unconventional manipulations of the stack frame, we can
 602    :      // skip instrumenting stack-based memory access (based on ESP or EBP).
 603    :      // Conventionally, accesses through ESP/EBP are always on stack.
 604    :      if (stack_mode == kSafeStackAccess &&
 605    :          (operand.base() == core::kRegisterEsp ||
 606  E :           operand.base() == core::kRegisterEbp)) {
 607  E :        continue;
 608    :      }
 609    :  
 610    :      // We do not instrument memory accesses through special segments.
 611    :      // FS is used for thread local specifics and GS for CPU info.
 612  E :      uint8_t segment = SEGMENT_GET(repr.segment);
 613  E :      if (segment == R_FS || segment == R_GS)
 614  E :        continue;
 615    :  
 616    :      // Finally, don't instrument any filtered instructions.
 617  E :      if (IsFiltered(*iter_inst))
 618  E :        continue;
 619    :  
 620    :      // Create a BasicBlockAssembler to insert new instruction.
 621  E :      BasicBlockAssembler bb_asm(iter_inst, &basic_block->instructions());
 622    :  
 623    :      // Configure the assembler to copy the SourceRange information of the
 624    :      // current instrumented instruction into newly created instructions. This is
 625    :      // a hack to allow valid stack walking and better error reporting, but
 626    :      // breaks the 1:1 OMAP mapping and may confuse some debuggers.
 627  E :      if (debug_friendly_)
 628  E :        bb_asm.set_source_range(instr.source_range());
 629    :  
 630    :      if (use_liveness_analysis_ &&
 631  E :          (info.mode == kReadAccess || info.mode == kWriteAccess)) {
 632    :        // Use the liveness information to skip saving the flags if possible.
 633  E :        info.save_flags = state.AreArithmeticFlagsLive();
 634    :      }
 635    :  
 636    :      // Insert hook for standard instructions.
 637  E :      AsanHookMap::iterator hook = check_access_hooks_->find(info);
 638  E :      if (hook == check_access_hooks_->end()) {
 639  i :        LOG(ERROR) << "Invalid access : " << GetAsanCheckAccessFunctionName(info);
 640  i :        return false;
 641    :      }
 642    :  
 643    :      // Instrument this instruction.
 644  E :      InjectAsanHook(&bb_asm, info, operand, &hook->second, state);
 645  E :    }
 646    :  
 647  E :    DCHECK(iter_state == states.end());
 648    :  
 649  E :    return true;
 650  E :  }
 651    :  
 652    :  bool AsanBasicBlockTransform::TransformBasicBlockSubGraph(
 653  E :      BlockGraph* block_graph, BasicBlockSubGraph* subgraph) {
 654  E :    DCHECK(block_graph != NULL);
 655  E :    DCHECK(subgraph != NULL);
 656    :  
 657    :    // Perform a global liveness analysis.
 658  E :    if (use_liveness_analysis_)
 659  E :      liveness_.Analyze(subgraph);
 660    :  
 661    :    // Perform a redundant memory access analysis.
 662  E :    if (remove_redundant_checks_)
 663  E :      memory_accesses_.Analyze(subgraph);
 664    :  
 665    :    // Determines if this subgraph uses unconventional stack pointer
 666    :    // manipulations.
 667  E :    StackAccessMode stack_mode = kUnsafeStackAccess;
 668  E :    if (!block_graph::HasUnexpectedStackFrameManipulation(subgraph))
 669  E :      stack_mode = kSafeStackAccess;
 670    :  
 671    :    // Iterates through each basic block and instruments it.
 672    :    BasicBlockSubGraph::BBCollection::iterator it =
 673  E :        subgraph->basic_blocks().begin();
 674  E :    for (; it != subgraph->basic_blocks().end(); ++it) {
 675  E :      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
 676  E :      if (bb != NULL && !InstrumentBasicBlock(bb, stack_mode))
 677  i :        return false;
 678  E :    }
 679  E :    return true;
 680  E :  }
 681    :  
 682    :  const char AsanTransform::kTransformName[] = "SyzyAsanTransform";
 683    :  
 684    :  const char AsanTransform::kAsanHookStubName[] = "asan_hook_stub";
 685    :  
 686    :  const char AsanTransform::kSyzyAsanDll[] = "asan_rtl.dll";
 687    :  
 688    :  AsanTransform::AsanTransform()
 689    :      : asan_dll_name_(kSyzyAsanDll),
 690    :        debug_friendly_(false),
 691    :        use_liveness_analysis_(false),
 692    :        remove_redundant_checks_(false),
 693  E :        check_access_hooks_ref_() {
 694  E :  }
 695    :  
 696    :  bool AsanTransform::PreBlockGraphIteration(BlockGraph* block_graph,
 697  E :                                             BlockGraph::Block* header_block) {
 698  E :    bool already_instrumented = false;
 699    :    // Ensure that this image has not already been instrumented.
 700  E :    if (!pe::HasImportEntry(header_block, kSyzyAsanDll, &already_instrumented)) {
 701  i :      LOG(ERROR) << "Unable to check if the image is already instrumented.";
 702  i :      return false;
 703    :    }
 704    :  
 705  E :    if (already_instrumented) {
 706  i :      LOG(ERROR) << "The image is already instrumented.";
 707  i :      return false;
 708    :    }
 709    :  
 710  E :    AccessHookParamVector access_hook_param_vec;
 711  E :    AsanBasicBlockTransform::AsanDefaultHookMap default_stub_map;
 712    :  
 713    :    // Create the hook stub for read/write instructions.
 714  E :    BlockGraph::Reference read_write_hook;
 715    :    if (!CreateHooksStub(block_graph, kAsanHookStubName,
 716    :                         AsanBasicBlockTransform::kReadAccess,
 717  E :                        &read_write_hook)) {
 718  i :      return false;
 719    :    }
 720    :  
 721    :    // Create the hook stub for strings instructions.
 722  E :    BlockGraph::Reference instr_hook;
 723    :    if (!CreateHooksStub(block_graph, kAsanHookStubName,
 724    :                         AsanBasicBlockTransform::kInstrAccess,
 725  E :                        &instr_hook)) {
 726  i :      return false;
 727    :    }
 728    :  
 729    :    // Map each memory access kind to an appropriate stub.
 730  E :    default_stub_map[AsanBasicBlockTransform::kReadAccess] = read_write_hook;
 731  E :    default_stub_map[AsanBasicBlockTransform::kWriteAccess] = read_write_hook;
 732  E :    default_stub_map[AsanBasicBlockTransform::kInstrAccess] = instr_hook;
 733  E :    default_stub_map[AsanBasicBlockTransform::kRepzAccess] = instr_hook;
 734  E :    default_stub_map[AsanBasicBlockTransform::kRepnzAccess] = instr_hook;
 735    :  
 736    :    // Add an import entry for the ASAN runtime.
 737  E :    ImportedModule import_module(asan_dll_name_);
 738    :  
 739    :    // Import the hooks for the read/write accesses.
 740  E :    for (int access_size = 1; access_size <= 32; access_size *= 2) {
 741    :      MemoryAccessInfo read_info =
 742  E :          { AsanBasicBlockTransform::kReadAccess, access_size, 0, true };
 743  E :      access_hook_param_vec.push_back(read_info);
 744  E :      if (use_liveness_analysis()) {
 745  E :        read_info.save_flags = false;
 746  E :        access_hook_param_vec.push_back(read_info);
 747    :      }
 748    :  
 749    :      MemoryAccessInfo write_info =
 750  E :          { AsanBasicBlockTransform::kWriteAccess, access_size, 0, true };
 751  E :      access_hook_param_vec.push_back(write_info);
 752  E :      if (use_liveness_analysis()) {
 753  E :        write_info.save_flags = false;
 754  E :        access_hook_param_vec.push_back(write_info);
 755    :      }
 756  E :    }
 757    :  
 758    :    // Import the hooks for the read/write 10-bytes accesses.
 759    :    MemoryAccessInfo read_info_10 =
 760  E :        { AsanBasicBlockTransform::kReadAccess, 10, 0, true };
 761  E :    access_hook_param_vec.push_back(read_info_10);
 762  E :    if (use_liveness_analysis()) {
 763  E :      read_info_10.save_flags = false;
 764  E :      access_hook_param_vec.push_back(read_info_10);
 765    :    }
 766    :  
 767    :    MemoryAccessInfo write_info_10 =
 768  E :        { AsanBasicBlockTransform::kWriteAccess, 10, 0, true };
 769  E :    access_hook_param_vec.push_back(write_info_10);
 770  E :    if (use_liveness_analysis()) {
 771  E :      write_info_10.save_flags = false;
 772  E :      access_hook_param_vec.push_back(write_info_10);
 773    :    }
 774    :  
 775    :    // Import the hooks for strings/prefix memory accesses.
 776  E :    const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
 777  E :    int strings_length = sizeof(strings)/sizeof(_InstructionType);
 778    :  
 779  E :    for (int access_size = 1; access_size <= 4; access_size *= 2) {
 780  E :      for (int inst = 0; inst < strings_length; ++inst) {
 781    :        MemoryAccessInfo repz_inst_info = {
 782  E :           AsanBasicBlockTransform::kRepzAccess,
 783  E :           access_size,
 784  E :           strings[inst],
 785    :           true
 786  E :        };
 787  E :        access_hook_param_vec.push_back(repz_inst_info);
 788    :  
 789    :        MemoryAccessInfo inst_info = {
 790  E :            AsanBasicBlockTransform::kInstrAccess,
 791  E :            access_size,
 792  E :            strings[inst],
 793    :            true
 794  E :        };
 795  E :        access_hook_param_vec.push_back(inst_info);
 796  E :      }
 797  E :    }
 798    :  
 799    :    if (!AddAsanCheckAccessHooks(access_hook_param_vec,
 800    :                                 default_stub_map,
 801    :                                 &import_module,
 802    :                                 &check_access_hooks_ref_,
 803    :                                 block_graph,
 804  E :                                 header_block)) {
 805  i :      return false;
 806    :    }
 807  E :    return true;
 808  E :  }
 809    :  
 810    :  bool AsanTransform::OnBlock(BlockGraph* block_graph,
 811  E :                              BlockGraph::Block* block) {
 812  E :    DCHECK(block_graph != NULL);
 813  E :    DCHECK(block != NULL);
 814  E :    if (block->type() != BlockGraph::CODE_BLOCK)
 815  E :      return true;
 816    :  
 817  E :    if (!pe::CodeBlockIsBasicBlockDecomposable(block))
 818  E :      return true;
 819    :  
 820    :    // Use the filter that was passed to us for our child transform.
 821  E :    AsanBasicBlockTransform transform(&check_access_hooks_ref_);
 822  E :    transform.set_debug_friendly(debug_friendly());
 823  E :    transform.set_use_liveness_analysis(use_liveness_analysis());
 824  E :    transform.set_remove_redundant_checks(remove_redundant_checks());
 825  E :    transform.set_filter(filter());
 826    :  
 827  E :    if (!ApplyBasicBlockSubGraphTransform(&transform, block_graph, block, NULL))
 828  i :      return false;
 829    :  
 830  E :    return true;
 831  E :  }
 832    :  
 833    :  bool AsanTransform::PostBlockGraphIteration(BlockGraph* block_graph,
 834  E :                                              BlockGraph::Block* header_block) {
 835    :    // This function redirects the heap-related kernel32 imports to point to a set
 836    :    // of "override" imports in the ASAN runtime.
 837    :  
 838    :    static const size_t kInvalidIndex = -1;
 839    :  
 840    :    struct Kernel32ImportRedirect {
 841    :      const char* import_name;
 842    :      const char* redirect_name;
 843    :    };
 844    :    static const Kernel32ImportRedirect kKernel32Redirects[] = {
 845    :      { "HeapCreate", "asan_HeapCreate" },
 846    :      { "HeapDestroy", "asan_HeapDestroy" },
 847    :      { "HeapAlloc", "asan_HeapAlloc" },
 848    :      { "HeapReAlloc", "asan_HeapReAlloc" },
 849    :      { "HeapFree", "asan_HeapFree" },
 850    :      { "HeapSize", "asan_HeapSize" },
 851    :      { "HeapValidate", "asan_HeapValidate" },
 852    :      { "HeapCompact", "asan_HeapCompact" },
 853    :      { "HeapLock", "asan_HeapLock" },
 854    :      { "HeapUnlock", "asan_HeapUnlock" },
 855    :      { "HeapWalk", "asan_HeapWalk" },
 856    :      { "HeapSetInformation", "asan_HeapSetInformation" },
 857    :      { "HeapQueryInformation", "asan_HeapQueryInformation" },
 858    :    };
 859    :  
 860    :    // Initialize the module info for querying kernel32 imports.
 861  E :    std::vector<std::pair<size_t, size_t>> override_indexes;
 862  E :    ImportedModule module_kernel32("kernel32.dll");
 863  E :    for (size_t i = 0; i < arraysize(kKernel32Redirects); ++i) {
 864    :      size_t kernel32_index =
 865    :          module_kernel32.AddSymbol(kKernel32Redirects[i].import_name,
 866  E :                                    ImportedModule::kFindOnly);
 867  E :      override_indexes.push_back(std::make_pair(kernel32_index, kInvalidIndex));
 868  E :    }
 869    :  
 870    :    // Query the kernel32 imports.
 871  E :    AddImportsTransform find_kernel_imports;
 872  E :    find_kernel_imports.AddModule(&module_kernel32);
 873  E :    if (!find_kernel_imports.TransformBlockGraph(block_graph, header_block)) {
 874  i :      LOG(ERROR) << "Unable to find kernel32 imports for redirection.";
 875  i :      return false;
 876    :    }
 877    :  
 878    :    // Add ASAN imports for those kernel32 functions we found. These will later
 879    :    // be redirected.
 880  E :    ImportedModule module_asan(asan_dll_name_);
 881  E :    for (size_t i = 0; i < arraysize(kKernel32Redirects); ++i) {
 882  E :      size_t kernel32_index = override_indexes[i].first;
 883  E :      if (module_kernel32.SymbolIsImported(kernel32_index)) {
 884    :        size_t asan_index = module_asan.AddSymbol(
 885    :            kKernel32Redirects[i].redirect_name,
 886  E :            ImportedModule::kAlwaysImport);
 887  E :        DCHECK_EQ(kInvalidIndex, override_indexes[i].second);
 888  E :        override_indexes[i].second = asan_index;
 889    :      }
 890  E :    }
 891    :  
 892    :    // Another transform can safely be run without invalidating the results
 893    :    // stored in module_kernel32, as additions to the IAT will strictly be
 894    :    // performed at the end.
 895  E :    AddImportsTransform add_imports_transform;
 896  E :    add_imports_transform.AddModule(&module_asan);
 897  E :    if (!add_imports_transform.TransformBlockGraph(block_graph, header_block)) {
 898  i :      LOG(ERROR) << "Unable to add imports for import redirection.";
 899  i :      return false;
 900    :    }
 901    :  
 902    :    // Keeps track of all the blocks referenced by the original references.
 903  E :    BlockSet dst_blocks;
 904    :    // Stores the reference mapping we want to rewrite.
 905  E :    ReferenceMap reference_redirect_map;
 906    :  
 907  E :    for (size_t i = 0; i < override_indexes.size(); ++i) {
 908    :      // Symbols that aren't imported don't need to be redirected.
 909  E :      size_t kernel32_index = override_indexes[i].first;
 910  E :      size_t asan_index = override_indexes[i].second;
 911  E :      if (!module_kernel32.SymbolIsImported(kernel32_index)) {
 912  E :        DCHECK_EQ(kInvalidIndex, asan_index);
 913  E :        continue;
 914    :      }
 915    :  
 916  E :      DCHECK_NE(kInvalidIndex, asan_index);
 917  E :      BlockGraph::Reference src;
 918  E :      BlockGraph::Reference dst;
 919    :      if (!module_kernel32.GetSymbolReference(kernel32_index, &src) ||
 920  E :          !module_asan.GetSymbolReference(asan_index, &dst)) {
 921  i :         NOTREACHED() << "Unable to get references after a successful transform.";
 922  i :        return false;
 923    :      }
 924    :  
 925    :      // Add the destination block to the set of referred blocks.
 926  E :      dst_blocks.insert(src.referenced());
 927    :      reference_redirect_map.insert(
 928    :          std::make_pair(ReferenceDest(src.referenced(), src.offset()),
 929  E :                         ReferenceDest(dst.referenced(), dst.offset())));
 930  E :    }
 931    :  
 932  E :    RedirectReferences(dst_blocks, reference_redirect_map);
 933    :  
 934    :    // The timestamp 1 corresponds to Thursday, 01 Jan 1970 00:00:01 GMT. Setting
 935    :    // the timestamp of the image import descriptor to this value allows us to
 936    :    // temporarily bind the library until the loader finishes loading this module.
 937    :    // As the value is far in the past this means that the entries in the IAT for
 938    :    // this module will all be replace by pointers into the actual library.
 939    :    static const size_t kDateInThePast = 1;
 940    :  
 941    :    // We need to bind the IAT for our module to make sure the stub is used until
 942    :    // the sandbox lets the loader finish patching the IAT entries.
 943  E :    module_asan.import_descriptor()->TimeDateStamp = kDateInThePast;
 944    :  
 945  E :    return true;
 946  E :  }
 947    :  
 948    :  bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
 949  E :                 const AsanBasicBlockTransform::MemoryAccessInfo& right) {
 950  E :    if (left.mode != right.mode)
 951  E :      return left.mode < right.mode;
 952  E :    if (left.size != right.size)
 953  E :      return left.size < right.size;
 954  E :    if (left.save_flags != right.save_flags)
 955  E :      return left.save_flags < right.save_flags;
 956  E :    return left.opcode < right.opcode;
 957  E :  }
 958    :  
 959    :  }  // namespace transforms
 960    :  }  // namespace instrument

Coverage information generated Thu Jul 04 09:34:53 2013.