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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.9%52560.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    :  #include "syzygy/agent/asan/memory_interceptors.h"
  15    :  
  16    :  #include <stdint.h>
  17    :  
  18    :  #include "base/logging.h"
  19    :  #include "base/macros.h"
  20    :  #include "syzygy/agent/asan/rtl_utils.h"
  21    :  #include "syzygy/agent/asan/shadow.h"
  22    :  
  23    :  using agent::asan::Shadow;
  24    :  
  25    :  namespace agent {
  26    :  namespace asan {
  27    :  namespace {
  28    :  
  29  E :  RedirectEntryCallback redirect_entry_callback;
  30    :  
  31    :  // The global shadow memory that is used by the memory interceptors.
  32    :  // This is only used by interceptors that make use of the Shadow API.
  33    :  // Interceptors with direct reference (the basic read/write probes) to the
  34    :  // shadow memory must be patched directly.
  35    :  Shadow* memory_interceptor_shadow_ = nullptr;
  36    :  
  37    :  }  // namespace
  38    :  
  39  E :  Shadow* SetMemoryInterceptorShadow(Shadow* shadow) {
  40  E :    Shadow* old_shadow = memory_interceptor_shadow_;
  41  E :    memory_interceptor_shadow_ = shadow;
  42  E :    return old_shadow;
  43  E :  }
  44    :  
  45    :  const MemoryAccessorVariants kMemoryAccessorVariants[] = {
  46    :  #define ENUM_MEM_INTERCEPT_FUNCTION_VARIANTS(access_size, access_mode_str,   \
  47    :                                               access_mode_value)              \
  48    :    { "asan_check_" #access_size "_byte_" #access_mode_str,                    \
  49    :      asan_redirect_##access_size##_byte_##access_mode_str, asan_no_check,     \
  50    :      asan_check_##access_size##_byte_##access_mode_str##_2gb,                 \
  51    :      asan_check_##access_size##_byte_##access_mode_str##_4gb                  \
  52    :    },                                                                         \
  53    :    { "asan_check_" #access_size "_byte_" #access_mode_str "_no_flags",        \
  54    :       asan_redirect_##access_size##_byte_##access_mode_str##_no_flags,        \
  55    :       asan_no_check,                                                          \
  56    :       asan_check_##access_size##_byte_##access_mode_str##_no_flags_2gb,       \
  57    :       asan_check_##access_size##_byte_##access_mode_str##_no_flags_4gb},
  58    :  
  59    :    ASAN_MEM_INTERCEPT_FUNCTIONS(ENUM_MEM_INTERCEPT_FUNCTION_VARIANTS)
  60    :  
  61    :  #undef ENUM_MEM_INTERCEPT_FUNCTION_VARIANTS
  62    :  
  63    :  #define ENUM_STRING_INTERCEPT_FUNCTION_VARIANTS( \
  64    :      func, prefix, counter, dst_mode, src_mode, access_size, compare)         \
  65    :    { "asan_check" #prefix #access_size "_byte_" #func "_access",              \
  66    :      asan_redirect ## prefix ## access_size ## _byte_ ## func ## _access,     \
  67    :      asan_string_no_check,                                                    \
  68    :      asan_check ## prefix ## access_size ## _byte_ ## func ## _access,        \
  69    :      asan_check ## prefix ## access_size ## _byte_ ## func ## _access,        \
  70    :    },
  71    :  
  72    :    ASAN_STRING_INTERCEPT_FUNCTIONS(ENUM_STRING_INTERCEPT_FUNCTION_VARIANTS)
  73    :  
  74    :  #undef ENUM_STRING_INTERCEPT_FUNCTION_VARIANTS
  75    :  };
  76    :  
  77    :  const size_t kNumMemoryAccessorVariants = arraysize(kMemoryAccessorVariants);
  78    :  
  79  E :  void SetRedirectEntryCallback(const RedirectEntryCallback& callback) {
  80  E :    redirect_entry_callback = callback;
  81  E :  }
  82    :  
  83    :  // Check if the memory location is accessible and report an error on bad memory
  84    :  // accesses.
  85    :  // @param location The memory address of the access.
  86    :  // @param access_mode The mode of the access.
  87    :  // @param access_size The size of the access.
  88    :  // @param context The registers context of the access.
  89    :  void CheckMemoryAccess(void* location,
  90    :                         AccessMode access_mode,
  91    :                         size_t access_size,
  92  E :                         const AsanContext& context) {
  93    :    if (memory_interceptor_shadow_ &&
  94  E :        !memory_interceptor_shadow_->IsAccessible(location)) {
  95  E :      ReportBadMemoryAccess(location, access_mode, access_size, context);
  96    :    }
  97  E :  }
  98    :  
  99    :  // The slow path relies on the fact that the shadow memory non accessible byte
 100    :  // mask has its upper bit set to 1.
 101    :  static_assert((kHeapNonAccessibleMarkerMask & (1 << 7)) != 0,
 102    :                "Asan shadow mask upper bit is 0.");
 103    :  
 104    :  extern "C" {
 105    :  
 106    :  // Check if the memory accesses done by a string instructions are valid.
 107    :  // @param dst The destination memory address of the access.
 108    :  // @param dst_access_mode The destination mode of the access.
 109    :  // @param src The source memory address of the access.
 110    :  // @param src_access_mode The source mode of the access.
 111    :  // @param length The number of memory accesses.
 112    :  // @param access_size The size of each the access in byte.
 113    :  // @param increment The increment to move dst/src after each access.
 114    :  // @param compare Flag to activate shortcut of the execution on difference.
 115    :  // @param context The registers context of the access.
 116    :  void asan_check_strings_memory_accesses(uint8* dst,
 117    :                                          AccessMode dst_access_mode,
 118    :                                          uint8* src,
 119    :                                          AccessMode src_access_mode,
 120    :                                          uint32 length,
 121    :                                          size_t access_size,
 122    :                                          int32 increment,
 123    :                                          bool compare,
 124  E :                                          const AsanContext& context) {
 125  E :    int32 offset = 0;
 126    :  
 127  E :    for (uint32 i = 0; i < length; ++i) {
 128    :      // Check next memory location at src[offset].
 129  E :      if (src_access_mode != agent::asan::ASAN_UNKNOWN_ACCESS)
 130  E :        CheckMemoryAccess(&src[offset], src_access_mode, access_size, context);
 131    :  
 132    :      // Check next memory location at dst[offset].
 133  E :      if (dst_access_mode != agent::asan::ASAN_UNKNOWN_ACCESS)
 134  E :        CheckMemoryAccess(&dst[offset], dst_access_mode, access_size, context);
 135    :  
 136    :      // For CMPS instructions, we shortcut the execution of prefix REPZ when
 137    :      // memory contents differ.
 138  E :      if (compare) {
 139  E :        uint32 src_content = 0;
 140  E :        uint32 dst_content = 0;
 141  E :        switch (access_size) {
 142    :        case 4:
 143  E :          src_content = *reinterpret_cast<uint32*>(&src[offset]);
 144  E :          dst_content = *reinterpret_cast<uint32*>(&dst[offset]);
 145  E :          break;
 146    :        case 2:
 147  E :          src_content = *reinterpret_cast<uint16*>(&src[offset]);
 148  E :          dst_content = *reinterpret_cast<uint16*>(&dst[offset]);
 149  E :          break;
 150    :        case 1:
 151  E :          src_content = *reinterpret_cast<uint8*>(&src[offset]);
 152  E :          dst_content = *reinterpret_cast<uint8*>(&dst[offset]);
 153  E :          break;
 154    :        default:
 155  i :          NOTREACHED() << "Unexpected access_size.";
 156    :          break;
 157    :        }
 158    :  
 159  E :        if (src_content != dst_content)
 160  E :          return;
 161    :      }
 162    :  
 163    :      // Increments offset of dst/src to the next memory location.
 164  E :      offset += increment;
 165  E :    }
 166  E :  }
 167    :  
 168    :  MemoryAccessorFunction asan_redirect_stub_entry(
 169    :      const void* caller_address,
 170  E :      MemoryAccessorFunction called_redirect) {
 171  E :    MemoryAccessorMode mode = MEMORY_ACCESSOR_MODE_NOOP;
 172    :  
 173    :    // TODO(siggi): Does it make sense to CHECK on this?
 174  E :    if (!redirect_entry_callback.is_null())
 175  E :      mode = redirect_entry_callback.Run(caller_address);
 176    :  
 177  E :    for (size_t i = 0; i < arraysize(kMemoryAccessorVariants); ++i) {
 178  E :      if (kMemoryAccessorVariants[i].redirect_accessor != called_redirect)
 179  E :        continue;
 180  E :      CHECK_LE(0u, mode);
 181  E :      CHECK_GT(MEMORY_ACCESSOR_MODE_MAX, mode);
 182  E :      return kMemoryAccessorVariants[i].accessors[mode];
 183  i :    }
 184    :  
 185  i :    NOTREACHED();
 186  i :    return NULL;
 187  E :  }
 188    :  
 189    :  // A simple wrapper to agent::asan::ReportBadMemoryAccess that has C linkage
 190    :  // so it can be referred to in memory_interceptors.asm.
 191    :  void asan_report_bad_memory_access(void* location,
 192    :                                     AccessMode access_mode,
 193    :                                     size_t access_size,
 194  E :                                     const AsanContext& asan_context) {
 195    :    return agent::asan::ReportBadMemoryAccess(location, access_mode, access_size,
 196  E :                                              asan_context);
 197  E :  }
 198    :  
 199    :  }  // extern "C"
 200    :  
 201    :  }  // namespace asan
 202    :  }  // namespace agent

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