Home | History | Annotate | Line # | Download | only in asan
      1 //===-- asan_malloc_linux.cpp ---------------------------------------------===//
      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 // This file is a part of AddressSanitizer, an address sanity checker.
     10 //
     11 // Linux-specific malloc interception.
     12 // We simply define functions like malloc, free, realloc, etc.
     13 // They will replace the corresponding libc functions automagically.
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "sanitizer_common/sanitizer_platform.h"
     17 #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
     18     SANITIZER_NETBSD || SANITIZER_SOLARIS
     19 
     20 #  include "asan_allocator.h"
     21 #  include "asan_interceptors.h"
     22 #  include "asan_internal.h"
     23 #  include "asan_stack.h"
     24 #  include "lsan/lsan_common.h"
     25 #  include "sanitizer_common/sanitizer_allocator_checks.h"
     26 #  include "sanitizer_common/sanitizer_allocator_dlsym.h"
     27 #  include "sanitizer_common/sanitizer_errno.h"
     28 #  include "sanitizer_common/sanitizer_tls_get_addr.h"
     29 
     30 // ---------------------- Replacement functions ---------------- {{{1
     31 using namespace __asan;
     32 
     33 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
     34   static bool UseImpl() { return asan_init_is_running; }
     35   static void OnAllocate(const void *ptr, uptr size) {
     36 #  if CAN_SANITIZE_LEAKS
     37     // Suppress leaks from dlerror(). Previously dlsym hack on global array was
     38     // used by leak sanitizer as a root region.
     39     __lsan_register_root_region(ptr, size);
     40 #  endif
     41   }
     42   static void OnFree(const void *ptr, uptr size) {
     43 #  if CAN_SANITIZE_LEAKS
     44     __lsan_unregister_root_region(ptr, size);
     45 #  endif
     46   }
     47 };
     48 
     49 INTERCEPTOR(void, free, void *ptr) {
     50   if (DlsymAlloc::PointerIsMine(ptr))
     51     return DlsymAlloc::Free(ptr);
     52   GET_STACK_TRACE_FREE;
     53   asan_free(ptr, &stack, FROM_MALLOC);
     54 }
     55 
     56 #if SANITIZER_INTERCEPT_CFREE
     57 INTERCEPTOR(void, cfree, void *ptr) {
     58   if (DlsymAlloc::PointerIsMine(ptr))
     59     return DlsymAlloc::Free(ptr);
     60   GET_STACK_TRACE_FREE;
     61   asan_free(ptr, &stack, FROM_MALLOC);
     62 }
     63 #endif // SANITIZER_INTERCEPT_CFREE
     64 
     65 INTERCEPTOR(void*, malloc, uptr size) {
     66   if (DlsymAlloc::Use())
     67     return DlsymAlloc::Allocate(size);
     68   ENSURE_ASAN_INITED();
     69   GET_STACK_TRACE_MALLOC;
     70   return asan_malloc(size, &stack);
     71 }
     72 
     73 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
     74   if (DlsymAlloc::Use())
     75     return DlsymAlloc::Callocate(nmemb, size);
     76   ENSURE_ASAN_INITED();
     77   GET_STACK_TRACE_MALLOC;
     78   return asan_calloc(nmemb, size, &stack);
     79 }
     80 
     81 INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
     82   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
     83     return DlsymAlloc::Realloc(ptr, size);
     84   ENSURE_ASAN_INITED();
     85   GET_STACK_TRACE_MALLOC;
     86   return asan_realloc(ptr, size, &stack);
     87 }
     88 
     89 #if SANITIZER_INTERCEPT_REALLOCARRAY
     90 INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) {
     91   ENSURE_ASAN_INITED();
     92   GET_STACK_TRACE_MALLOC;
     93   return asan_reallocarray(ptr, nmemb, size, &stack);
     94 }
     95 #endif  // SANITIZER_INTERCEPT_REALLOCARRAY
     96 
     97 #if SANITIZER_INTERCEPT_MEMALIGN
     98 INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
     99   GET_STACK_TRACE_MALLOC;
    100   return asan_memalign(boundary, size, &stack, FROM_MALLOC);
    101 }
    102 
    103 INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
    104   GET_STACK_TRACE_MALLOC;
    105   void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
    106   DTLS_on_libc_memalign(res, size);
    107   return res;
    108 }
    109 #endif // SANITIZER_INTERCEPT_MEMALIGN
    110 
    111 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
    112 INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
    113   GET_STACK_TRACE_MALLOC;
    114   return asan_aligned_alloc(boundary, size, &stack);
    115 }
    116 #endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC
    117 
    118 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
    119   GET_CURRENT_PC_BP_SP;
    120   (void)sp;
    121   return asan_malloc_usable_size(ptr, pc, bp);
    122 }
    123 
    124 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
    125 // We avoid including malloc.h for portability reasons.
    126 // man mallinfo says the fields are "long", but the implementation uses int.
    127 // It doesn't matter much -- we just need to make sure that the libc's mallinfo
    128 // is not called.
    129 struct fake_mallinfo {
    130   int x[10];
    131 };
    132 
    133 INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
    134   struct fake_mallinfo res;
    135   REAL(memset)(&res, 0, sizeof(res));
    136   return res;
    137 }
    138 
    139 INTERCEPTOR(int, mallopt, int cmd, int value) {
    140   return 0;
    141 }
    142 #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
    143 
    144 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
    145   GET_STACK_TRACE_MALLOC;
    146   return asan_posix_memalign(memptr, alignment, size, &stack);
    147 }
    148 
    149 INTERCEPTOR(void*, valloc, uptr size) {
    150   GET_STACK_TRACE_MALLOC;
    151   return asan_valloc(size, &stack);
    152 }
    153 
    154 #if SANITIZER_INTERCEPT_PVALLOC
    155 INTERCEPTOR(void*, pvalloc, uptr size) {
    156   GET_STACK_TRACE_MALLOC;
    157   return asan_pvalloc(size, &stack);
    158 }
    159 #endif // SANITIZER_INTERCEPT_PVALLOC
    160 
    161 INTERCEPTOR(void, malloc_stats, void) {
    162   __asan_print_accumulated_stats();
    163 }
    164 
    165 #if SANITIZER_ANDROID
    166 // Format of __libc_malloc_dispatch has changed in Android L.
    167 // While we are moving towards a solution that does not depend on bionic
    168 // internals, here is something to support both K* and L releases.
    169 struct MallocDebugK {
    170   void *(*malloc)(uptr bytes);
    171   void (*free)(void *mem);
    172   void *(*calloc)(uptr n_elements, uptr elem_size);
    173   void *(*realloc)(void *oldMem, uptr bytes);
    174   void *(*memalign)(uptr alignment, uptr bytes);
    175   uptr (*malloc_usable_size)(void *mem);
    176 };
    177 
    178 struct MallocDebugL {
    179   void *(*calloc)(uptr n_elements, uptr elem_size);
    180   void (*free)(void *mem);
    181   fake_mallinfo (*mallinfo)(void);
    182   void *(*malloc)(uptr bytes);
    183   uptr (*malloc_usable_size)(void *mem);
    184   void *(*memalign)(uptr alignment, uptr bytes);
    185   int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
    186   void* (*pvalloc)(uptr size);
    187   void *(*realloc)(void *oldMem, uptr bytes);
    188   void* (*valloc)(uptr size);
    189 };
    190 
    191 ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
    192     WRAP(malloc),  WRAP(free),     WRAP(calloc),
    193     WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
    194 
    195 ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
    196     WRAP(calloc),         WRAP(free),               WRAP(mallinfo),
    197     WRAP(malloc),         WRAP(malloc_usable_size), WRAP(memalign),
    198     WRAP(posix_memalign), WRAP(pvalloc),            WRAP(realloc),
    199     WRAP(valloc)};
    200 
    201 namespace __asan {
    202 void ReplaceSystemMalloc() {
    203   void **__libc_malloc_dispatch_p =
    204       (void **)AsanDlSymNext("__libc_malloc_dispatch");
    205   if (__libc_malloc_dispatch_p) {
    206     // Decide on K vs L dispatch format by the presence of
    207     // __libc_malloc_default_dispatch export in libc.
    208     void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
    209     if (default_dispatch_p)
    210       *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
    211     else
    212       *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
    213   }
    214 }
    215 }  // namespace __asan
    216 
    217 #else  // SANITIZER_ANDROID
    218 
    219 namespace __asan {
    220 void ReplaceSystemMalloc() {
    221 }
    222 }  // namespace __asan
    223 #endif  // SANITIZER_ANDROID
    224 
    225 #endif  // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
    226         // SANITIZER_NETBSD || SANITIZER_SOLARIS
    227