]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- msan_interceptors.cc ----------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file is a part of MemorySanitizer. | |
11 | // | |
12 | // Interceptors for standard library functions. | |
13 | // | |
14 | // FIXME: move as many interceptors as possible into | |
15 | // sanitizer_common/sanitizer_common_interceptors.h | |
16 | //===----------------------------------------------------------------------===// | |
17 | ||
92a42be0 | 18 | #include "interception/interception.h" |
1a4d82fc | 19 | #include "msan.h" |
92a42be0 SL |
20 | #include "msan_chained_origin_depot.h" |
21 | #include "msan_origin.h" | |
1a4d82fc | 22 | #include "msan_thread.h" |
92a42be0 | 23 | #include "msan_poisoning.h" |
1a4d82fc JJ |
24 | #include "sanitizer_common/sanitizer_platform_limits_posix.h" |
25 | #include "sanitizer_common/sanitizer_allocator.h" | |
92a42be0 | 26 | #include "sanitizer_common/sanitizer_allocator_interface.h" |
1a4d82fc JJ |
27 | #include "sanitizer_common/sanitizer_allocator_internal.h" |
28 | #include "sanitizer_common/sanitizer_atomic.h" | |
29 | #include "sanitizer_common/sanitizer_common.h" | |
1a4d82fc JJ |
30 | #include "sanitizer_common/sanitizer_stackdepot.h" |
31 | #include "sanitizer_common/sanitizer_libc.h" | |
32 | #include "sanitizer_common/sanitizer_linux.h" | |
92a42be0 | 33 | #include "sanitizer_common/sanitizer_tls_get_addr.h" |
1a4d82fc JJ |
34 | |
35 | #include <stdarg.h> | |
36 | // ACHTUNG! No other system header includes in this file. | |
37 | // Ideally, we should get rid of stdarg.h as well. | |
38 | ||
39 | using namespace __msan; | |
40 | ||
41 | using __sanitizer::memory_order; | |
42 | using __sanitizer::atomic_load; | |
43 | using __sanitizer::atomic_store; | |
44 | using __sanitizer::atomic_uintptr_t; | |
45 | ||
92a42be0 SL |
46 | #if SANITIZER_FREEBSD |
47 | #define __errno_location __error | |
48 | #endif | |
49 | ||
1a4d82fc JJ |
50 | // True if this is a nested interceptor. |
51 | static THREADLOCAL int in_interceptor_scope; | |
52 | ||
53 | extern "C" int *__errno_location(void); | |
54 | ||
55 | struct InterceptorScope { | |
56 | InterceptorScope() { ++in_interceptor_scope; } | |
57 | ~InterceptorScope() { --in_interceptor_scope; } | |
58 | }; | |
59 | ||
60 | bool IsInInterceptorScope() { | |
61 | return in_interceptor_scope; | |
62 | } | |
63 | ||
64 | #define ENSURE_MSAN_INITED() do { \ | |
65 | CHECK(!msan_init_is_running); \ | |
66 | if (!msan_inited) { \ | |
67 | __msan_init(); \ | |
68 | } \ | |
69 | } while (0) | |
70 | ||
71 | // Check that [x, x+n) range is unpoisoned. | |
92a42be0 SL |
72 | #define CHECK_UNPOISONED_0(x, n) \ |
73 | do { \ | |
74 | sptr offset = __msan_test_shadow(x, n); \ | |
75 | if (__msan::IsInSymbolizer()) \ | |
76 | break; \ | |
77 | if (offset >= 0 && __msan::flags()->report_umrs) { \ | |
78 | GET_CALLER_PC_BP_SP; \ | |
79 | (void) sp; \ | |
80 | ReportUMRInsideAddressRange(__func__, x, n, offset); \ | |
81 | __msan::PrintWarningWithOrigin( \ | |
82 | pc, bp, __msan_get_origin((const char *)x + offset)); \ | |
83 | if (__msan::flags()->halt_on_error) { \ | |
84 | Printf("Exiting\n"); \ | |
85 | Die(); \ | |
86 | } \ | |
87 | } \ | |
1a4d82fc JJ |
88 | } while (0) |
89 | ||
90 | // Check that [x, x+n) range is unpoisoned unless we are in a nested | |
91 | // interceptor. | |
92 | #define CHECK_UNPOISONED(x, n) \ | |
93 | do { \ | |
94 | if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \ | |
95 | } while (0); | |
96 | ||
92a42be0 SL |
97 | #define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \ |
98 | CHECK_UNPOISONED((x), \ | |
99 | common_flags()->strict_string_checks ? (len) + 1 : (n) ) | |
100 | ||
101 | #define CHECK_UNPOISONED_STRING(x, n) \ | |
102 | CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n)) | |
1a4d82fc JJ |
103 | |
104 | INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { | |
105 | ENSURE_MSAN_INITED(); | |
106 | SIZE_T res = REAL(fread)(ptr, size, nmemb, file); | |
107 | if (res > 0) | |
108 | __msan_unpoison(ptr, res *size); | |
109 | return res; | |
110 | } | |
111 | ||
92a42be0 | 112 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
113 | INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, |
114 | void *file) { | |
115 | ENSURE_MSAN_INITED(); | |
116 | SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file); | |
117 | if (res > 0) | |
118 | __msan_unpoison(ptr, res *size); | |
119 | return res; | |
120 | } | |
92a42be0 SL |
121 | #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked) |
122 | #else | |
123 | #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED | |
124 | #endif | |
1a4d82fc JJ |
125 | |
126 | INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { | |
127 | ENSURE_MSAN_INITED(); | |
92a42be0 | 128 | CHECK_UNPOISONED_STRING(path, 0) |
1a4d82fc JJ |
129 | SSIZE_T res = REAL(readlink)(path, buf, bufsiz); |
130 | if (res > 0) | |
131 | __msan_unpoison(buf, res); | |
132 | return res; | |
133 | } | |
134 | ||
135 | INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) { | |
136 | return __msan_memcpy(dest, src, n); | |
137 | } | |
138 | ||
139 | INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) { | |
140 | return (char *)__msan_memcpy(dest, src, n) + n; | |
141 | } | |
142 | ||
143 | INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) { | |
144 | ENSURE_MSAN_INITED(); | |
145 | void *res = REAL(memccpy)(dest, src, c, n); | |
146 | CHECK(!res || (res >= dest && res <= (char *)dest + n)); | |
147 | SIZE_T sz = res ? (char *)res - (char *)dest : n; | |
148 | CHECK_UNPOISONED(src, sz); | |
149 | __msan_unpoison(dest, sz); | |
150 | return res; | |
151 | } | |
152 | ||
153 | INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) { | |
154 | return __msan_memmove(dest, src, n); | |
155 | } | |
156 | ||
157 | INTERCEPTOR(void *, memset, void *s, int c, SIZE_T n) { | |
158 | return __msan_memset(s, c, n); | |
159 | } | |
160 | ||
161 | INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) { | |
162 | return __msan_memmove(dest, src, n); | |
163 | } | |
164 | ||
165 | INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { | |
166 | GET_MALLOC_STACK_TRACE; | |
167 | CHECK_EQ(alignment & (alignment - 1), 0); | |
168 | CHECK_NE(memptr, 0); | |
92a42be0 | 169 | *memptr = MsanReallocate(&stack, nullptr, size, alignment, false); |
1a4d82fc JJ |
170 | CHECK_NE(*memptr, 0); |
171 | __msan_unpoison(memptr, sizeof(*memptr)); | |
172 | return 0; | |
173 | } | |
174 | ||
92a42be0 | 175 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
176 | INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) { |
177 | GET_MALLOC_STACK_TRACE; | |
178 | CHECK_EQ(boundary & (boundary - 1), 0); | |
92a42be0 | 179 | void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); |
1a4d82fc JJ |
180 | return ptr; |
181 | } | |
92a42be0 SL |
182 | #define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) |
183 | #else | |
184 | #define MSAN_MAYBE_INTERCEPT_MEMALIGN | |
185 | #endif | |
1a4d82fc | 186 | |
92a42be0 SL |
187 | INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) { |
188 | GET_MALLOC_STACK_TRACE; | |
189 | CHECK_EQ(boundary & (boundary - 1), 0); | |
190 | void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); | |
191 | return ptr; | |
192 | } | |
193 | ||
194 | INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) { | |
195 | GET_MALLOC_STACK_TRACE; | |
196 | CHECK_EQ(boundary & (boundary - 1), 0); | |
197 | void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); | |
198 | DTLS_on_libc_memalign(ptr, size * boundary); | |
199 | return ptr; | |
200 | } | |
1a4d82fc JJ |
201 | |
202 | INTERCEPTOR(void *, valloc, SIZE_T size) { | |
203 | GET_MALLOC_STACK_TRACE; | |
92a42be0 | 204 | void *ptr = MsanReallocate(&stack, nullptr, size, GetPageSizeCached(), false); |
1a4d82fc JJ |
205 | return ptr; |
206 | } | |
207 | ||
92a42be0 | 208 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
209 | INTERCEPTOR(void *, pvalloc, SIZE_T size) { |
210 | GET_MALLOC_STACK_TRACE; | |
211 | uptr PageSize = GetPageSizeCached(); | |
212 | size = RoundUpTo(size, PageSize); | |
213 | if (size == 0) { | |
214 | // pvalloc(0) should allocate one page. | |
215 | size = PageSize; | |
216 | } | |
92a42be0 | 217 | void *ptr = MsanReallocate(&stack, nullptr, size, PageSize, false); |
1a4d82fc JJ |
218 | return ptr; |
219 | } | |
92a42be0 SL |
220 | #define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) |
221 | #else | |
222 | #define MSAN_MAYBE_INTERCEPT_PVALLOC | |
223 | #endif | |
1a4d82fc JJ |
224 | |
225 | INTERCEPTOR(void, free, void *ptr) { | |
226 | GET_MALLOC_STACK_TRACE; | |
92a42be0 | 227 | if (!ptr) return; |
1a4d82fc JJ |
228 | MsanDeallocate(&stack, ptr); |
229 | } | |
230 | ||
92a42be0 | 231 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
232 | INTERCEPTOR(void, cfree, void *ptr) { |
233 | GET_MALLOC_STACK_TRACE; | |
92a42be0 | 234 | if (!ptr) return; |
1a4d82fc JJ |
235 | MsanDeallocate(&stack, ptr); |
236 | } | |
92a42be0 SL |
237 | #define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree) |
238 | #else | |
239 | #define MSAN_MAYBE_INTERCEPT_CFREE | |
240 | #endif | |
1a4d82fc JJ |
241 | |
242 | INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { | |
92a42be0 | 243 | return __sanitizer_get_allocated_size(ptr); |
1a4d82fc JJ |
244 | } |
245 | ||
92a42be0 | 246 | #if !SANITIZER_FREEBSD |
1a4d82fc | 247 | // This function actually returns a struct by value, but we can't unpoison a |
92a42be0 SL |
248 | // temporary! The following is equivalent on all supported platforms but |
249 | // aarch64 (which uses a different register for sret value). We have a test | |
250 | // to confirm that. | |
1a4d82fc | 251 | INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) { |
92a42be0 SL |
252 | #ifdef __aarch64__ |
253 | uptr r8; | |
254 | asm volatile("mov %0,x8" : "=r" (r8)); | |
255 | sret = reinterpret_cast<__sanitizer_mallinfo*>(r8); | |
256 | #endif | |
1a4d82fc JJ |
257 | REAL(memset)(sret, 0, sizeof(*sret)); |
258 | __msan_unpoison(sret, sizeof(*sret)); | |
259 | } | |
92a42be0 SL |
260 | #define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo) |
261 | #else | |
262 | #define MSAN_MAYBE_INTERCEPT_MALLINFO | |
263 | #endif | |
1a4d82fc | 264 | |
92a42be0 | 265 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
266 | INTERCEPTOR(int, mallopt, int cmd, int value) { |
267 | return -1; | |
268 | } | |
92a42be0 SL |
269 | #define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt) |
270 | #else | |
271 | #define MSAN_MAYBE_INTERCEPT_MALLOPT | |
272 | #endif | |
1a4d82fc | 273 | |
92a42be0 | 274 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
275 | INTERCEPTOR(void, malloc_stats, void) { |
276 | // FIXME: implement, but don't call REAL(malloc_stats)! | |
277 | } | |
92a42be0 SL |
278 | #define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats) |
279 | #else | |
280 | #define MSAN_MAYBE_INTERCEPT_MALLOC_STATS | |
281 | #endif | |
1a4d82fc JJ |
282 | |
283 | INTERCEPTOR(SIZE_T, strlen, const char *s) { | |
92a42be0 SL |
284 | if (msan_init_is_running) |
285 | return REAL(strlen)(s); | |
1a4d82fc JJ |
286 | ENSURE_MSAN_INITED(); |
287 | SIZE_T res = REAL(strlen)(s); | |
288 | CHECK_UNPOISONED(s, res + 1); | |
289 | return res; | |
290 | } | |
291 | ||
292 | INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) { | |
293 | ENSURE_MSAN_INITED(); | |
294 | SIZE_T res = REAL(strnlen)(s, n); | |
295 | SIZE_T scan_size = (res == n) ? res : res + 1; | |
296 | CHECK_UNPOISONED(s, scan_size); | |
297 | return res; | |
298 | } | |
299 | ||
1a4d82fc JJ |
300 | INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT |
301 | ENSURE_MSAN_INITED(); | |
302 | GET_STORE_STACK_TRACE; | |
303 | SIZE_T n = REAL(strlen)(src); | |
92a42be0 | 304 | CHECK_UNPOISONED_STRING(src + n, 0); |
1a4d82fc | 305 | char *res = REAL(strcpy)(dest, src); // NOLINT |
92a42be0 | 306 | CopyShadowAndOrigin(dest, src, n + 1, &stack); |
1a4d82fc JJ |
307 | return res; |
308 | } | |
309 | ||
310 | INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT | |
311 | ENSURE_MSAN_INITED(); | |
312 | GET_STORE_STACK_TRACE; | |
313 | SIZE_T copy_size = REAL(strnlen)(src, n); | |
314 | if (copy_size < n) | |
315 | copy_size++; // trailing \0 | |
316 | char *res = REAL(strncpy)(dest, src, n); // NOLINT | |
92a42be0 SL |
317 | CopyShadowAndOrigin(dest, src, copy_size, &stack); |
318 | __msan_unpoison(dest + copy_size, n - copy_size); | |
1a4d82fc JJ |
319 | return res; |
320 | } | |
321 | ||
322 | INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT | |
323 | ENSURE_MSAN_INITED(); | |
324 | GET_STORE_STACK_TRACE; | |
325 | SIZE_T n = REAL(strlen)(src); | |
92a42be0 | 326 | CHECK_UNPOISONED_STRING(src + n, 0); |
1a4d82fc | 327 | char *res = REAL(stpcpy)(dest, src); // NOLINT |
92a42be0 | 328 | CopyShadowAndOrigin(dest, src, n + 1, &stack); |
1a4d82fc JJ |
329 | return res; |
330 | } | |
331 | ||
332 | INTERCEPTOR(char *, strdup, char *src) { | |
333 | ENSURE_MSAN_INITED(); | |
334 | GET_STORE_STACK_TRACE; | |
92a42be0 SL |
335 | // On FreeBSD strdup() leverages strlen(). |
336 | InterceptorScope interceptor_scope; | |
1a4d82fc | 337 | SIZE_T n = REAL(strlen)(src); |
92a42be0 | 338 | CHECK_UNPOISONED_STRING(src + n, 0); |
1a4d82fc | 339 | char *res = REAL(strdup)(src); |
92a42be0 | 340 | CopyShadowAndOrigin(res, src, n + 1, &stack); |
1a4d82fc JJ |
341 | return res; |
342 | } | |
343 | ||
92a42be0 | 344 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
345 | INTERCEPTOR(char *, __strdup, char *src) { |
346 | ENSURE_MSAN_INITED(); | |
347 | GET_STORE_STACK_TRACE; | |
348 | SIZE_T n = REAL(strlen)(src); | |
92a42be0 | 349 | CHECK_UNPOISONED_STRING(src + n, 0); |
1a4d82fc | 350 | char *res = REAL(__strdup)(src); |
92a42be0 | 351 | CopyShadowAndOrigin(res, src, n + 1, &stack); |
1a4d82fc JJ |
352 | return res; |
353 | } | |
92a42be0 SL |
354 | #define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup) |
355 | #else | |
356 | #define MSAN_MAYBE_INTERCEPT___STRDUP | |
357 | #endif | |
1a4d82fc JJ |
358 | |
359 | INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { | |
360 | ENSURE_MSAN_INITED(); | |
361 | GET_STORE_STACK_TRACE; | |
92a42be0 SL |
362 | // On FreeBSD strndup() leverages strnlen(). |
363 | InterceptorScope interceptor_scope; | |
1a4d82fc JJ |
364 | SIZE_T copy_size = REAL(strnlen)(src, n); |
365 | char *res = REAL(strndup)(src, n); | |
92a42be0 | 366 | CopyShadowAndOrigin(res, src, copy_size, &stack); |
1a4d82fc JJ |
367 | __msan_unpoison(res + copy_size, 1); // \0 |
368 | return res; | |
369 | } | |
370 | ||
92a42be0 | 371 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
372 | INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { |
373 | ENSURE_MSAN_INITED(); | |
374 | GET_STORE_STACK_TRACE; | |
375 | SIZE_T copy_size = REAL(strnlen)(src, n); | |
376 | char *res = REAL(__strndup)(src, n); | |
92a42be0 | 377 | CopyShadowAndOrigin(res, src, copy_size, &stack); |
1a4d82fc JJ |
378 | __msan_unpoison(res + copy_size, 1); // \0 |
379 | return res; | |
380 | } | |
92a42be0 SL |
381 | #define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) |
382 | #else | |
383 | #define MSAN_MAYBE_INTERCEPT___STRNDUP | |
384 | #endif | |
1a4d82fc JJ |
385 | |
386 | INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { | |
387 | ENSURE_MSAN_INITED(); | |
388 | char *res = REAL(gcvt)(number, ndigit, buf); | |
92a42be0 SL |
389 | SIZE_T n = REAL(strlen)(buf); |
390 | __msan_unpoison(buf, n + 1); | |
1a4d82fc JJ |
391 | return res; |
392 | } | |
393 | ||
394 | INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT | |
395 | ENSURE_MSAN_INITED(); | |
396 | GET_STORE_STACK_TRACE; | |
397 | SIZE_T src_size = REAL(strlen)(src); | |
398 | SIZE_T dest_size = REAL(strlen)(dest); | |
92a42be0 SL |
399 | CHECK_UNPOISONED_STRING(src + src_size, 0); |
400 | CHECK_UNPOISONED_STRING(dest + dest_size, 0); | |
1a4d82fc | 401 | char *res = REAL(strcat)(dest, src); // NOLINT |
92a42be0 | 402 | CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack); |
1a4d82fc JJ |
403 | return res; |
404 | } | |
405 | ||
406 | INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT | |
407 | ENSURE_MSAN_INITED(); | |
408 | GET_STORE_STACK_TRACE; | |
409 | SIZE_T dest_size = REAL(strlen)(dest); | |
410 | SIZE_T copy_size = REAL(strnlen)(src, n); | |
92a42be0 | 411 | CHECK_UNPOISONED_STRING(dest + dest_size, 0); |
1a4d82fc | 412 | char *res = REAL(strncat)(dest, src, n); // NOLINT |
92a42be0 | 413 | CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack); |
1a4d82fc JJ |
414 | __msan_unpoison(dest + dest_size + copy_size, 1); // \0 |
415 | return res; | |
416 | } | |
417 | ||
418 | // Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to | |
419 | // deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO. | |
420 | #define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \ | |
421 | ENSURE_MSAN_INITED(); \ | |
422 | ret_type res = REAL(func)(__VA_ARGS__); \ | |
92a42be0 | 423 | __msan_unpoison(endptr, sizeof(*endptr)); \ |
1a4d82fc JJ |
424 | return res; |
425 | ||
92a42be0 SL |
426 | #define INTERCEPTOR_STRTO(ret_type, func, char_type) \ |
427 | INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \ | |
428 | INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \ | |
1a4d82fc JJ |
429 | } |
430 | ||
92a42be0 SL |
431 | #define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \ |
432 | INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ | |
433 | int base) { \ | |
434 | INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \ | |
1a4d82fc JJ |
435 | } |
436 | ||
92a42be0 SL |
437 | #define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \ |
438 | INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ | |
1a4d82fc | 439 | void *loc) { \ |
92a42be0 | 440 | INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \ |
1a4d82fc JJ |
441 | } |
442 | ||
92a42be0 SL |
443 | #define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \ |
444 | INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ | |
445 | int base, void *loc) { \ | |
446 | INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \ | |
1a4d82fc | 447 | } |
1a4d82fc | 448 | |
92a42be0 SL |
449 | #define INTERCEPTORS_STRTO(ret_type, func, char_type) \ |
450 | INTERCEPTOR_STRTO(ret_type, func, char_type) \ | |
451 | INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \ | |
452 | INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \ | |
453 | INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type) | |
454 | ||
455 | #define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \ | |
456 | INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \ | |
457 | INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \ | |
458 | INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \ | |
459 | INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type) | |
460 | ||
461 | INTERCEPTORS_STRTO(double, strtod, char) // NOLINT | |
462 | INTERCEPTORS_STRTO(float, strtof, char) // NOLINT | |
463 | INTERCEPTORS_STRTO(long double, strtold, char) // NOLINT | |
464 | INTERCEPTORS_STRTO_BASE(long, strtol, char) // NOLINT | |
465 | INTERCEPTORS_STRTO_BASE(long long, strtoll, char) // NOLINT | |
466 | INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) // NOLINT | |
467 | INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) // NOLINT | |
468 | ||
469 | INTERCEPTORS_STRTO(double, wcstod, wchar_t) // NOLINT | |
470 | INTERCEPTORS_STRTO(float, wcstof, wchar_t) // NOLINT | |
471 | INTERCEPTORS_STRTO(long double, wcstold, wchar_t) // NOLINT | |
472 | INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) // NOLINT | |
473 | INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) // NOLINT | |
474 | INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) // NOLINT | |
475 | INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) // NOLINT | |
476 | ||
477 | #define INTERCEPT_STRTO(func) \ | |
478 | INTERCEPT_FUNCTION(func); \ | |
479 | INTERCEPT_FUNCTION(func##_l); \ | |
480 | INTERCEPT_FUNCTION(__##func##_l); \ | |
481 | INTERCEPT_FUNCTION(__##func##_internal); | |
482 | ||
483 | ||
484 | // FIXME: support *wprintf in common format interceptors. | |
1a4d82fc JJ |
485 | INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) { |
486 | ENSURE_MSAN_INITED(); | |
487 | int res = REAL(vswprintf)(str, size, format, ap); | |
92a42be0 | 488 | if (res >= 0) { |
1a4d82fc JJ |
489 | __msan_unpoison(str, 4 * (res + 1)); |
490 | } | |
491 | return res; | |
492 | } | |
493 | ||
92a42be0 | 494 | INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) { |
1a4d82fc JJ |
495 | ENSURE_MSAN_INITED(); |
496 | va_list ap; | |
497 | va_start(ap, format); | |
92a42be0 | 498 | int res = vswprintf(str, size, format, ap); |
1a4d82fc JJ |
499 | va_end(ap); |
500 | return res; | |
501 | } | |
502 | ||
92a42be0 | 503 | INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) { |
1a4d82fc | 504 | ENSURE_MSAN_INITED(); |
92a42be0 SL |
505 | CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); |
506 | SIZE_T res = REAL(strxfrm)(dest, src, n); | |
507 | if (res < n) __msan_unpoison(dest, res + 1); | |
1a4d82fc JJ |
508 | return res; |
509 | } | |
510 | ||
92a42be0 SL |
511 | INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n, |
512 | void *loc) { | |
1a4d82fc | 513 | ENSURE_MSAN_INITED(); |
92a42be0 SL |
514 | CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); |
515 | SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc); | |
516 | if (res < n) __msan_unpoison(dest, res + 1); | |
1a4d82fc JJ |
517 | return res; |
518 | } | |
519 | ||
520 | #define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \ | |
521 | ENSURE_MSAN_INITED(); \ | |
522 | ret_type res = REAL(func)(s, __VA_ARGS__); \ | |
523 | if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \ | |
524 | return res; | |
525 | ||
526 | INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format, | |
527 | __sanitizer_tm *tm) { | |
528 | INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm); | |
529 | } | |
530 | ||
531 | INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format, | |
532 | __sanitizer_tm *tm, void *loc) { | |
533 | INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc); | |
534 | } | |
535 | ||
92a42be0 | 536 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
537 | INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format, |
538 | __sanitizer_tm *tm, void *loc) { | |
539 | INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm, | |
540 | loc); | |
541 | } | |
92a42be0 SL |
542 | #define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l) |
543 | #else | |
544 | #define MSAN_MAYBE_INTERCEPT___STRFTIME_L | |
545 | #endif | |
1a4d82fc JJ |
546 | |
547 | INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format, | |
548 | __sanitizer_tm *tm) { | |
549 | INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm); | |
550 | } | |
551 | ||
552 | INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, | |
553 | __sanitizer_tm *tm, void *loc) { | |
554 | INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm, | |
555 | loc); | |
556 | } | |
557 | ||
92a42be0 | 558 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
559 | INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, |
560 | __sanitizer_tm *tm, void *loc) { | |
561 | INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm, | |
562 | loc); | |
563 | } | |
92a42be0 SL |
564 | #define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l) |
565 | #else | |
566 | #define MSAN_MAYBE_INTERCEPT___WCSFTIME_L | |
567 | #endif | |
1a4d82fc JJ |
568 | |
569 | INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) { | |
570 | ENSURE_MSAN_INITED(); | |
571 | int res = REAL(mbtowc)(dest, src, n); | |
572 | if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t)); | |
573 | return res; | |
574 | } | |
575 | ||
576 | INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) { | |
577 | ENSURE_MSAN_INITED(); | |
578 | SIZE_T res = REAL(mbrtowc)(dest, src, n, ps); | |
579 | if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t)); | |
580 | return res; | |
581 | } | |
582 | ||
583 | INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { | |
584 | ENSURE_MSAN_INITED(); | |
585 | SIZE_T res = REAL(wcslen)(s); | |
586 | CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1)); | |
587 | return res; | |
588 | } | |
589 | ||
590 | // wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); | |
591 | INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { | |
592 | ENSURE_MSAN_INITED(); | |
593 | wchar_t *res = REAL(wcschr)(s, wc, ps); | |
594 | return res; | |
595 | } | |
596 | ||
597 | // wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); | |
598 | INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { | |
599 | ENSURE_MSAN_INITED(); | |
600 | GET_STORE_STACK_TRACE; | |
601 | wchar_t *res = REAL(wcscpy)(dest, src); | |
92a42be0 SL |
602 | CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), |
603 | &stack); | |
1a4d82fc JJ |
604 | return res; |
605 | } | |
606 | ||
607 | // wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n); | |
608 | INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { | |
609 | ENSURE_MSAN_INITED(); | |
610 | GET_STORE_STACK_TRACE; | |
611 | wchar_t *res = REAL(wmemcpy)(dest, src, n); | |
92a42be0 | 612 | CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); |
1a4d82fc JJ |
613 | return res; |
614 | } | |
615 | ||
616 | INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { | |
617 | ENSURE_MSAN_INITED(); | |
618 | GET_STORE_STACK_TRACE; | |
619 | wchar_t *res = REAL(wmempcpy)(dest, src, n); | |
92a42be0 | 620 | CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); |
1a4d82fc JJ |
621 | return res; |
622 | } | |
623 | ||
624 | INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) { | |
625 | CHECK(MEM_IS_APP(s)); | |
626 | ENSURE_MSAN_INITED(); | |
92a42be0 | 627 | wchar_t *res = REAL(wmemset)(s, c, n); |
1a4d82fc JJ |
628 | __msan_unpoison(s, n * sizeof(wchar_t)); |
629 | return res; | |
630 | } | |
631 | ||
632 | INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) { | |
633 | ENSURE_MSAN_INITED(); | |
634 | GET_STORE_STACK_TRACE; | |
635 | wchar_t *res = REAL(wmemmove)(dest, src, n); | |
92a42be0 | 636 | MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); |
1a4d82fc JJ |
637 | return res; |
638 | } | |
639 | ||
640 | INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) { | |
641 | ENSURE_MSAN_INITED(); | |
642 | int res = REAL(wcscmp)(s1, s2); | |
643 | return res; | |
644 | } | |
645 | ||
1a4d82fc JJ |
646 | INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { |
647 | ENSURE_MSAN_INITED(); | |
648 | int res = REAL(gettimeofday)(tv, tz); | |
649 | if (tv) | |
650 | __msan_unpoison(tv, 16); | |
651 | if (tz) | |
652 | __msan_unpoison(tz, 8); | |
653 | return res; | |
654 | } | |
655 | ||
656 | INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) { | |
657 | ENSURE_MSAN_INITED(); | |
658 | char *res = REAL(fcvt)(x, a, b, c); | |
92a42be0 SL |
659 | __msan_unpoison(b, sizeof(*b)); |
660 | __msan_unpoison(c, sizeof(*c)); | |
661 | if (res) __msan_unpoison(res, REAL(strlen)(res) + 1); | |
1a4d82fc JJ |
662 | return res; |
663 | } | |
664 | ||
665 | INTERCEPTOR(char *, getenv, char *name) { | |
92a42be0 SL |
666 | if (msan_init_is_running) |
667 | return REAL(getenv)(name); | |
1a4d82fc JJ |
668 | ENSURE_MSAN_INITED(); |
669 | char *res = REAL(getenv)(name); | |
92a42be0 | 670 | if (res) __msan_unpoison(res, REAL(strlen)(res) + 1); |
1a4d82fc JJ |
671 | return res; |
672 | } | |
673 | ||
674 | extern char **environ; | |
675 | ||
676 | static void UnpoisonEnviron() { | |
677 | char **envp = environ; | |
678 | for (; *envp; ++envp) { | |
679 | __msan_unpoison(envp, sizeof(*envp)); | |
680 | __msan_unpoison(*envp, REAL(strlen)(*envp) + 1); | |
681 | } | |
682 | // Trailing NULL pointer. | |
683 | __msan_unpoison(envp, sizeof(*envp)); | |
684 | } | |
685 | ||
686 | INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) { | |
687 | ENSURE_MSAN_INITED(); | |
92a42be0 | 688 | CHECK_UNPOISONED_STRING(name, 0) |
1a4d82fc JJ |
689 | int res = REAL(setenv)(name, value, overwrite); |
690 | if (!res) UnpoisonEnviron(); | |
691 | return res; | |
692 | } | |
693 | ||
694 | INTERCEPTOR(int, putenv, char *string) { | |
695 | ENSURE_MSAN_INITED(); | |
696 | int res = REAL(putenv)(string); | |
697 | if (!res) UnpoisonEnviron(); | |
698 | return res; | |
699 | } | |
700 | ||
92a42be0 | 701 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
702 | INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) { |
703 | ENSURE_MSAN_INITED(); | |
704 | int res = REAL(__fxstat)(magic, fd, buf); | |
705 | if (!res) | |
706 | __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
707 | return res; | |
708 | } | |
92a42be0 SL |
709 | #define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat) |
710 | #else | |
711 | #define MSAN_MAYBE_INTERCEPT___FXSTAT | |
712 | #endif | |
1a4d82fc | 713 | |
92a42be0 | 714 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
715 | INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) { |
716 | ENSURE_MSAN_INITED(); | |
717 | int res = REAL(__fxstat64)(magic, fd, buf); | |
718 | if (!res) | |
719 | __msan_unpoison(buf, __sanitizer::struct_stat64_sz); | |
720 | return res; | |
721 | } | |
92a42be0 SL |
722 | #define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64) |
723 | #else | |
724 | #define MSAN_MAYBE_INTERCEPT___FXSTAT64 | |
725 | #endif | |
1a4d82fc | 726 | |
92a42be0 SL |
727 | #if SANITIZER_FREEBSD |
728 | INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) { | |
729 | ENSURE_MSAN_INITED(); | |
730 | int res = REAL(fstatat)(fd, pathname, buf, flags); | |
731 | if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
732 | return res; | |
733 | } | |
734 | # define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(fstatat) | |
735 | #else | |
1a4d82fc JJ |
736 | INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf, |
737 | int flags) { | |
738 | ENSURE_MSAN_INITED(); | |
739 | int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags); | |
740 | if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
741 | return res; | |
742 | } | |
92a42be0 SL |
743 | # define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(__fxstatat) |
744 | #endif | |
1a4d82fc | 745 | |
92a42be0 | 746 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
747 | INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf, |
748 | int flags) { | |
749 | ENSURE_MSAN_INITED(); | |
750 | int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags); | |
751 | if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz); | |
752 | return res; | |
753 | } | |
92a42be0 SL |
754 | #define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64) |
755 | #else | |
756 | #define MSAN_MAYBE_INTERCEPT___FXSTATAT64 | |
757 | #endif | |
1a4d82fc | 758 | |
92a42be0 SL |
759 | #if SANITIZER_FREEBSD |
760 | INTERCEPTOR(int, stat, char *path, void *buf) { | |
761 | ENSURE_MSAN_INITED(); | |
762 | int res = REAL(stat)(path, buf); | |
763 | if (!res) | |
764 | __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
765 | return res; | |
766 | } | |
767 | # define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(stat) | |
768 | #else | |
1a4d82fc JJ |
769 | INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) { |
770 | ENSURE_MSAN_INITED(); | |
771 | int res = REAL(__xstat)(magic, path, buf); | |
772 | if (!res) | |
773 | __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
774 | return res; | |
775 | } | |
92a42be0 SL |
776 | # define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(__xstat) |
777 | #endif | |
1a4d82fc | 778 | |
92a42be0 | 779 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
780 | INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) { |
781 | ENSURE_MSAN_INITED(); | |
782 | int res = REAL(__xstat64)(magic, path, buf); | |
783 | if (!res) | |
784 | __msan_unpoison(buf, __sanitizer::struct_stat64_sz); | |
785 | return res; | |
786 | } | |
92a42be0 SL |
787 | #define MSAN_MAYBE_INTERCEPT___XSTAT64 INTERCEPT_FUNCTION(__xstat64) |
788 | #else | |
789 | #define MSAN_MAYBE_INTERCEPT___XSTAT64 | |
790 | #endif | |
1a4d82fc | 791 | |
92a42be0 | 792 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
793 | INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) { |
794 | ENSURE_MSAN_INITED(); | |
795 | int res = REAL(__lxstat)(magic, path, buf); | |
796 | if (!res) | |
797 | __msan_unpoison(buf, __sanitizer::struct_stat_sz); | |
798 | return res; | |
799 | } | |
92a42be0 SL |
800 | #define MSAN_MAYBE_INTERCEPT___LXSTAT INTERCEPT_FUNCTION(__lxstat) |
801 | #else | |
802 | #define MSAN_MAYBE_INTERCEPT___LXSTAT | |
803 | #endif | |
1a4d82fc | 804 | |
92a42be0 | 805 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
806 | INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) { |
807 | ENSURE_MSAN_INITED(); | |
808 | int res = REAL(__lxstat64)(magic, path, buf); | |
809 | if (!res) | |
810 | __msan_unpoison(buf, __sanitizer::struct_stat64_sz); | |
811 | return res; | |
812 | } | |
92a42be0 SL |
813 | #define MSAN_MAYBE_INTERCEPT___LXSTAT64 INTERCEPT_FUNCTION(__lxstat64) |
814 | #else | |
815 | #define MSAN_MAYBE_INTERCEPT___LXSTAT64 | |
816 | #endif | |
1a4d82fc JJ |
817 | |
818 | INTERCEPTOR(int, pipe, int pipefd[2]) { | |
819 | if (msan_init_is_running) | |
820 | return REAL(pipe)(pipefd); | |
821 | ENSURE_MSAN_INITED(); | |
822 | int res = REAL(pipe)(pipefd); | |
823 | if (!res) | |
824 | __msan_unpoison(pipefd, sizeof(int[2])); | |
825 | return res; | |
826 | } | |
827 | ||
828 | INTERCEPTOR(int, pipe2, int pipefd[2], int flags) { | |
829 | ENSURE_MSAN_INITED(); | |
830 | int res = REAL(pipe2)(pipefd, flags); | |
831 | if (!res) | |
832 | __msan_unpoison(pipefd, sizeof(int[2])); | |
833 | return res; | |
834 | } | |
835 | ||
836 | INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) { | |
837 | ENSURE_MSAN_INITED(); | |
838 | int res = REAL(socketpair)(domain, type, protocol, sv); | |
839 | if (!res) | |
840 | __msan_unpoison(sv, sizeof(int[2])); | |
841 | return res; | |
842 | } | |
843 | ||
844 | INTERCEPTOR(char *, fgets, char *s, int size, void *stream) { | |
845 | ENSURE_MSAN_INITED(); | |
846 | char *res = REAL(fgets)(s, size, stream); | |
847 | if (res) | |
848 | __msan_unpoison(s, REAL(strlen)(s) + 1); | |
849 | return res; | |
850 | } | |
851 | ||
92a42be0 | 852 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
853 | INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) { |
854 | ENSURE_MSAN_INITED(); | |
855 | char *res = REAL(fgets_unlocked)(s, size, stream); | |
856 | if (res) | |
857 | __msan_unpoison(s, REAL(strlen)(s) + 1); | |
858 | return res; | |
859 | } | |
92a42be0 SL |
860 | #define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked) |
861 | #else | |
862 | #define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED | |
863 | #endif | |
1a4d82fc JJ |
864 | |
865 | INTERCEPTOR(int, getrlimit, int resource, void *rlim) { | |
866 | if (msan_init_is_running) | |
867 | return REAL(getrlimit)(resource, rlim); | |
868 | ENSURE_MSAN_INITED(); | |
869 | int res = REAL(getrlimit)(resource, rlim); | |
870 | if (!res) | |
871 | __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz); | |
872 | return res; | |
873 | } | |
874 | ||
92a42be0 | 875 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
876 | INTERCEPTOR(int, getrlimit64, int resource, void *rlim) { |
877 | if (msan_init_is_running) | |
878 | return REAL(getrlimit64)(resource, rlim); | |
879 | ENSURE_MSAN_INITED(); | |
880 | int res = REAL(getrlimit64)(resource, rlim); | |
881 | if (!res) | |
882 | __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz); | |
883 | return res; | |
884 | } | |
92a42be0 SL |
885 | #define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64) |
886 | #else | |
887 | #define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 | |
888 | #endif | |
1a4d82fc | 889 | |
92a42be0 SL |
890 | #if SANITIZER_FREEBSD |
891 | // FreeBSD's <sys/utsname.h> define uname() as | |
892 | // static __inline int uname(struct utsname *name) { | |
893 | // return __xuname(SYS_NMLN, (void*)name); | |
894 | // } | |
895 | INTERCEPTOR(int, __xuname, int size, void *utsname) { | |
896 | ENSURE_MSAN_INITED(); | |
897 | int res = REAL(__xuname)(size, utsname); | |
898 | if (!res) | |
899 | __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); | |
900 | return res; | |
901 | } | |
902 | #define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname) | |
903 | #else | |
904 | INTERCEPTOR(int, uname, struct utsname *utsname) { | |
1a4d82fc JJ |
905 | ENSURE_MSAN_INITED(); |
906 | int res = REAL(uname)(utsname); | |
92a42be0 | 907 | if (!res) |
1a4d82fc | 908 | __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); |
1a4d82fc JJ |
909 | return res; |
910 | } | |
92a42be0 SL |
911 | #define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname) |
912 | #endif | |
1a4d82fc JJ |
913 | |
914 | INTERCEPTOR(int, gethostname, char *name, SIZE_T len) { | |
915 | ENSURE_MSAN_INITED(); | |
916 | int res = REAL(gethostname)(name, len); | |
917 | if (!res) { | |
918 | SIZE_T real_len = REAL(strnlen)(name, len); | |
919 | if (real_len < len) | |
920 | ++real_len; | |
921 | __msan_unpoison(name, real_len); | |
922 | } | |
923 | return res; | |
924 | } | |
925 | ||
92a42be0 | 926 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
927 | INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents, |
928 | int timeout) { | |
929 | ENSURE_MSAN_INITED(); | |
930 | int res = REAL(epoll_wait)(epfd, events, maxevents, timeout); | |
931 | if (res > 0) { | |
932 | __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res); | |
933 | } | |
934 | return res; | |
935 | } | |
92a42be0 SL |
936 | #define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait) |
937 | #else | |
938 | #define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT | |
939 | #endif | |
1a4d82fc | 940 | |
92a42be0 | 941 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
942 | INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents, |
943 | int timeout, void *sigmask) { | |
944 | ENSURE_MSAN_INITED(); | |
945 | int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask); | |
946 | if (res > 0) { | |
947 | __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res); | |
948 | } | |
949 | return res; | |
950 | } | |
92a42be0 SL |
951 | #define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait) |
952 | #else | |
953 | #define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT | |
954 | #endif | |
1a4d82fc JJ |
955 | |
956 | INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) { | |
957 | ENSURE_MSAN_INITED(); | |
958 | SSIZE_T res = REAL(recv)(fd, buf, len, flags); | |
959 | if (res > 0) | |
960 | __msan_unpoison(buf, res); | |
961 | return res; | |
962 | } | |
963 | ||
964 | INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags, | |
965 | void *srcaddr, int *addrlen) { | |
966 | ENSURE_MSAN_INITED(); | |
967 | SIZE_T srcaddr_sz; | |
968 | if (srcaddr) srcaddr_sz = *addrlen; | |
969 | SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen); | |
970 | if (res > 0) { | |
971 | __msan_unpoison(buf, res); | |
972 | if (srcaddr) { | |
973 | SIZE_T sz = *addrlen; | |
92a42be0 | 974 | __msan_unpoison(srcaddr, Min(sz, srcaddr_sz)); |
1a4d82fc JJ |
975 | } |
976 | } | |
977 | return res; | |
978 | } | |
979 | ||
980 | INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { | |
1a4d82fc | 981 | GET_MALLOC_STACK_TRACE; |
92a42be0 | 982 | if (UNLIKELY(!msan_inited)) { |
1a4d82fc JJ |
983 | // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. |
984 | const SIZE_T kCallocPoolSize = 1024; | |
985 | static uptr calloc_memory_for_dlsym[kCallocPoolSize]; | |
986 | static SIZE_T allocated; | |
987 | SIZE_T size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; | |
988 | void *mem = (void*)&calloc_memory_for_dlsym[allocated]; | |
989 | allocated += size_in_words; | |
990 | CHECK(allocated < kCallocPoolSize); | |
991 | return mem; | |
992 | } | |
92a42be0 | 993 | return MsanCalloc(&stack, nmemb, size); |
1a4d82fc JJ |
994 | } |
995 | ||
996 | INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { | |
997 | GET_MALLOC_STACK_TRACE; | |
998 | return MsanReallocate(&stack, ptr, size, sizeof(u64), false); | |
999 | } | |
1000 | ||
1001 | INTERCEPTOR(void *, malloc, SIZE_T size) { | |
1002 | GET_MALLOC_STACK_TRACE; | |
92a42be0 SL |
1003 | return MsanReallocate(&stack, nullptr, size, sizeof(u64), false); |
1004 | } | |
1005 | ||
1006 | void __msan_allocated_memory(const void *data, uptr size) { | |
1007 | GET_MALLOC_STACK_TRACE; | |
1008 | if (flags()->poison_in_malloc) { | |
1009 | stack.tag = STACK_TRACE_TAG_POISON; | |
1010 | PoisonMemory(data, size, &stack); | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | void __msan_copy_shadow(void *dest, const void *src, uptr n) { | |
1015 | GET_STORE_STACK_TRACE; | |
1016 | MoveShadowAndOrigin(dest, src, n, &stack); | |
1a4d82fc JJ |
1017 | } |
1018 | ||
92a42be0 | 1019 | void __sanitizer_dtor_callback(const void *data, uptr size) { |
1a4d82fc | 1020 | GET_MALLOC_STACK_TRACE; |
92a42be0 SL |
1021 | if (flags()->poison_in_dtor) { |
1022 | stack.tag = STACK_TRACE_TAG_POISON; | |
1023 | PoisonMemory(data, size, &stack); | |
1a4d82fc JJ |
1024 | } |
1025 | } | |
1026 | ||
1027 | INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, | |
1028 | int fd, OFF_T offset) { | |
92a42be0 SL |
1029 | if (msan_init_is_running) |
1030 | return REAL(mmap)(addr, length, prot, flags, fd, offset); | |
1a4d82fc JJ |
1031 | ENSURE_MSAN_INITED(); |
1032 | if (addr && !MEM_IS_APP(addr)) { | |
1033 | if (flags & map_fixed) { | |
1034 | *__errno_location() = errno_EINVAL; | |
1035 | return (void *)-1; | |
1036 | } else { | |
92a42be0 | 1037 | addr = nullptr; |
1a4d82fc JJ |
1038 | } |
1039 | } | |
1040 | void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); | |
1041 | if (res != (void*)-1) | |
1042 | __msan_unpoison(res, RoundUpTo(length, GetPageSize())); | |
1043 | return res; | |
1044 | } | |
1045 | ||
92a42be0 | 1046 | #if !SANITIZER_FREEBSD |
1a4d82fc JJ |
1047 | INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, |
1048 | int fd, OFF64_T offset) { | |
1049 | ENSURE_MSAN_INITED(); | |
1050 | if (addr && !MEM_IS_APP(addr)) { | |
1051 | if (flags & map_fixed) { | |
1052 | *__errno_location() = errno_EINVAL; | |
1053 | return (void *)-1; | |
1054 | } else { | |
92a42be0 | 1055 | addr = nullptr; |
1a4d82fc JJ |
1056 | } |
1057 | } | |
1058 | void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); | |
1059 | if (res != (void*)-1) | |
1060 | __msan_unpoison(res, RoundUpTo(length, GetPageSize())); | |
1061 | return res; | |
1062 | } | |
92a42be0 SL |
1063 | #define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) |
1064 | #else | |
1065 | #define MSAN_MAYBE_INTERCEPT_MMAP64 | |
1066 | #endif | |
1a4d82fc JJ |
1067 | |
1068 | struct dlinfo { | |
1069 | char *dli_fname; | |
1070 | void *dli_fbase; | |
1071 | char *dli_sname; | |
1072 | void *dli_saddr; | |
1073 | }; | |
1074 | ||
1075 | INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) { | |
1076 | ENSURE_MSAN_INITED(); | |
1077 | int res = REAL(dladdr)(addr, info); | |
1078 | if (res != 0) { | |
1079 | __msan_unpoison(info, sizeof(*info)); | |
1080 | if (info->dli_fname) | |
1081 | __msan_unpoison(info->dli_fname, REAL(strlen)(info->dli_fname) + 1); | |
1082 | if (info->dli_sname) | |
1083 | __msan_unpoison(info->dli_sname, REAL(strlen)(info->dli_sname) + 1); | |
1084 | } | |
1085 | return res; | |
1086 | } | |
1087 | ||
1088 | INTERCEPTOR(char *, dlerror, int fake) { | |
1089 | ENSURE_MSAN_INITED(); | |
1090 | char *res = REAL(dlerror)(fake); | |
92a42be0 | 1091 | if (res) __msan_unpoison(res, REAL(strlen)(res) + 1); |
1a4d82fc JJ |
1092 | return res; |
1093 | } | |
1094 | ||
1a4d82fc JJ |
1095 | typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size, |
1096 | void *data); | |
1097 | struct dl_iterate_phdr_data { | |
1098 | dl_iterate_phdr_cb callback; | |
1099 | void *data; | |
1100 | }; | |
1101 | ||
1102 | static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, | |
1103 | void *data) { | |
1104 | if (info) { | |
1105 | __msan_unpoison(info, size); | |
92a42be0 SL |
1106 | if (info->dlpi_phdr && info->dlpi_phnum) |
1107 | __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum); | |
1a4d82fc JJ |
1108 | if (info->dlpi_name) |
1109 | __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1); | |
1110 | } | |
1111 | dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data; | |
1112 | UnpoisonParam(3); | |
92a42be0 | 1113 | return cbdata->callback(info, size, cbdata->data); |
1a4d82fc JJ |
1114 | } |
1115 | ||
1116 | INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) { | |
1117 | ENSURE_MSAN_INITED(); | |
1a4d82fc JJ |
1118 | dl_iterate_phdr_data cbdata; |
1119 | cbdata.callback = callback; | |
1120 | cbdata.data = data; | |
1121 | int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata); | |
1a4d82fc JJ |
1122 | return res; |
1123 | } | |
1124 | ||
1125 | INTERCEPTOR(int, getrusage, int who, void *usage) { | |
1126 | ENSURE_MSAN_INITED(); | |
1127 | int res = REAL(getrusage)(who, usage); | |
1128 | if (res == 0) { | |
1129 | __msan_unpoison(usage, __sanitizer::struct_rusage_sz); | |
1130 | } | |
1131 | return res; | |
1132 | } | |
1133 | ||
1134 | class SignalHandlerScope { | |
1135 | public: | |
92a42be0 SL |
1136 | SignalHandlerScope() { |
1137 | if (MsanThread *t = GetCurrentThread()) | |
1138 | t->EnterSignalHandler(); | |
1139 | } | |
1140 | ~SignalHandlerScope() { | |
1141 | if (MsanThread *t = GetCurrentThread()) | |
1142 | t->LeaveSignalHandler(); | |
1143 | } | |
1a4d82fc JJ |
1144 | }; |
1145 | ||
1146 | // sigactions_mu guarantees atomicity of sigaction() and signal() calls. | |
1147 | // Access to sigactions[] is gone with relaxed atomics to avoid data race with | |
1148 | // the signal handler. | |
1149 | const int kMaxSignals = 1024; | |
1150 | static atomic_uintptr_t sigactions[kMaxSignals]; | |
1151 | static StaticSpinMutex sigactions_mu; | |
1152 | ||
1153 | static void SignalHandler(int signo) { | |
1154 | SignalHandlerScope signal_handler_scope; | |
1155 | ScopedThreadLocalStateBackup stlsb; | |
1156 | UnpoisonParam(1); | |
1157 | ||
1158 | typedef void (*signal_cb)(int x); | |
1159 | signal_cb cb = | |
1160 | (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed); | |
92a42be0 | 1161 | cb(signo); |
1a4d82fc JJ |
1162 | } |
1163 | ||
1164 | static void SignalAction(int signo, void *si, void *uc) { | |
1165 | SignalHandlerScope signal_handler_scope; | |
1166 | ScopedThreadLocalStateBackup stlsb; | |
1167 | UnpoisonParam(3); | |
1168 | __msan_unpoison(si, sizeof(__sanitizer_sigaction)); | |
1169 | __msan_unpoison(uc, __sanitizer::ucontext_t_sz); | |
1170 | ||
1171 | typedef void (*sigaction_cb)(int, void *, void *); | |
1172 | sigaction_cb cb = | |
1173 | (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed); | |
92a42be0 | 1174 | cb(signo, si, uc); |
1a4d82fc JJ |
1175 | } |
1176 | ||
1177 | INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act, | |
1178 | __sanitizer_sigaction *oldact) { | |
1179 | ENSURE_MSAN_INITED(); | |
1180 | // FIXME: check that *act is unpoisoned. | |
1181 | // That requires intercepting all of sigemptyset, sigfillset, etc. | |
1182 | int res; | |
1183 | if (flags()->wrap_signals) { | |
1184 | SpinMutexLock lock(&sigactions_mu); | |
1185 | CHECK_LT(signo, kMaxSignals); | |
1186 | uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed); | |
1187 | __sanitizer_sigaction new_act; | |
92a42be0 | 1188 | __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr; |
1a4d82fc | 1189 | if (act) { |
92a42be0 | 1190 | REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction)); |
1a4d82fc JJ |
1191 | uptr cb = (uptr)pnew_act->sigaction; |
1192 | uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo) | |
1193 | ? (uptr)SignalAction | |
1194 | : (uptr)SignalHandler; | |
1195 | if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { | |
1196 | atomic_store(&sigactions[signo], cb, memory_order_relaxed); | |
1197 | pnew_act->sigaction = (void (*)(int, void *, void *))new_cb; | |
1198 | } | |
1199 | } | |
1200 | res = REAL(sigaction)(signo, pnew_act, oldact); | |
1201 | if (res == 0 && oldact) { | |
1202 | uptr cb = (uptr)oldact->sigaction; | |
1203 | if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { | |
1204 | oldact->sigaction = (void (*)(int, void *, void *))old_cb; | |
1205 | } | |
1206 | } | |
1207 | } else { | |
1208 | res = REAL(sigaction)(signo, act, oldact); | |
1209 | } | |
1210 | ||
1211 | if (res == 0 && oldact) { | |
1212 | __msan_unpoison(oldact, sizeof(__sanitizer_sigaction)); | |
1213 | } | |
1214 | return res; | |
1215 | } | |
1216 | ||
1217 | INTERCEPTOR(int, signal, int signo, uptr cb) { | |
1218 | ENSURE_MSAN_INITED(); | |
1219 | if (flags()->wrap_signals) { | |
1220 | CHECK_LT(signo, kMaxSignals); | |
1221 | SpinMutexLock lock(&sigactions_mu); | |
1222 | if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { | |
1223 | atomic_store(&sigactions[signo], cb, memory_order_relaxed); | |
1224 | cb = (uptr) SignalHandler; | |
1225 | } | |
1226 | return REAL(signal)(signo, cb); | |
1227 | } else { | |
1228 | return REAL(signal)(signo, cb); | |
1229 | } | |
1230 | } | |
1231 | ||
1232 | extern "C" int pthread_attr_init(void *attr); | |
1233 | extern "C" int pthread_attr_destroy(void *attr); | |
1234 | ||
1235 | static void *MsanThreadStartFunc(void *arg) { | |
1236 | MsanThread *t = (MsanThread *)arg; | |
1237 | SetCurrentThread(t); | |
1238 | return t->ThreadStart(); | |
1239 | } | |
1240 | ||
1241 | INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), | |
1242 | void * param) { | |
1243 | ENSURE_MSAN_INITED(); // for GetTlsSize() | |
1244 | __sanitizer_pthread_attr_t myattr; | |
92a42be0 | 1245 | if (!attr) { |
1a4d82fc JJ |
1246 | pthread_attr_init(&myattr); |
1247 | attr = &myattr; | |
1248 | } | |
1249 | ||
1250 | AdjustStackSize(attr); | |
1251 | ||
1252 | MsanThread *t = MsanThread::Create(callback, param); | |
1253 | ||
1254 | int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t); | |
1255 | ||
1256 | if (attr == &myattr) | |
1257 | pthread_attr_destroy(&myattr); | |
1258 | if (!res) { | |
1259 | __msan_unpoison(th, __sanitizer::pthread_t_sz); | |
1260 | } | |
1261 | return res; | |
1262 | } | |
1263 | ||
1264 | INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key, | |
1265 | void (*dtor)(void *value)) { | |
1266 | if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor); | |
1267 | ENSURE_MSAN_INITED(); | |
1268 | int res = REAL(pthread_key_create)(key, dtor); | |
1269 | if (!res && key) | |
1270 | __msan_unpoison(key, sizeof(*key)); | |
1271 | return res; | |
1272 | } | |
1273 | ||
1274 | INTERCEPTOR(int, pthread_join, void *th, void **retval) { | |
1275 | ENSURE_MSAN_INITED(); | |
1276 | int res = REAL(pthread_join)(th, retval); | |
1277 | if (!res && retval) | |
1278 | __msan_unpoison(retval, sizeof(*retval)); | |
1279 | return res; | |
1280 | } | |
1281 | ||
1282 | extern char *tzname[2]; | |
1283 | ||
1284 | INTERCEPTOR(void, tzset, int fake) { | |
1285 | ENSURE_MSAN_INITED(); | |
1286 | REAL(tzset)(fake); | |
1287 | if (tzname[0]) | |
1288 | __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1); | |
1289 | if (tzname[1]) | |
1290 | __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1); | |
1291 | return; | |
1292 | } | |
1293 | ||
1294 | struct MSanAtExitRecord { | |
1295 | void (*func)(void *arg); | |
1296 | void *arg; | |
1297 | }; | |
1298 | ||
1299 | void MSanAtExitWrapper(void *arg) { | |
1300 | UnpoisonParam(1); | |
1301 | MSanAtExitRecord *r = (MSanAtExitRecord *)arg; | |
92a42be0 | 1302 | r->func(r->arg); |
1a4d82fc JJ |
1303 | InternalFree(r); |
1304 | } | |
1305 | ||
1306 | // Unpoison argument shadow for C++ module destructors. | |
1307 | INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, | |
1308 | void *dso_handle) { | |
1309 | if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle); | |
1310 | ENSURE_MSAN_INITED(); | |
1311 | MSanAtExitRecord *r = | |
1312 | (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord)); | |
1313 | r->func = func; | |
1314 | r->arg = arg; | |
1315 | return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle); | |
1316 | } | |
1317 | ||
1318 | DECLARE_REAL(int, shmctl, int shmid, int cmd, void *buf) | |
1319 | ||
1320 | INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) { | |
1321 | ENSURE_MSAN_INITED(); | |
1322 | void *p = REAL(shmat)(shmid, shmaddr, shmflg); | |
1323 | if (p != (void *)-1) { | |
1324 | __sanitizer_shmid_ds ds; | |
1325 | int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds); | |
1326 | if (!res) { | |
1327 | __msan_unpoison(p, ds.shm_segsz); | |
1328 | } | |
1329 | } | |
1330 | return p; | |
1331 | } | |
1332 | ||
92a42be0 SL |
1333 | static void BeforeFork() { |
1334 | StackDepotLockAll(); | |
1335 | ChainedOriginDepotLockAll(); | |
1a4d82fc JJ |
1336 | } |
1337 | ||
92a42be0 SL |
1338 | static void AfterFork() { |
1339 | ChainedOriginDepotUnlockAll(); | |
1340 | StackDepotUnlockAll(); | |
1a4d82fc JJ |
1341 | } |
1342 | ||
92a42be0 SL |
1343 | INTERCEPTOR(int, fork, void) { |
1344 | ENSURE_MSAN_INITED(); | |
1345 | BeforeFork(); | |
1346 | int pid = REAL(fork)(); | |
1347 | AfterFork(); | |
1348 | return pid; | |
1a4d82fc JJ |
1349 | } |
1350 | ||
92a42be0 SL |
1351 | INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name, |
1352 | const void *termp, const void *winp) { | |
1353 | ENSURE_MSAN_INITED(); | |
1354 | InterceptorScope interceptor_scope; | |
1355 | int res = REAL(openpty)(amaster, aslave, name, termp, winp); | |
1356 | if (!res) { | |
1357 | __msan_unpoison(amaster, sizeof(*amaster)); | |
1358 | __msan_unpoison(aslave, sizeof(*aslave)); | |
1359 | } | |
1360 | return res; | |
1a4d82fc JJ |
1361 | } |
1362 | ||
92a42be0 SL |
1363 | INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp, |
1364 | const void *winp) { | |
1365 | ENSURE_MSAN_INITED(); | |
1366 | InterceptorScope interceptor_scope; | |
1367 | int res = REAL(forkpty)(amaster, name, termp, winp); | |
1368 | if (res != -1) | |
1369 | __msan_unpoison(amaster, sizeof(*amaster)); | |
1370 | return res; | |
1a4d82fc JJ |
1371 | } |
1372 | ||
1373 | struct MSanInterceptorContext { | |
1374 | bool in_interceptor_scope; | |
1375 | }; | |
1376 | ||
1377 | namespace __msan { | |
1378 | ||
1379 | int OnExit() { | |
1380 | // FIXME: ask frontend whether we need to return failure. | |
1381 | return 0; | |
1382 | } | |
1383 | ||
92a42be0 | 1384 | } // namespace __msan |
1a4d82fc JJ |
1385 | |
1386 | // A version of CHECK_UNPOISONED using a saved scope value. Used in common | |
1387 | // interceptors. | |
1388 | #define CHECK_UNPOISONED_CTX(ctx, x, n) \ | |
1389 | do { \ | |
1390 | if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \ | |
1391 | CHECK_UNPOISONED_0(x, n); \ | |
1392 | } while (0) | |
1393 | ||
1394 | #define MSAN_INTERCEPT_FUNC(name) \ | |
1395 | do { \ | |
1396 | if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ | |
1397 | VReport(1, "MemorySanitizer: failed to intercept '" #name "'\n"); \ | |
1398 | } while (0) | |
1399 | ||
1400 | #define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name) | |
1401 | #define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \ | |
1402 | UnpoisonParam(count) | |
1403 | #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ | |
1404 | __msan_unpoison(ptr, size) | |
1405 | #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ | |
1406 | CHECK_UNPOISONED_CTX(ctx, ptr, size) | |
1407 | #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \ | |
1408 | __msan_unpoison(ptr, size) | |
1409 | #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ | |
1410 | if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \ | |
1411 | MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \ | |
1412 | ctx = (void *)&msan_ctx; \ | |
1413 | (void)ctx; \ | |
1414 | InterceptorScope interceptor_scope; \ | |
1415 | __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */ \ | |
1416 | ENSURE_MSAN_INITED(); | |
92a42be0 SL |
1417 | #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ |
1418 | do { \ | |
1419 | } while (false) | |
1a4d82fc JJ |
1420 | #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ |
1421 | do { \ | |
1422 | } while (false) | |
1423 | #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ | |
1424 | do { \ | |
1425 | } while (false) | |
1426 | #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ | |
1427 | do { \ | |
1428 | } while (false) | |
1429 | #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ | |
1430 | do { \ | |
1431 | } while (false) // FIXME | |
1432 | #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ | |
1433 | do { \ | |
1434 | } while (false) // FIXME | |
1435 | #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) | |
1436 | #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() | |
92a42be0 SL |
1437 | #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ |
1438 | do { \ | |
1439 | link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \ | |
1440 | if (map) ForEachMappedRegion(map, __msan_unpoison); \ | |
1441 | } while (false) | |
1442 | ||
1443 | #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ | |
1444 | if (MsanThread *t = GetCurrentThread()) { \ | |
1445 | *begin = t->tls_begin(); \ | |
1446 | *end = t->tls_end(); \ | |
1447 | } else { \ | |
1448 | *begin = *end = 0; \ | |
1449 | } | |
1450 | ||
1a4d82fc JJ |
1451 | #include "sanitizer_common/sanitizer_common_interceptors.inc" |
1452 | ||
1453 | #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s) | |
1454 | #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ | |
1455 | do { \ | |
1456 | } while (false) | |
1457 | #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ | |
1458 | do { \ | |
1459 | } while (false) | |
1460 | #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s) | |
1461 | #include "sanitizer_common/sanitizer_common_syscalls.inc" | |
1462 | ||
1a4d82fc | 1463 | // These interface functions reside here so that they can use |
92a42be0 | 1464 | // REAL(memset), etc. |
1a4d82fc JJ |
1465 | void __msan_unpoison(const void *a, uptr size) { |
1466 | if (!MEM_IS_APP(a)) return; | |
92a42be0 | 1467 | SetShadow(a, size, 0); |
1a4d82fc JJ |
1468 | } |
1469 | ||
1470 | void __msan_poison(const void *a, uptr size) { | |
1471 | if (!MEM_IS_APP(a)) return; | |
92a42be0 | 1472 | SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1); |
1a4d82fc JJ |
1473 | } |
1474 | ||
1475 | void __msan_poison_stack(void *a, uptr size) { | |
1476 | if (!MEM_IS_APP(a)) return; | |
92a42be0 | 1477 | SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1); |
1a4d82fc JJ |
1478 | } |
1479 | ||
1480 | void __msan_clear_and_unpoison(void *a, uptr size) { | |
92a42be0 SL |
1481 | REAL(memset)(a, 0, size); |
1482 | SetShadow(a, size, 0); | |
1a4d82fc JJ |
1483 | } |
1484 | ||
1485 | void *__msan_memcpy(void *dest, const void *src, SIZE_T n) { | |
1486 | if (!msan_inited) return internal_memcpy(dest, src, n); | |
92a42be0 SL |
1487 | if (msan_init_is_running || __msan::IsInSymbolizer()) |
1488 | return REAL(memcpy)(dest, src, n); | |
1a4d82fc JJ |
1489 | ENSURE_MSAN_INITED(); |
1490 | GET_STORE_STACK_TRACE; | |
92a42be0 SL |
1491 | void *res = REAL(memcpy)(dest, src, n); |
1492 | CopyShadowAndOrigin(dest, src, n, &stack); | |
1a4d82fc JJ |
1493 | return res; |
1494 | } | |
1495 | ||
1496 | void *__msan_memset(void *s, int c, SIZE_T n) { | |
1497 | if (!msan_inited) return internal_memset(s, c, n); | |
1498 | if (msan_init_is_running) return REAL(memset)(s, c, n); | |
1499 | ENSURE_MSAN_INITED(); | |
92a42be0 | 1500 | void *res = REAL(memset)(s, c, n); |
1a4d82fc JJ |
1501 | __msan_unpoison(s, n); |
1502 | return res; | |
1503 | } | |
1504 | ||
1505 | void *__msan_memmove(void *dest, const void *src, SIZE_T n) { | |
1506 | if (!msan_inited) return internal_memmove(dest, src, n); | |
1507 | if (msan_init_is_running) return REAL(memmove)(dest, src, n); | |
1508 | ENSURE_MSAN_INITED(); | |
1509 | GET_STORE_STACK_TRACE; | |
1510 | void *res = REAL(memmove)(dest, src, n); | |
92a42be0 | 1511 | MoveShadowAndOrigin(dest, src, n, &stack); |
1a4d82fc JJ |
1512 | return res; |
1513 | } | |
1514 | ||
1515 | void __msan_unpoison_string(const char* s) { | |
1516 | if (!MEM_IS_APP(s)) return; | |
1517 | __msan_unpoison(s, REAL(strlen)(s) + 1); | |
1518 | } | |
1519 | ||
1520 | namespace __msan { | |
1521 | ||
1a4d82fc JJ |
1522 | void InitializeInterceptors() { |
1523 | static int inited = 0; | |
1524 | CHECK_EQ(inited, 0); | |
92a42be0 | 1525 | InitializeCommonInterceptors(); |
1a4d82fc JJ |
1526 | |
1527 | INTERCEPT_FUNCTION(mmap); | |
92a42be0 | 1528 | MSAN_MAYBE_INTERCEPT_MMAP64; |
1a4d82fc | 1529 | INTERCEPT_FUNCTION(posix_memalign); |
92a42be0 SL |
1530 | MSAN_MAYBE_INTERCEPT_MEMALIGN; |
1531 | INTERCEPT_FUNCTION(__libc_memalign); | |
1a4d82fc | 1532 | INTERCEPT_FUNCTION(valloc); |
92a42be0 | 1533 | MSAN_MAYBE_INTERCEPT_PVALLOC; |
1a4d82fc JJ |
1534 | INTERCEPT_FUNCTION(malloc); |
1535 | INTERCEPT_FUNCTION(calloc); | |
1536 | INTERCEPT_FUNCTION(realloc); | |
1537 | INTERCEPT_FUNCTION(free); | |
92a42be0 | 1538 | MSAN_MAYBE_INTERCEPT_CFREE; |
1a4d82fc | 1539 | INTERCEPT_FUNCTION(malloc_usable_size); |
92a42be0 SL |
1540 | MSAN_MAYBE_INTERCEPT_MALLINFO; |
1541 | MSAN_MAYBE_INTERCEPT_MALLOPT; | |
1542 | MSAN_MAYBE_INTERCEPT_MALLOC_STATS; | |
1a4d82fc | 1543 | INTERCEPT_FUNCTION(fread); |
92a42be0 | 1544 | MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED; |
1a4d82fc JJ |
1545 | INTERCEPT_FUNCTION(readlink); |
1546 | INTERCEPT_FUNCTION(memcpy); | |
1547 | INTERCEPT_FUNCTION(memccpy); | |
1548 | INTERCEPT_FUNCTION(mempcpy); | |
1549 | INTERCEPT_FUNCTION(memset); | |
1550 | INTERCEPT_FUNCTION(memmove); | |
1551 | INTERCEPT_FUNCTION(bcopy); | |
1552 | INTERCEPT_FUNCTION(wmemset); | |
1553 | INTERCEPT_FUNCTION(wmemcpy); | |
1554 | INTERCEPT_FUNCTION(wmempcpy); | |
1555 | INTERCEPT_FUNCTION(wmemmove); | |
1556 | INTERCEPT_FUNCTION(strcpy); // NOLINT | |
1557 | INTERCEPT_FUNCTION(stpcpy); // NOLINT | |
1558 | INTERCEPT_FUNCTION(strdup); | |
92a42be0 | 1559 | MSAN_MAYBE_INTERCEPT___STRDUP; |
1a4d82fc | 1560 | INTERCEPT_FUNCTION(strndup); |
92a42be0 | 1561 | MSAN_MAYBE_INTERCEPT___STRNDUP; |
1a4d82fc JJ |
1562 | INTERCEPT_FUNCTION(strncpy); // NOLINT |
1563 | INTERCEPT_FUNCTION(strlen); | |
1564 | INTERCEPT_FUNCTION(strnlen); | |
1565 | INTERCEPT_FUNCTION(gcvt); | |
1566 | INTERCEPT_FUNCTION(strcat); // NOLINT | |
1567 | INTERCEPT_FUNCTION(strncat); // NOLINT | |
92a42be0 SL |
1568 | INTERCEPT_STRTO(strtod); |
1569 | INTERCEPT_STRTO(strtof); | |
1570 | INTERCEPT_STRTO(strtold); | |
1571 | INTERCEPT_STRTO(strtol); | |
1572 | INTERCEPT_STRTO(strtoul); | |
1573 | INTERCEPT_STRTO(strtoll); | |
1574 | INTERCEPT_STRTO(strtoull); | |
1575 | INTERCEPT_STRTO(wcstod); | |
1576 | INTERCEPT_STRTO(wcstof); | |
1577 | INTERCEPT_STRTO(wcstold); | |
1578 | INTERCEPT_STRTO(wcstol); | |
1579 | INTERCEPT_STRTO(wcstoul); | |
1580 | INTERCEPT_STRTO(wcstoll); | |
1581 | INTERCEPT_STRTO(wcstoull); | |
1a4d82fc | 1582 | INTERCEPT_FUNCTION(vswprintf); |
1a4d82fc | 1583 | INTERCEPT_FUNCTION(swprintf); |
92a42be0 SL |
1584 | INTERCEPT_FUNCTION(strxfrm); |
1585 | INTERCEPT_FUNCTION(strxfrm_l); | |
1a4d82fc JJ |
1586 | INTERCEPT_FUNCTION(strftime); |
1587 | INTERCEPT_FUNCTION(strftime_l); | |
92a42be0 | 1588 | MSAN_MAYBE_INTERCEPT___STRFTIME_L; |
1a4d82fc JJ |
1589 | INTERCEPT_FUNCTION(wcsftime); |
1590 | INTERCEPT_FUNCTION(wcsftime_l); | |
92a42be0 | 1591 | MSAN_MAYBE_INTERCEPT___WCSFTIME_L; |
1a4d82fc JJ |
1592 | INTERCEPT_FUNCTION(mbtowc); |
1593 | INTERCEPT_FUNCTION(mbrtowc); | |
1594 | INTERCEPT_FUNCTION(wcslen); | |
1595 | INTERCEPT_FUNCTION(wcschr); | |
1596 | INTERCEPT_FUNCTION(wcscpy); | |
1597 | INTERCEPT_FUNCTION(wcscmp); | |
1a4d82fc JJ |
1598 | INTERCEPT_FUNCTION(getenv); |
1599 | INTERCEPT_FUNCTION(setenv); | |
1600 | INTERCEPT_FUNCTION(putenv); | |
1601 | INTERCEPT_FUNCTION(gettimeofday); | |
1602 | INTERCEPT_FUNCTION(fcvt); | |
92a42be0 SL |
1603 | MSAN_MAYBE_INTERCEPT___FXSTAT; |
1604 | MSAN_INTERCEPT_FSTATAT; | |
1605 | MSAN_INTERCEPT_STAT; | |
1606 | MSAN_MAYBE_INTERCEPT___LXSTAT; | |
1607 | MSAN_MAYBE_INTERCEPT___FXSTAT64; | |
1608 | MSAN_MAYBE_INTERCEPT___FXSTATAT64; | |
1609 | MSAN_MAYBE_INTERCEPT___XSTAT64; | |
1610 | MSAN_MAYBE_INTERCEPT___LXSTAT64; | |
1a4d82fc JJ |
1611 | INTERCEPT_FUNCTION(pipe); |
1612 | INTERCEPT_FUNCTION(pipe2); | |
1613 | INTERCEPT_FUNCTION(socketpair); | |
1614 | INTERCEPT_FUNCTION(fgets); | |
92a42be0 | 1615 | MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED; |
1a4d82fc | 1616 | INTERCEPT_FUNCTION(getrlimit); |
92a42be0 SL |
1617 | MSAN_MAYBE_INTERCEPT_GETRLIMIT64; |
1618 | MSAN_INTERCEPT_UNAME; | |
1a4d82fc | 1619 | INTERCEPT_FUNCTION(gethostname); |
92a42be0 SL |
1620 | MSAN_MAYBE_INTERCEPT_EPOLL_WAIT; |
1621 | MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT; | |
1a4d82fc JJ |
1622 | INTERCEPT_FUNCTION(recv); |
1623 | INTERCEPT_FUNCTION(recvfrom); | |
1624 | INTERCEPT_FUNCTION(dladdr); | |
1625 | INTERCEPT_FUNCTION(dlerror); | |
1a4d82fc JJ |
1626 | INTERCEPT_FUNCTION(dl_iterate_phdr); |
1627 | INTERCEPT_FUNCTION(getrusage); | |
1628 | INTERCEPT_FUNCTION(sigaction); | |
1629 | INTERCEPT_FUNCTION(signal); | |
1630 | INTERCEPT_FUNCTION(pthread_create); | |
1631 | INTERCEPT_FUNCTION(pthread_key_create); | |
1632 | INTERCEPT_FUNCTION(pthread_join); | |
1633 | INTERCEPT_FUNCTION(tzset); | |
1634 | INTERCEPT_FUNCTION(__cxa_atexit); | |
1635 | INTERCEPT_FUNCTION(shmat); | |
92a42be0 SL |
1636 | INTERCEPT_FUNCTION(fork); |
1637 | INTERCEPT_FUNCTION(openpty); | |
1638 | INTERCEPT_FUNCTION(forkpty); | |
1a4d82fc JJ |
1639 | |
1640 | inited = 1; | |
1641 | } | |
92a42be0 | 1642 | } // namespace __msan |