llvm/compiler-rt/lib/asan/asan_interceptors.cpp

//===-- asan_interceptors.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Intercept various libc functions.
//===----------------------------------------------------------------------===//

#include "asan_interceptors.h"

#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_suppressions.h"
#include "asan_thread.h"
#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_libc.h"

// There is no general interception at all on Fuchsia.
// Only the functions in asan_interceptors_memintrinsics.cpp are
// really defined to replace libc functions.
#if !SANITIZER_FUCHSIA

#  if SANITIZER_POSIX
#    include "sanitizer_common/sanitizer_posix.h"
#  endif

#  if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \
      ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
#    include <unwind.h>
#  endif

#  if defined(__i386) && SANITIZER_LINUX
#define ASAN_PTHREAD_CREATE_VERSION
#  elif defined(__mips__) && SANITIZER_LINUX
#define ASAN_PTHREAD_CREATE_VERSION
#  endif

namespace __asan {

#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n)

#define ASAN_READ_STRING(ctx, s, n)

static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {}

void SetThreadName(const char *name) {}

int OnExit() {}

} // namespace __asan

// ---------------------- Wrappers ---------------- {{{1
usingnamespace__asan;

DECLARE_REAL_AND_INTERCEPTOR()
DECLARE_REAL_AND_INTERCEPTOR()

#define COMMON_INTERCEPT_FUNCTION_VER(name, ver)
#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)
#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path)
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd)
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd)
#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name)
// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
// But asan does not remember UserId's for threads (pthread_t);
// and remembers all ever existed threads, so the linear search by UserId
// can be slow.
#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name)
// Strict init-order checking is dlopen-hostile:
// https://github.com/google/sanitizers/issues/178
#define COMMON_INTERCEPTOR_DLOPEN(filename, flag)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx)
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end)

template <class Mmap>
static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
                              int prot, int flags, int fd, OFF64_T offset) {}

template <class Munmap>
static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {}

#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags,   \
                                     fd, offset)

#define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length)

#if CAN_SANITIZE_LEAKS
#define COMMON_INTERCEPTOR_STRERROR()
#endif

#define SIGNAL_INTERCEPTOR_ENTER()

#  include "sanitizer_common/sanitizer_common_interceptors.inc"
#  include "sanitizer_common/sanitizer_signal_interceptors.inc"

// Syscall interceptors don't have contexts, we don't support suppressions
// for them.
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s)
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"

#if ASAN_INTERCEPT_PTHREAD_CREATE
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {}

INTERCEPTOR(int, pthread_create, void *thread, void *attr,
            void *(*start_routine)(void *), void *arg) {}

INTERCEPTOR(int, pthread_join, void *thread, void **retval) {}

INTERCEPTOR(int, pthread_detach, void *thread) {}

INTERCEPTOR(void, pthread_exit, void *retval) {}

#    if ASAN_INTERCEPT_TRYJOIN
INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {}
#    endif

#    if ASAN_INTERCEPT_TIMEDJOIN
INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
            const struct timespec *abstime) {}
#    endif

DEFINE_INTERNAL_PTHREAD_FUNCTIONS
#endif  // ASAN_INTERCEPT_PTHREAD_CREATE

#if ASAN_INTERCEPT_SWAPCONTEXT
static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {}

// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address
// as on other targets.  For binary compatibility, the new version uses a
// different external name, so we intercept that.
#    if SANITIZER_SOLARIS && defined(__sparc__)
INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),
            int argc, ...) {
#    else
INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
            ...) {}

INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
            struct ucontext_t *ucp) {}
#endif  // ASAN_INTERCEPT_SWAPCONTEXT

#if SANITIZER_NETBSD
#define longjmp
#define siglongjmp
#endif

INTERCEPTOR(void, longjmp, void *env, int val) {}

#if ASAN_INTERCEPT__LONGJMP
INTERCEPTOR(void, _longjmp, void *env, int val) {}
#endif

#if ASAN_INTERCEPT___LONGJMP_CHK
INTERCEPTOR(void, __longjmp_chk, void *env, int val) {}
#endif

#if ASAN_INTERCEPT_SIGLONGJMP
INTERCEPTOR(void, siglongjmp, void *env, int val) {}
#endif

#if ASAN_INTERCEPT___CXA_THROW
INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {}
#endif

#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {}
#endif

