Coverage for /Syzygy/agent/asan/rtl_utils.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.1%67690.C++source

Line-by-line coverage:

   1    :  // Copyright 2014 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/agent/asan/rtl_utils.h"
  16    :  
  17    :  #include <memory>
  18    :  
  19    :  #include "base/bind.h"
  20    :  #include "base/callback.h"
  21    :  #include "base/logging.h"
  22    :  #include "base/debug/alias.h"
  23    :  #include "syzygy/agent/asan/heap_checker.h"
  24    :  #include "syzygy/agent/asan/runtime.h"
  25    :  #include "syzygy/agent/asan/shadow.h"
  26    :  #include "syzygy/agent/common/scoped_last_error_keeper.h"
  27    :  #include "syzygy/agent/common/stack_capture.h"
  28    :  
  29    :  namespace {
  30    :  
  31    :  // The asan runtime manager.
  32    :  agent::asan::AsanRuntime* asan_runtime = NULL;
  33    :  
  34    :  }  // namespace
  35    :  
  36    :  namespace agent {
  37    :  namespace asan {
  38    :  
  39  E :  void SetAsanRuntimeInstance(AsanRuntime* runtime) {
  40  E :    asan_runtime = runtime;
  41  E :  }
  42    :  
  43    :  void ReportBadMemoryAccess(const void* location,
  44    :                             AccessMode access_mode,
  45    :                             size_t access_size,
  46  E :                             const AsanContext& asan_context) {
  47    :    // Capture the context and restore the value of the register as before calling
  48    :    // the asan hook.
  49    :  
  50    :    // Save the last error value so this function will be able to restore it.
  51  E :    agent::common::ScopedLastErrorKeeper scoped_last_error_keeper;
  52    :  
  53    :    // We keep a structure with all the useful information about this bad access
  54    :    // on the stack.
  55  E :    AsanErrorInfo bad_access_info = {};
  56    :  
  57    :    // We need to call ::RtlCaptureContext if we want SegSS and SegCS to be
  58    :    // properly set.
  59  E :    ::RtlCaptureContext(&bad_access_info.context);
  60  E :    bad_access_info.context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
  61    :  
  62    :    // Restore the original value of the registers.
  63    :  #ifdef _WIN64
  64    :    // TODO(loskutov): add more x64 registers or eliminate this piece of code.
  65    :    bad_access_info.context.Rip = asan_context.original_rip;
  66    :    bad_access_info.context.Rax = asan_context.original_rax;
  67    :    bad_access_info.context.Rcx = asan_context.original_rcx;
  68    :    bad_access_info.context.Rdx = asan_context.original_rdx;
  69    :    bad_access_info.context.Rbx = asan_context.original_rbx;
  70    :    bad_access_info.context.Rbp = asan_context.original_rbp;
  71    :    bad_access_info.context.Rsp = asan_context.original_rsp;
  72    :    bad_access_info.context.Rsi = asan_context.original_rsi;
  73    :    bad_access_info.context.Rdi = asan_context.original_rdi;
  74    :  #else
  75  E :    bad_access_info.context.Eip = asan_context.original_eip;
  76  E :    bad_access_info.context.Eax = asan_context.original_eax;
  77  E :    bad_access_info.context.Ecx = asan_context.original_ecx;
  78  E :    bad_access_info.context.Edx = asan_context.original_edx;
  79  E :    bad_access_info.context.Ebx = asan_context.original_ebx;
  80  E :    bad_access_info.context.Ebp = asan_context.original_ebp;
  81  E :    bad_access_info.context.Esp = asan_context.original_esp;
  82  E :    bad_access_info.context.Esi = asan_context.original_esi;
  83  E :    bad_access_info.context.Edi = asan_context.original_edi;
  84    :  #endif
  85  E :    bad_access_info.context.EFlags = asan_context.original_eflags;
  86    :  
  87  E :    common::StackCapture stack;
  88  E :    stack.InitFromStack();
  89    :    // We need to use the relative stack id so that for the same stack trace we
  90    :    // get the same value every time even if the modules are loaded at a different
  91    :    // base address.
  92    :    //
  93    :    // Check if we can ignore this error.
  94  E :    if (asan_runtime->ShouldIgnoreError(stack.relative_stack_id()))
  95  i :      return;
  96    :  
  97  E :    bad_access_info.crash_stack_id = stack.relative_stack_id();
  98  E :    bad_access_info.location = location;
  99  E :    bad_access_info.access_mode = access_mode;
 100  E :    bad_access_info.access_size = access_size;
 101  E :    bad_access_info.error_type = UNKNOWN_BAD_ACCESS;
 102  E :    bad_access_info.block_info.alloc_stack_size = 0U;
 103  E :    bad_access_info.block_info.alloc_tid = 0U;
 104  E :    bad_access_info.block_info.free_stack_size = 0U;
 105  E :    bad_access_info.block_info.free_tid = 0U;
 106  E :    bad_access_info.block_info.milliseconds_since_free = 0U;
 107  E :    bad_access_info.corrupt_ranges = NULL;
 108  E :    bad_access_info.corrupt_range_count = 0;
 109    :  
 110    :    // Make sure this structure is not optimized out.
 111  E :    base::debug::Alias(&bad_access_info);
 112    :  
 113    :    // TODO(sebmarchand): Check if the heap is corrupt and store the information
 114    :    //     about the corrupt blocks if it's the case.
 115  E :    bad_access_info.heap_is_corrupt = false;
 116    :  
 117  E :    asan_runtime->GetBadAccessInformation(&bad_access_info);
 118    :  
 119    :    // Accesses to the first 64k of the memory (invalid address) should not be
 120    :    // reported by SyzyASAN unless we detect a heap corruption or if it has been
 121    :    // requested by the user. By returning early, we let the unhandled exception
 122    :    // filter do the heap corruption check. The check is not done here because we
 123    :    // don't want to duplicate the work.
 124  E :    if (!asan_runtime->params().report_invalid_accesses &&
 125    :        bad_access_info.location <
 126    :            reinterpret_cast<void*>(Shadow::kAddressLowerBound)) {
 127  E :      return;
 128    :    }
 129    :  
 130    :    // Report this error.
 131  E :    asan_runtime->OnError(&bad_access_info);
 132  E :  }
 133    :  
 134  E :  void ContextToAsanContext(const CONTEXT& context, AsanContext* asan_context) {
 135  E :    DCHECK(asan_context != NULL);
 136    :  #ifdef _WIN64
 137    :    asan_context->original_rax = context.Rax;
 138    :    asan_context->original_rbp = context.Rbp;
 139    :    asan_context->original_rbx = context.Rbx;
 140    :    asan_context->original_rcx = context.Rcx;
 141    :    asan_context->original_rdi = context.Rdi;
 142    :    asan_context->original_rdx = context.Rdx;
 143    :    asan_context->original_rip = context.Rip;
 144    :    asan_context->original_rsi = context.Rsi;
 145    :    asan_context->original_rsp = context.Rsp;
 146    :  #else
 147  E :    asan_context->original_eax = context.Eax;
 148  E :    asan_context->original_ebp = context.Ebp;
 149  E :    asan_context->original_ebx = context.Ebx;
 150  E :    asan_context->original_ecx = context.Ecx;
 151  E :    asan_context->original_edi = context.Edi;
 152  E :    asan_context->original_edx = context.Edx;
 153  E :    asan_context->original_eip = context.Eip;
 154  E :    asan_context->original_esi = context.Esi;
 155  E :    asan_context->original_esp = context.Esp;
 156    :  #endif
 157  E :    asan_context->original_eflags = context.EFlags;
 158  E :  }
 159    :  
 160  E :  void ReportBadAccess(const void* location, AccessMode access_mode) {
 161  E :    AsanContext asan_context = {};
 162  E :    CONTEXT context = {};
 163  E :    ::RtlCaptureContext(&context);
 164  E :    ContextToAsanContext(context, &asan_context);
 165  E :    ReportBadMemoryAccess(location, access_mode, 1U, asan_context);
 166  E :  }
 167    :  
 168    :  void TestMemoryRange(Shadow* shadow,
 169    :                       const uint8_t* memory,
 170    :                       size_t size,
 171  E :                       AccessMode access_mode) {
 172  E :    if (!shadow || size == 0U)
 173  i :      return;
 174    :  
 175    :    // TODO(sebmarchand): This approach is pretty limited because it only checks
 176    :    //     if the first and the last elements are accessible. Once we have the
 177    :    //     plumbing in place we should benchmark a check that looks at each
 178    :    //     address to be touched (via the shadow memory, 8 bytes at a time).
 179  E :    if (!shadow->IsAccessible(memory) ||
 180    :        !shadow->IsAccessible(memory + size - 1)) {
 181  E :      const void* location = shadow->FindFirstPoisonedByte(memory, size);
 182    :      // If this check hits, either you've lucked on a time-of-check race, and
 183    :      // there's a genuine bug in the call stack above, or else there's a bug
 184    :      // in the runtime.
 185  E :      CHECK(location != nullptr);
 186    :  
 187  E :      ReportBadAccess(location, access_mode);
 188    :    }
 189  E :  }
 190    :  
 191    :  }  // namespace asan
 192    :  }  // namespace agent

Coverage information generated Fri Jul 29 11:00:21 2016.