xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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