#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,
            _Unwind_Exception *object) {}
#endif

#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,
            _Unwind_Exception *object) {
  CHECK(REAL(_Unwind_SjLj_RaiseException));
  __asan_handle_no_return();
  return REAL(_Unwind_SjLj_RaiseException)(object);
}
#endif

#if ASAN_INTERCEPT_INDEX
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
INTERCEPTOR(char*, index, const char *string, int c)
  ALIAS(WRAP(strchr));
# else
#  if SANITIZER_APPLE
DECLARE_REAL(char*, index, const char *string, int c)
OVERRIDE_FUNCTION(index, strchr);
#  else
DEFINE_REAL(char*, index, const char *string, int c)
#  endif
# endif
#endif  // ASAN_INTERCEPT_INDEX

// For both strcat() and strncat() we need to check the validity of |to|
// argument irrespective of the |from| length.
  INTERCEPTOR(char *, strcat, char *to, const char *from) {}

INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {}

INTERCEPTOR(char *, strcpy, char *to, const char *from) {}

// Windows doesn't always define the strdup identifier,
// and when it does it's a macro defined to either _strdup
// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
// we want to intercept that. push/pop_macro are used to avoid problems
// if this file ends up including <string.h> in the future.
#  if SANITIZER_WINDOWS
#    pragma push_macro("strdup")
#    undef strdup
#define strdup
#  endif

INTERCEPTOR(char*, strdup, const char *s) {}

#  if ASAN_INTERCEPT___STRDUP
INTERCEPTOR(char*, __strdup, const char *s) {}
#endif // ASAN_INTERCEPT___STRDUP

INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {}

template <typename Fn>
static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,
                                     char **endptr, int base)
    -> decltype(real(nullptr, nullptr, 0)) {}

#define INTERCEPTOR_STRTO_BASE(ret_type, func)

INTERCEPTOR_STRTO_BASE()

#  if SANITIZER_WINDOWS
INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {
  // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,
  // call REAL(strtoll) and do the range check ourselves.
  COMPILER_CHECK(sizeof(long) == sizeof(u32));

  void *ctx;
  ASAN_INTERCEPTOR_ENTER(ctx, strtol);
  AsanInitFromRtl();

  long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);

  if (result > INT32_MAX) {
    errno = errno_ERANGE;
    return INT32_MAX;
  }
  if (result < INT32_MIN) {
    errno = errno_ERANGE;
    return INT32_MIN;
  }
  return (long)result;
}
#  else
INTERCEPTOR_STRTO_BASE()
#  endif

#  if SANITIZER_GLIBC
INTERCEPTOR_STRTO_BASE()
INTERCEPTOR_STRTO_BASE()
#  endif

INTERCEPTOR(int, atoi, const char *nptr) {}

INTERCEPTOR(long, atol, const char *nptr) {}

INTERCEPTOR(long long, atoll, const char *nptr) {}

#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
static void AtCxaAtexit(void *unused) {}
#endif

#if ASAN_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
            void *dso_handle) {}
#endif  // ASAN_INTERCEPT___CXA_ATEXIT

#if ASAN_INTERCEPT_ATEXIT
INTERCEPTOR(int, atexit, void (*func)()) {
  AsanInitFromRtl();
#    if CAN_SANITIZE_LEAKS
  __lsan::ScopedInterceptorDisabler disabler;
#endif
  // Avoid calling real atexit as it is unreachable on at least on Linux.
  int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
  REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
  return res;
}
#endif

#if ASAN_INTERCEPT_PTHREAD_ATFORK
extern "C" {
extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
                           void (*child)());
}

INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
            void (*child)()) {
#if CAN_SANITIZE_LEAKS
  __lsan::ScopedInterceptorDisabler disabler;
#endif
  // REAL(pthread_atfork) cannot be called due to symbol indirections at least
  // on NetBSD
  return _pthread_atfork(prepare, parent, child);
}
#endif

#if ASAN_INTERCEPT_VFORK
DEFINE_REAL()
DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER()
#endif

// ---------------------- InitializeAsanInterceptors ---------------- {{{1
namespace __asan {
void InitializeAsanInterceptors() {}

#  if SANITIZER_WINDOWS
#    pragma pop_macro("strdup")
#  endif

} // namespace __asan

#endif  // !SANITIZER_FUCHSIA