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