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