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