1*490215a3Smrg //===-- asan_malloc_linux.cc ----------------------------------------------===//
2*490215a3Smrg //
3*490215a3Smrg // This file is distributed under the University of Illinois Open Source
4*490215a3Smrg // License. See LICENSE.TXT for details.
5*490215a3Smrg //
6*490215a3Smrg //===----------------------------------------------------------------------===//
7*490215a3Smrg //
8*490215a3Smrg // This file is a part of AddressSanitizer, an address sanity checker.
9*490215a3Smrg //
10*490215a3Smrg // Linux-specific malloc interception.
11*490215a3Smrg // We simply define functions like malloc, free, realloc, etc.
12*490215a3Smrg // They will replace the corresponding libc functions automagically.
13*490215a3Smrg //===----------------------------------------------------------------------===//
14*490215a3Smrg 
15*490215a3Smrg #include "sanitizer_common/sanitizer_platform.h"
16*490215a3Smrg #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
17*490215a3Smrg     SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS
18*490215a3Smrg 
19*490215a3Smrg #include "sanitizer_common/sanitizer_allocator_checks.h"
20*490215a3Smrg #include "sanitizer_common/sanitizer_errno.h"
21*490215a3Smrg #include "sanitizer_common/sanitizer_tls_get_addr.h"
22*490215a3Smrg #include "asan_allocator.h"
23*490215a3Smrg #include "asan_interceptors.h"
24*490215a3Smrg #include "asan_internal.h"
25*490215a3Smrg #include "asan_malloc_local.h"
26*490215a3Smrg #include "asan_stack.h"
27*490215a3Smrg 
28*490215a3Smrg // ---------------------- Replacement functions ---------------- {{{1
29*490215a3Smrg using namespace __asan;  // NOLINT
30*490215a3Smrg 
31*490215a3Smrg static uptr allocated_for_dlsym;
32*490215a3Smrg static uptr last_dlsym_alloc_size_in_words;
33*490215a3Smrg static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024;
34*490215a3Smrg static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
35*490215a3Smrg 
IsInDlsymAllocPool(const void * ptr)36*490215a3Smrg static INLINE bool IsInDlsymAllocPool(const void *ptr) {
37*490215a3Smrg   uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
38*490215a3Smrg   return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
39*490215a3Smrg }
40*490215a3Smrg 
AllocateFromLocalPool(uptr size_in_bytes)41*490215a3Smrg static void *AllocateFromLocalPool(uptr size_in_bytes) {
42*490215a3Smrg   uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
43*490215a3Smrg   void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym];
44*490215a3Smrg   last_dlsym_alloc_size_in_words = size_in_words;
45*490215a3Smrg   allocated_for_dlsym += size_in_words;
46*490215a3Smrg   CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
47*490215a3Smrg   return mem;
48*490215a3Smrg }
49*490215a3Smrg 
DeallocateFromLocalPool(const void * ptr)50*490215a3Smrg static void DeallocateFromLocalPool(const void *ptr) {
51*490215a3Smrg   // Hack: since glibc 2.27 dlsym no longer uses stack-allocated memory to store
52*490215a3Smrg   // error messages and instead uses malloc followed by free. To avoid pool
53*490215a3Smrg   // exhaustion due to long object filenames, handle that special case here.
54*490215a3Smrg   uptr prev_offset = allocated_for_dlsym - last_dlsym_alloc_size_in_words;
55*490215a3Smrg   void *prev_mem = (void*)&alloc_memory_for_dlsym[prev_offset];
56*490215a3Smrg   if (prev_mem == ptr) {
57*490215a3Smrg     REAL(memset)(prev_mem, 0, last_dlsym_alloc_size_in_words * kWordSize);
58*490215a3Smrg     allocated_for_dlsym = prev_offset;
59*490215a3Smrg     last_dlsym_alloc_size_in_words = 0;
60*490215a3Smrg   }
61*490215a3Smrg }
62*490215a3Smrg 
PosixMemalignFromLocalPool(void ** memptr,uptr alignment,uptr size_in_bytes)63*490215a3Smrg static int PosixMemalignFromLocalPool(void **memptr, uptr alignment,
64*490215a3Smrg                                       uptr size_in_bytes) {
65*490215a3Smrg   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment)))
66*490215a3Smrg     return errno_EINVAL;
67*490215a3Smrg 
68*490215a3Smrg   CHECK(alignment >= kWordSize);
69*490215a3Smrg 
70*490215a3Smrg   uptr addr = (uptr)&alloc_memory_for_dlsym[allocated_for_dlsym];
71*490215a3Smrg   uptr aligned_addr = RoundUpTo(addr, alignment);
72*490215a3Smrg   uptr aligned_size = RoundUpTo(size_in_bytes, kWordSize);
73*490215a3Smrg 
74*490215a3Smrg   uptr *end_mem = (uptr*)(aligned_addr + aligned_size);
75*490215a3Smrg   uptr allocated = end_mem - alloc_memory_for_dlsym;
76*490215a3Smrg   if (allocated >= kDlsymAllocPoolSize)
77*490215a3Smrg     return errno_ENOMEM;
78*490215a3Smrg 
79*490215a3Smrg   allocated_for_dlsym = allocated;
80*490215a3Smrg   *memptr = (void*)aligned_addr;
81*490215a3Smrg   return 0;
82*490215a3Smrg }
83*490215a3Smrg 
84*490215a3Smrg #if SANITIZER_RTEMS
MemalignFromLocalPool(uptr alignment,uptr size)85*490215a3Smrg void* MemalignFromLocalPool(uptr alignment, uptr size) {
86*490215a3Smrg   void *ptr = nullptr;
87*490215a3Smrg   alignment = Max(alignment, kWordSize);
88*490215a3Smrg   PosixMemalignFromLocalPool(&ptr, alignment, size);
89*490215a3Smrg   return ptr;
90*490215a3Smrg }
91*490215a3Smrg 
IsFromLocalPool(const void * ptr)92*490215a3Smrg bool IsFromLocalPool(const void *ptr) {
93*490215a3Smrg   return IsInDlsymAllocPool(ptr);
94*490215a3Smrg }
95*490215a3Smrg #endif
96*490215a3Smrg 
MaybeInDlsym()97*490215a3Smrg static INLINE bool MaybeInDlsym() {
98*490215a3Smrg   // Fuchsia doesn't use dlsym-based interceptors.
99*490215a3Smrg   return !SANITIZER_FUCHSIA && asan_init_is_running;
100*490215a3Smrg }
101*490215a3Smrg 
UseLocalPool()102*490215a3Smrg static INLINE bool UseLocalPool() {
103*490215a3Smrg   return EarlyMalloc() || MaybeInDlsym();
104*490215a3Smrg }
105*490215a3Smrg 
ReallocFromLocalPool(void * ptr,uptr size)106*490215a3Smrg static void *ReallocFromLocalPool(void *ptr, uptr size) {
107*490215a3Smrg   const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
108*490215a3Smrg   const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
109*490215a3Smrg   void *new_ptr;
110*490215a3Smrg   if (UNLIKELY(UseLocalPool())) {
111*490215a3Smrg     new_ptr = AllocateFromLocalPool(size);
112*490215a3Smrg   } else {
113*490215a3Smrg     ENSURE_ASAN_INITED();
114*490215a3Smrg     GET_STACK_TRACE_MALLOC;
115*490215a3Smrg     new_ptr = asan_malloc(size, &stack);
116*490215a3Smrg   }
117*490215a3Smrg   internal_memcpy(new_ptr, ptr, copy_size);
118*490215a3Smrg   return new_ptr;
119*490215a3Smrg }
120*490215a3Smrg 
INTERCEPTOR(void,free,void * ptr)121*490215a3Smrg INTERCEPTOR(void, free, void *ptr) {
122*490215a3Smrg   GET_STACK_TRACE_FREE;
123*490215a3Smrg   if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
124*490215a3Smrg     DeallocateFromLocalPool(ptr);
125*490215a3Smrg     return;
126*490215a3Smrg   }
127*490215a3Smrg   asan_free(ptr, &stack, FROM_MALLOC);
128*490215a3Smrg }
129*490215a3Smrg 
130*490215a3Smrg #if SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void,cfree,void * ptr)131*490215a3Smrg INTERCEPTOR(void, cfree, void *ptr) {
132*490215a3Smrg   GET_STACK_TRACE_FREE;
133*490215a3Smrg   if (UNLIKELY(IsInDlsymAllocPool(ptr)))
134*490215a3Smrg     return;
135*490215a3Smrg   asan_free(ptr, &stack, FROM_MALLOC);
136*490215a3Smrg }
137*490215a3Smrg #endif // SANITIZER_INTERCEPT_CFREE
138*490215a3Smrg 
INTERCEPTOR(void *,malloc,uptr size)139*490215a3Smrg INTERCEPTOR(void*, malloc, uptr size) {
140*490215a3Smrg   if (UNLIKELY(UseLocalPool()))
141*490215a3Smrg     // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
142*490215a3Smrg     return AllocateFromLocalPool(size);
143*490215a3Smrg   ENSURE_ASAN_INITED();
144*490215a3Smrg   GET_STACK_TRACE_MALLOC;
145*490215a3Smrg   return asan_malloc(size, &stack);
146*490215a3Smrg }
147*490215a3Smrg 
INTERCEPTOR(void *,calloc,uptr nmemb,uptr size)148*490215a3Smrg INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
149*490215a3Smrg   if (UNLIKELY(UseLocalPool()))
150*490215a3Smrg     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
151*490215a3Smrg     return AllocateFromLocalPool(nmemb * size);
152*490215a3Smrg   ENSURE_ASAN_INITED();
153*490215a3Smrg   GET_STACK_TRACE_MALLOC;
154*490215a3Smrg   return asan_calloc(nmemb, size, &stack);
155*490215a3Smrg }
156*490215a3Smrg 
INTERCEPTOR(void *,realloc,void * ptr,uptr size)157*490215a3Smrg INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
158*490215a3Smrg   if (UNLIKELY(IsInDlsymAllocPool(ptr)))
159*490215a3Smrg     return ReallocFromLocalPool(ptr, size);
160*490215a3Smrg   if (UNLIKELY(UseLocalPool()))
161*490215a3Smrg     return AllocateFromLocalPool(size);
162*490215a3Smrg   ENSURE_ASAN_INITED();
163*490215a3Smrg   GET_STACK_TRACE_MALLOC;
164*490215a3Smrg   return asan_realloc(ptr, size, &stack);
165*490215a3Smrg }
166*490215a3Smrg 
167*490215a3Smrg #if SANITIZER_INTERCEPT_MEMALIGN
INTERCEPTOR(void *,memalign,uptr boundary,uptr size)168*490215a3Smrg INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
169*490215a3Smrg   GET_STACK_TRACE_MALLOC;
170*490215a3Smrg   return asan_memalign(boundary, size, &stack, FROM_MALLOC);
171*490215a3Smrg }
172*490215a3Smrg 
INTERCEPTOR(void *,__libc_memalign,uptr boundary,uptr size)173*490215a3Smrg INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
174*490215a3Smrg   GET_STACK_TRACE_MALLOC;
175*490215a3Smrg   void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
176*490215a3Smrg   DTLS_on_libc_memalign(res, size);
177*490215a3Smrg   return res;
178*490215a3Smrg }
179*490215a3Smrg #endif // SANITIZER_INTERCEPT_MEMALIGN
180*490215a3Smrg 
181*490215a3Smrg #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
INTERCEPTOR(void *,aligned_alloc,uptr boundary,uptr size)182*490215a3Smrg INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
183*490215a3Smrg   GET_STACK_TRACE_MALLOC;
184*490215a3Smrg   return asan_aligned_alloc(boundary, size, &stack);
185*490215a3Smrg }
186*490215a3Smrg #endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC
187*490215a3Smrg 
INTERCEPTOR(uptr,malloc_usable_size,void * ptr)188*490215a3Smrg INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
189*490215a3Smrg   GET_CURRENT_PC_BP_SP;
190*490215a3Smrg   (void)sp;
191*490215a3Smrg   return asan_malloc_usable_size(ptr, pc, bp);
192*490215a3Smrg }
193*490215a3Smrg 
194*490215a3Smrg #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
195*490215a3Smrg // We avoid including malloc.h for portability reasons.
196*490215a3Smrg // man mallinfo says the fields are "long", but the implementation uses int.
197*490215a3Smrg // It doesn't matter much -- we just need to make sure that the libc's mallinfo
198*490215a3Smrg // is not called.
199*490215a3Smrg struct fake_mallinfo {
200*490215a3Smrg   int x[10];
201*490215a3Smrg };
202*490215a3Smrg 
INTERCEPTOR(struct fake_mallinfo,mallinfo,void)203*490215a3Smrg INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
204*490215a3Smrg   struct fake_mallinfo res;
205*490215a3Smrg   REAL(memset)(&res, 0, sizeof(res));
206*490215a3Smrg   return res;
207*490215a3Smrg }
208*490215a3Smrg 
INTERCEPTOR(int,mallopt,int cmd,int value)209*490215a3Smrg INTERCEPTOR(int, mallopt, int cmd, int value) {
210*490215a3Smrg   return -1;
211*490215a3Smrg }
212*490215a3Smrg #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
213*490215a3Smrg 
INTERCEPTOR(int,posix_memalign,void ** memptr,uptr alignment,uptr size)214*490215a3Smrg INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
215*490215a3Smrg   if (UNLIKELY(UseLocalPool()))
216*490215a3Smrg     return PosixMemalignFromLocalPool(memptr, alignment, size);
217*490215a3Smrg   GET_STACK_TRACE_MALLOC;
218*490215a3Smrg   return asan_posix_memalign(memptr, alignment, size, &stack);
219*490215a3Smrg }
220*490215a3Smrg 
INTERCEPTOR(void *,valloc,uptr size)221*490215a3Smrg INTERCEPTOR(void*, valloc, uptr size) {
222*490215a3Smrg   GET_STACK_TRACE_MALLOC;
223*490215a3Smrg   return asan_valloc(size, &stack);
224*490215a3Smrg }
225*490215a3Smrg 
226*490215a3Smrg #if SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void *,pvalloc,uptr size)227*490215a3Smrg INTERCEPTOR(void*, pvalloc, uptr size) {
228*490215a3Smrg   GET_STACK_TRACE_MALLOC;
229*490215a3Smrg   return asan_pvalloc(size, &stack);
230*490215a3Smrg }
231*490215a3Smrg #endif // SANITIZER_INTERCEPT_PVALLOC
232*490215a3Smrg 
INTERCEPTOR(void,malloc_stats,void)233*490215a3Smrg INTERCEPTOR(void, malloc_stats, void) {
234*490215a3Smrg   __asan_print_accumulated_stats();
235*490215a3Smrg }
236*490215a3Smrg 
237*490215a3Smrg #if SANITIZER_ANDROID
238*490215a3Smrg // Format of __libc_malloc_dispatch has changed in Android L.
239*490215a3Smrg // While we are moving towards a solution that does not depend on bionic
240*490215a3Smrg // internals, here is something to support both K* and L releases.
241*490215a3Smrg struct MallocDebugK {
242*490215a3Smrg   void *(*malloc)(uptr bytes);
243*490215a3Smrg   void (*free)(void *mem);
244*490215a3Smrg   void *(*calloc)(uptr n_elements, uptr elem_size);
245*490215a3Smrg   void *(*realloc)(void *oldMem, uptr bytes);
246*490215a3Smrg   void *(*memalign)(uptr alignment, uptr bytes);
247*490215a3Smrg   uptr (*malloc_usable_size)(void *mem);
248*490215a3Smrg };
249*490215a3Smrg 
250*490215a3Smrg struct MallocDebugL {
251*490215a3Smrg   void *(*calloc)(uptr n_elements, uptr elem_size);
252*490215a3Smrg   void (*free)(void *mem);
253*490215a3Smrg   fake_mallinfo (*mallinfo)(void);
254*490215a3Smrg   void *(*malloc)(uptr bytes);
255*490215a3Smrg   uptr (*malloc_usable_size)(void *mem);
256*490215a3Smrg   void *(*memalign)(uptr alignment, uptr bytes);
257*490215a3Smrg   int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
258*490215a3Smrg   void* (*pvalloc)(uptr size);
259*490215a3Smrg   void *(*realloc)(void *oldMem, uptr bytes);
260*490215a3Smrg   void* (*valloc)(uptr size);
261*490215a3Smrg };
262*490215a3Smrg 
263*490215a3Smrg ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
264*490215a3Smrg     WRAP(malloc),  WRAP(free),     WRAP(calloc),
265*490215a3Smrg     WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
266*490215a3Smrg 
267*490215a3Smrg ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
268*490215a3Smrg     WRAP(calloc),         WRAP(free),               WRAP(mallinfo),
269*490215a3Smrg     WRAP(malloc),         WRAP(malloc_usable_size), WRAP(memalign),
270*490215a3Smrg     WRAP(posix_memalign), WRAP(pvalloc),            WRAP(realloc),
271*490215a3Smrg     WRAP(valloc)};
272*490215a3Smrg 
273*490215a3Smrg namespace __asan {
ReplaceSystemMalloc()274*490215a3Smrg void ReplaceSystemMalloc() {
275*490215a3Smrg   void **__libc_malloc_dispatch_p =
276*490215a3Smrg       (void **)AsanDlSymNext("__libc_malloc_dispatch");
277*490215a3Smrg   if (__libc_malloc_dispatch_p) {
278*490215a3Smrg     // Decide on K vs L dispatch format by the presence of
279*490215a3Smrg     // __libc_malloc_default_dispatch export in libc.
280*490215a3Smrg     void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
281*490215a3Smrg     if (default_dispatch_p)
282*490215a3Smrg       *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
283*490215a3Smrg     else
284*490215a3Smrg       *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
285*490215a3Smrg   }
286*490215a3Smrg }
287*490215a3Smrg }  // namespace __asan
288*490215a3Smrg 
289*490215a3Smrg #else  // SANITIZER_ANDROID
290*490215a3Smrg 
291*490215a3Smrg namespace __asan {
ReplaceSystemMalloc()292*490215a3Smrg void ReplaceSystemMalloc() {
293*490215a3Smrg }
294*490215a3Smrg }  // namespace __asan
295*490215a3Smrg #endif  // SANITIZER_ANDROID
296*490215a3Smrg 
297*490215a3Smrg #endif  // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
298*490215a3Smrg         // SANITIZER_NETBSD || SANITIZER_SOLARIS
299