master
  1//===-- sanitizer_win_interception.cpp --------------------    --*- C++ -*-===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8//
  9// Windows-specific export surface to provide interception for parts of the
 10// runtime that are always statically linked, both for overriding user-defined
 11// functions as well as registering weak functions that the ASAN runtime should
 12// use over defaults.
 13//
 14//===----------------------------------------------------------------------===//
 15
 16#include "sanitizer_platform.h"
 17#if SANITIZER_WINDOWS
 18#  include <stddef.h>
 19
 20#  include "interception/interception.h"
 21#  include "sanitizer_addrhashmap.h"
 22#  include "sanitizer_common.h"
 23#  include "sanitizer_internal_defs.h"
 24#  include "sanitizer_placement_new.h"
 25#  include "sanitizer_win_immortalize.h"
 26#  include "sanitizer_win_interception.h"
 27
 28using namespace __sanitizer;
 29
 30extern "C" void *__ImageBase;
 31
 32namespace __sanitizer {
 33
 34static uptr GetSanitizerDllExport(const char *export_name) {
 35  const uptr function_address =
 36      __interception::InternalGetProcAddress(&__ImageBase, export_name);
 37  if (function_address == 0) {
 38    Report("ERROR: Failed to find sanitizer DLL export '%s'\n", export_name);
 39    CHECK("Failed to find sanitizer DLL export" && 0);
 40  }
 41  return function_address;
 42}
 43
 44struct WeakCallbackList {
 45  explicit constexpr WeakCallbackList(RegisterWeakFunctionCallback cb)
 46      : callback(cb), next(nullptr) {}
 47
 48  static void *operator new(size_t size) { return InternalAlloc(size); }
 49
 50  static void operator delete(void *p) { InternalFree(p); }
 51
 52  RegisterWeakFunctionCallback callback;
 53  WeakCallbackList *next;
 54};
 55using WeakCallbackMap = AddrHashMap<WeakCallbackList *, 11>;
 56
 57static WeakCallbackMap *GetWeakCallbackMap() {
 58  return &immortalize<WeakCallbackMap>();
 59}
 60
 61void AddRegisterWeakFunctionCallback(uptr export_address,
 62                                     RegisterWeakFunctionCallback cb) {
 63  WeakCallbackMap::Handle h_find_or_create(GetWeakCallbackMap(), export_address,
 64                                           false, true);
 65  CHECK(h_find_or_create.exists());
 66  if (h_find_or_create.created()) {
 67    *h_find_or_create = new WeakCallbackList(cb);
 68  } else {
 69    (*h_find_or_create)->next = new WeakCallbackList(cb);
 70  }
 71}
 72
 73static void RunWeakFunctionCallbacks(uptr export_address) {
 74  WeakCallbackMap::Handle h_find(GetWeakCallbackMap(), export_address, false,
 75                                 false);
 76  if (!h_find.exists()) {
 77    return;
 78  }
 79
 80  WeakCallbackList *list = *h_find;
 81  do {
 82    list->callback();
 83  } while ((list = list->next));
 84}
 85
 86}  // namespace __sanitizer
 87
 88extern "C" __declspec(dllexport) bool __cdecl __sanitizer_override_function(
 89    const char *export_name, const uptr user_function,
 90    uptr *const old_user_function) {
 91  CHECK(export_name);
 92  CHECK(user_function);
 93
 94  const uptr sanitizer_function = GetSanitizerDllExport(export_name);
 95
 96  const bool function_overridden = __interception::OverrideFunction(
 97      user_function, sanitizer_function, old_user_function);
 98  if (!function_overridden) {
 99    Report(
100        "ERROR: Failed to override local function at '%p' with sanitizer "
101        "function '%s'\n",
102        user_function, export_name);
103    CHECK("Failed to replace local function with sanitizer version." && 0);
104  }
105
106  return function_overridden;
107}
108
109extern "C"
110    __declspec(dllexport) bool __cdecl __sanitizer_override_function_by_addr(
111        const uptr source_function, const uptr target_function,
112        uptr *const old_target_function) {
113  CHECK(source_function);
114  CHECK(target_function);
115
116  const bool function_overridden = __interception::OverrideFunction(
117      target_function, source_function, old_target_function);
118  if (!function_overridden) {
119    Report(
120        "ERROR: Failed to override function at '%p' with function at "
121        "'%p'\n",
122        target_function, source_function);
123    CHECK("Failed to apply function override." && 0);
124  }
125
126  return function_overridden;
127}
128
129extern "C"
130    __declspec(dllexport) bool __cdecl __sanitizer_register_weak_function(
131        const char *export_name, const uptr user_function,
132        uptr *const old_user_function) {
133  CHECK(export_name);
134  CHECK(user_function);
135
136  const uptr sanitizer_function = GetSanitizerDllExport(export_name);
137
138  const bool function_overridden = __interception::OverrideFunction(
139      sanitizer_function, user_function, old_user_function);
140  if (!function_overridden) {
141    Report(
142        "ERROR: Failed to register local function at '%p' to be used in "
143        "place of sanitizer function '%s'\n.",
144        user_function, export_name);
145    CHECK("Failed to register weak function." && 0);
146  }
147
148  // Note that thread-safety of RunWeakFunctionCallbacks in InitializeFlags
149  // depends on __sanitizer_register_weak_functions being called during the
150  // loader lock.
151  RunWeakFunctionCallbacks(sanitizer_function);
152
153  return function_overridden;
154}
155
156#endif  // SANITIZER_WINDOWS