168d75effSDimitry Andric //===-- asan_malloc_linux.cpp ---------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Linux-specific malloc interception. 1268d75effSDimitry Andric // We simply define functions like malloc, free, realloc, etc. 1368d75effSDimitry Andric // They will replace the corresponding libc functions automagically. 1468d75effSDimitry Andric //===----------------------------------------------------------------------===// 1568d75effSDimitry Andric 1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 1768d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ 18fe6060f1SDimitry Andric SANITIZER_NETBSD || SANITIZER_SOLARIS 1968d75effSDimitry Andric 2068d75effSDimitry Andric # include "asan_allocator.h" 2168d75effSDimitry Andric # include "asan_interceptors.h" 2268d75effSDimitry Andric # include "asan_internal.h" 2368d75effSDimitry Andric # include "asan_stack.h" 24349cc55cSDimitry Andric # include "lsan/lsan_common.h" 25fe6060f1SDimitry Andric # include "sanitizer_common/sanitizer_allocator_checks.h" 26349cc55cSDimitry Andric # include "sanitizer_common/sanitizer_allocator_dlsym.h" 27fe6060f1SDimitry Andric # include "sanitizer_common/sanitizer_errno.h" 28fe6060f1SDimitry Andric # include "sanitizer_common/sanitizer_tls_get_addr.h" 2968d75effSDimitry Andric 3068d75effSDimitry Andric // ---------------------- Replacement functions ---------------- {{{1 3168d75effSDimitry Andric using namespace __asan; 3268d75effSDimitry Andric 33349cc55cSDimitry Andric struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { 345f757f3fSDimitry Andric static bool UseImpl() { return !TryAsanInitFromRtl(); } 35349cc55cSDimitry Andric static void OnAllocate(const void *ptr, uptr size) { 36349cc55cSDimitry Andric # if CAN_SANITIZE_LEAKS 37349cc55cSDimitry Andric // Suppress leaks from dlerror(). Previously dlsym hack on global array was 38349cc55cSDimitry Andric // used by leak sanitizer as a root region. 39349cc55cSDimitry Andric __lsan_register_root_region(ptr, size); 40349cc55cSDimitry Andric # endif 4168d75effSDimitry Andric } 42349cc55cSDimitry Andric static void OnFree(const void *ptr, uptr size) { 43349cc55cSDimitry Andric # if CAN_SANITIZE_LEAKS 44349cc55cSDimitry Andric __lsan_unregister_root_region(ptr, size); 45349cc55cSDimitry Andric # endif 4668d75effSDimitry Andric } 47349cc55cSDimitry Andric }; 4868d75effSDimitry Andric 4968d75effSDimitry Andric INTERCEPTOR(void, free, void *ptr) { 50349cc55cSDimitry Andric if (DlsymAlloc::PointerIsMine(ptr)) 51349cc55cSDimitry Andric return DlsymAlloc::Free(ptr); 52e8d8bef9SDimitry Andric GET_STACK_TRACE_FREE; 5368d75effSDimitry Andric asan_free(ptr, &stack, FROM_MALLOC); 5468d75effSDimitry Andric } 5568d75effSDimitry Andric 5668d75effSDimitry Andric #if SANITIZER_INTERCEPT_CFREE 5768d75effSDimitry Andric INTERCEPTOR(void, cfree, void *ptr) { 58349cc55cSDimitry Andric if (DlsymAlloc::PointerIsMine(ptr)) 59349cc55cSDimitry Andric return DlsymAlloc::Free(ptr); 60e8d8bef9SDimitry Andric GET_STACK_TRACE_FREE; 6168d75effSDimitry Andric asan_free(ptr, &stack, FROM_MALLOC); 6268d75effSDimitry Andric } 6368d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_CFREE 6468d75effSDimitry Andric 6568d75effSDimitry Andric INTERCEPTOR(void*, malloc, uptr size) { 66349cc55cSDimitry Andric if (DlsymAlloc::Use()) 67349cc55cSDimitry Andric return DlsymAlloc::Allocate(size); 6868d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 6968d75effSDimitry Andric return asan_malloc(size, &stack); 7068d75effSDimitry Andric } 7168d75effSDimitry Andric 7268d75effSDimitry Andric INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 73349cc55cSDimitry Andric if (DlsymAlloc::Use()) 74349cc55cSDimitry Andric return DlsymAlloc::Callocate(nmemb, size); 7568d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 7668d75effSDimitry Andric return asan_calloc(nmemb, size, &stack); 7768d75effSDimitry Andric } 7868d75effSDimitry Andric 7968d75effSDimitry Andric INTERCEPTOR(void*, realloc, void *ptr, uptr size) { 80349cc55cSDimitry Andric if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) 81349cc55cSDimitry Andric return DlsymAlloc::Realloc(ptr, size); 8268d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 8368d75effSDimitry Andric return asan_realloc(ptr, size, &stack); 8468d75effSDimitry Andric } 8568d75effSDimitry Andric 8668d75effSDimitry Andric #if SANITIZER_INTERCEPT_REALLOCARRAY 8768d75effSDimitry Andric INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) { 885f757f3fSDimitry Andric AsanInitFromRtl(); 8968d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 9068d75effSDimitry Andric return asan_reallocarray(ptr, nmemb, size, &stack); 9168d75effSDimitry Andric } 9268d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_REALLOCARRAY 9368d75effSDimitry Andric 9468d75effSDimitry Andric #if SANITIZER_INTERCEPT_MEMALIGN 9568d75effSDimitry Andric INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { 9668d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 9768d75effSDimitry Andric return asan_memalign(boundary, size, &stack, FROM_MALLOC); 9868d75effSDimitry Andric } 9968d75effSDimitry Andric 10068d75effSDimitry Andric INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { 10168d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 10268d75effSDimitry Andric void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); 10368d75effSDimitry Andric DTLS_on_libc_memalign(res, size); 10468d75effSDimitry Andric return res; 10568d75effSDimitry Andric } 10668d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MEMALIGN 10768d75effSDimitry Andric 10868d75effSDimitry Andric #if SANITIZER_INTERCEPT_ALIGNED_ALLOC 10968d75effSDimitry Andric INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { 11068d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 11168d75effSDimitry Andric return asan_aligned_alloc(boundary, size, &stack); 11268d75effSDimitry Andric } 11368d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC 11468d75effSDimitry Andric 11568d75effSDimitry Andric INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 11668d75effSDimitry Andric GET_CURRENT_PC_BP_SP; 11768d75effSDimitry Andric (void)sp; 11868d75effSDimitry Andric return asan_malloc_usable_size(ptr, pc, bp); 11968d75effSDimitry Andric } 12068d75effSDimitry Andric 12168d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 12268d75effSDimitry Andric // We avoid including malloc.h for portability reasons. 12368d75effSDimitry Andric // man mallinfo says the fields are "long", but the implementation uses int. 12468d75effSDimitry Andric // It doesn't matter much -- we just need to make sure that the libc's mallinfo 12568d75effSDimitry Andric // is not called. 12668d75effSDimitry Andric struct fake_mallinfo { 12768d75effSDimitry Andric int x[10]; 12868d75effSDimitry Andric }; 12968d75effSDimitry Andric 13068d75effSDimitry Andric INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 13168d75effSDimitry Andric struct fake_mallinfo res; 13268d75effSDimitry Andric REAL(memset)(&res, 0, sizeof(res)); 13368d75effSDimitry Andric return res; 13468d75effSDimitry Andric } 13568d75effSDimitry Andric 13668d75effSDimitry Andric INTERCEPTOR(int, mallopt, int cmd, int value) { 13768d75effSDimitry Andric return 0; 13868d75effSDimitry Andric } 13968d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 14068d75effSDimitry Andric 14168d75effSDimitry Andric INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 14268d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 14368d75effSDimitry Andric return asan_posix_memalign(memptr, alignment, size, &stack); 14468d75effSDimitry Andric } 14568d75effSDimitry Andric 14668d75effSDimitry Andric INTERCEPTOR(void*, valloc, uptr size) { 14768d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 14868d75effSDimitry Andric return asan_valloc(size, &stack); 14968d75effSDimitry Andric } 15068d75effSDimitry Andric 15168d75effSDimitry Andric #if SANITIZER_INTERCEPT_PVALLOC 15268d75effSDimitry Andric INTERCEPTOR(void*, pvalloc, uptr size) { 15368d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 15468d75effSDimitry Andric return asan_pvalloc(size, &stack); 15568d75effSDimitry Andric } 15668d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_PVALLOC 15768d75effSDimitry Andric 15868d75effSDimitry Andric INTERCEPTOR(void, malloc_stats, void) { 15968d75effSDimitry Andric __asan_print_accumulated_stats(); 16068d75effSDimitry Andric } 16168d75effSDimitry Andric 16268d75effSDimitry Andric #if SANITIZER_ANDROID 16368d75effSDimitry Andric // Format of __libc_malloc_dispatch has changed in Android L. 16468d75effSDimitry Andric // While we are moving towards a solution that does not depend on bionic 16568d75effSDimitry Andric // internals, here is something to support both K* and L releases. 16668d75effSDimitry Andric struct MallocDebugK { 16768d75effSDimitry Andric void *(*malloc)(uptr bytes); 16868d75effSDimitry Andric void (*free)(void *mem); 16968d75effSDimitry Andric void *(*calloc)(uptr n_elements, uptr elem_size); 17068d75effSDimitry Andric void *(*realloc)(void *oldMem, uptr bytes); 17168d75effSDimitry Andric void *(*memalign)(uptr alignment, uptr bytes); 17268d75effSDimitry Andric uptr (*malloc_usable_size)(void *mem); 17368d75effSDimitry Andric }; 17468d75effSDimitry Andric 17568d75effSDimitry Andric struct MallocDebugL { 17668d75effSDimitry Andric void *(*calloc)(uptr n_elements, uptr elem_size); 17768d75effSDimitry Andric void (*free)(void *mem); 17868d75effSDimitry Andric fake_mallinfo (*mallinfo)(void); 17968d75effSDimitry Andric void *(*malloc)(uptr bytes); 18068d75effSDimitry Andric uptr (*malloc_usable_size)(void *mem); 18168d75effSDimitry Andric void *(*memalign)(uptr alignment, uptr bytes); 18268d75effSDimitry Andric int (*posix_memalign)(void **memptr, uptr alignment, uptr size); 18368d75effSDimitry Andric void* (*pvalloc)(uptr size); 18468d75effSDimitry Andric void *(*realloc)(void *oldMem, uptr bytes); 18568d75effSDimitry Andric void* (*valloc)(uptr size); 18668d75effSDimitry Andric }; 18768d75effSDimitry Andric 188*0fca6ea1SDimitry Andric alignas(32) const MallocDebugK asan_malloc_dispatch_k = { 18968d75effSDimitry Andric WRAP(malloc), WRAP(free), WRAP(calloc), 19068d75effSDimitry Andric WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; 19168d75effSDimitry Andric 192*0fca6ea1SDimitry Andric alignas(32) const MallocDebugL asan_malloc_dispatch_l = { 19368d75effSDimitry Andric WRAP(calloc), WRAP(free), WRAP(mallinfo), 19468d75effSDimitry Andric WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign), 19568d75effSDimitry Andric WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc), 19668d75effSDimitry Andric WRAP(valloc)}; 19768d75effSDimitry Andric 19868d75effSDimitry Andric namespace __asan { 19968d75effSDimitry Andric void ReplaceSystemMalloc() { 20068d75effSDimitry Andric void **__libc_malloc_dispatch_p = 20168d75effSDimitry Andric (void **)AsanDlSymNext("__libc_malloc_dispatch"); 20268d75effSDimitry Andric if (__libc_malloc_dispatch_p) { 20368d75effSDimitry Andric // Decide on K vs L dispatch format by the presence of 20468d75effSDimitry Andric // __libc_malloc_default_dispatch export in libc. 20568d75effSDimitry Andric void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch"); 20668d75effSDimitry Andric if (default_dispatch_p) 20768d75effSDimitry Andric *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k; 20868d75effSDimitry Andric else 20968d75effSDimitry Andric *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l; 21068d75effSDimitry Andric } 21168d75effSDimitry Andric } 21268d75effSDimitry Andric } // namespace __asan 21368d75effSDimitry Andric 21468d75effSDimitry Andric #else // SANITIZER_ANDROID 21568d75effSDimitry Andric 21668d75effSDimitry Andric namespace __asan { 21768d75effSDimitry Andric void ReplaceSystemMalloc() { 21868d75effSDimitry Andric } 21968d75effSDimitry Andric } // namespace __asan 22068d75effSDimitry Andric #endif // SANITIZER_ANDROID 22168d75effSDimitry Andric 22268d75effSDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || 22368d75effSDimitry Andric // SANITIZER_NETBSD || SANITIZER_SOLARIS 224