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