1//===-- msan_interceptors.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 MemorySanitizer.
10//
11// Interceptors for standard library functions.
12//
13// FIXME: move as many interceptors as possible into
14// sanitizer_common/sanitizer_common_interceptors.h
15//===----------------------------------------------------------------------===//
16
17#define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
18
19#include "interception/interception.h"
20#include "msan.h"
21#include "msan_chained_origin_depot.h"
22#include "msan_dl.h"
23#include "msan_origin.h"
24#include "msan_poisoning.h"
25#include "msan_report.h"
26#include "msan_thread.h"
27#include "sanitizer_common/sanitizer_allocator.h"
28#include "sanitizer_common/sanitizer_allocator_dlsym.h"
29#include "sanitizer_common/sanitizer_allocator_interface.h"
30#include "sanitizer_common/sanitizer_atomic.h"
31#include "sanitizer_common/sanitizer_common.h"
32#include "sanitizer_common/sanitizer_errno.h"
33#include "sanitizer_common/sanitizer_errno_codes.h"
34#include "sanitizer_common/sanitizer_glibc_version.h"
35#include "sanitizer_common/sanitizer_libc.h"
36#include "sanitizer_common/sanitizer_linux.h"
37#include "sanitizer_common/sanitizer_platform_interceptors.h"
38#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
39#include "sanitizer_common/sanitizer_platform_limits_posix.h"
40#include "sanitizer_common/sanitizer_stackdepot.h"
41#include "sanitizer_common/sanitizer_vector.h"
42
43#if SANITIZER_NETBSD
44#define fstat __fstat50
45#define gettimeofday __gettimeofday50
46#define getrusage __getrusage50
47#define tzset __tzset50
48#endif
49
50#include <stdarg.h>
51// ACHTUNG! No other system header includes in this file.
52// Ideally, we should get rid of stdarg.h as well.
53
54using namespace __msan;
55
56using __sanitizer::memory_order;
57using __sanitizer::atomic_load;
58using __sanitizer::atomic_store;
59using __sanitizer::atomic_uintptr_t;
60
61DECLARE_REAL(SIZE_T, strlen, const char *s)
62DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
63DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n)
64DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n)
65
66// True if this is a nested interceptor.
67static THREADLOCAL int in_interceptor_scope;
68
69void __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; }
70void __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; }
71
72struct InterceptorScope {
73 InterceptorScope() { ++in_interceptor_scope; }
74 ~InterceptorScope() { --in_interceptor_scope; }
75};
76
77bool IsInInterceptorScope() {
78 return in_interceptor_scope;
79}
80
81struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
82 static bool UseImpl() { return !msan_inited; }
83};
84
85#define ENSURE_MSAN_INITED() do { \
86 CHECK(!msan_init_is_running); \
87 if (!msan_inited) { \
88 __msan_init(); \
89 } \
90} while (0)
91
92// Check that [x, x+n) range is unpoisoned.
93#define CHECK_UNPOISONED_0(x, n) \
94 do { \
95 sptr __offset = __msan_test_shadow(x, n); \
96 if (__msan::IsInSymbolizerOrUnwider()) \
97 break; \
98 if (__offset >= 0 && __msan::flags()->report_umrs) { \
99 GET_CALLER_PC_BP; \
100 ReportUMRInsideAddressRange(__func__, x, n, __offset); \
101 __msan::PrintWarningWithOrigin( \
102 pc, bp, __msan_get_origin((const char *)x + __offset)); \
103 if (__msan::flags()->halt_on_error) { \
104 Printf("Exiting\n"); \
105 Die(); \
106 } \
107 } \
108 } while (0)
109
110// Check that [x, x+n) range is unpoisoned unless we are in a nested
111// interceptor.
112#define CHECK_UNPOISONED(x, n) \
113 do { \
114 if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
115 } while (0)
116
117#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \
118 CHECK_UNPOISONED((x), \
119 common_flags()->strict_string_checks ? (len) + 1 : (n) )
120
121#define CHECK_UNPOISONED_STRING(x, n) \
122 CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
123
124#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
125INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
126 void *file) {
127 ENSURE_MSAN_INITED();
128 SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file);
129 if (res > 0)
130 __msan_unpoison(a: ptr, size: res *size);
131 return res;
132}
133#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
134#else
135#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
136#endif
137
138#if !SANITIZER_NETBSD
139INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
140 return (char *)__msan_memcpy(dst: dest, src, size: n) + n;
141}
142#define MSAN_MAYBE_INTERCEPT_MEMPCPY INTERCEPT_FUNCTION(mempcpy)
143#else
144#define MSAN_MAYBE_INTERCEPT_MEMPCPY
145#endif
146
147INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
148 ENSURE_MSAN_INITED();
149 void *res = REAL(memccpy)(dest, src, c, n);
150 CHECK(!res || (res >= dest && res <= (char *)dest + n));
151 SIZE_T sz = res ? (char *)res - (char *)dest : n;
152 CHECK_UNPOISONED(src, sz);
153 __msan_unpoison(a: dest, size: sz);
154 return res;
155}
156
157INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
158 return __msan_memmove(dest, src, n);
159}
160
161INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
162 GET_MALLOC_STACK_TRACE;
163 CHECK_NE(memptr, 0);
164 int res = msan_posix_memalign(memptr, alignment, size, stack: &stack);
165 if (!res)
166 __msan_unpoison(a: memptr, size: sizeof(*memptr));
167 return res;
168}
169
170#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
171INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
172 GET_MALLOC_STACK_TRACE;
173 return msan_memalign(alignment, size, stack: &stack);
174}
175#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
176#else
177#define MSAN_MAYBE_INTERCEPT_MEMALIGN
178#endif
179
180INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
181 GET_MALLOC_STACK_TRACE;
182 return msan_aligned_alloc(alignment, size, stack: &stack);
183}
184
185#if !SANITIZER_NETBSD
186INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
187 GET_MALLOC_STACK_TRACE;
188 return msan_memalign(alignment, size, stack: &stack);
189}
190#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
191#else
192#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
193#endif
194
195INTERCEPTOR(void *, valloc, SIZE_T size) {
196 GET_MALLOC_STACK_TRACE;
197 return msan_valloc(size, stack: &stack);
198}
199
200#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
201INTERCEPTOR(void *, pvalloc, SIZE_T size) {
202 GET_MALLOC_STACK_TRACE;
203 return msan_pvalloc(size, stack: &stack);
204}
205#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
206#else
207#define MSAN_MAYBE_INTERCEPT_PVALLOC
208#endif
209
210INTERCEPTOR(void, free, void *ptr) {
211 if (UNLIKELY(!ptr))
212 return;
213 if (DlsymAlloc::PointerIsMine(ptr))
214 return DlsymAlloc::Free(ptr);
215 GET_MALLOC_STACK_TRACE;
216 MsanDeallocate(stack: &stack, ptr);
217}
218
219#if SANITIZER_INTERCEPT_FREE_SIZED
220INTERCEPTOR(void, free_sized, void *ptr, uptr size) {
221 if (UNLIKELY(!ptr))
222 return;
223 if (DlsymAlloc::PointerIsMine(ptr))
224 return DlsymAlloc::Free(ptr);
225 GET_MALLOC_STACK_TRACE;
226 MsanDeallocate(stack: &stack, ptr);
227}
228# define MSAN_MAYBE_INTERCEPT_FREE_SIZED INTERCEPT_FUNCTION(free_sized)
229#else
230# define MSAN_MAYBE_INTERCEPT_FREE_SIZED
231#endif
232
233#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
234INTERCEPTOR(void, free_aligned_sized, void *ptr, uptr alignment, uptr size) {
235 if (UNLIKELY(!ptr))
236 return;
237 if (DlsymAlloc::PointerIsMine(ptr))
238 return DlsymAlloc::Free(ptr);
239 GET_MALLOC_STACK_TRACE;
240 MsanDeallocate(stack: &stack, ptr);
241}
242# define MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED \
243 INTERCEPT_FUNCTION(free_aligned_sized)
244#else
245# define MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED
246#endif
247
248#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
249INTERCEPTOR(void, cfree, void *ptr) {
250 if (UNLIKELY(!ptr))
251 return;
252 if (DlsymAlloc::PointerIsMine(ptr))
253 return DlsymAlloc::Free(ptr);
254 GET_MALLOC_STACK_TRACE;
255 MsanDeallocate(stack: &stack, ptr);
256}
257# define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
258#else
259#define MSAN_MAYBE_INTERCEPT_CFREE
260#endif
261
262#if !SANITIZER_NETBSD
263INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
264 return __sanitizer_get_allocated_size(p: ptr);
265}
266#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
267 INTERCEPT_FUNCTION(malloc_usable_size)
268#else
269#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
270#endif
271
272#if (!SANITIZER_FREEBSD && !SANITIZER_NETBSD) || __GLIBC_PREREQ(2, 33)
273template <class T>
274static NOINLINE void clear_mallinfo(T *sret) {
275 ENSURE_MSAN_INITED();
276 internal_memset(sret, 0, sizeof(*sret));
277 __msan_unpoison(sret, sizeof(*sret));
278}
279#endif
280
281#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
282// Interceptors use NRVO and assume that sret will be pre-allocated in
283// caller frame.
284INTERCEPTOR(__sanitizer_struct_mallinfo, mallinfo,) {
285 __sanitizer_struct_mallinfo sret;
286 clear_mallinfo(sret: &sret);
287 return sret;
288}
289# define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
290#else
291# define MSAN_MAYBE_INTERCEPT_MALLINFO
292#endif
293
294#if __GLIBC_PREREQ(2, 33)
295INTERCEPTOR(__sanitizer_struct_mallinfo2, mallinfo2) {
296 __sanitizer_struct_mallinfo2 sret;
297 clear_mallinfo(sret: &sret);
298 return sret;
299}
300# define MSAN_MAYBE_INTERCEPT_MALLINFO2 INTERCEPT_FUNCTION(mallinfo2)
301#else
302# define MSAN_MAYBE_INTERCEPT_MALLINFO2
303#endif
304
305#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
306INTERCEPTOR(int, mallopt, int cmd, int value) {
307 return 0;
308}
309#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
310#else
311#define MSAN_MAYBE_INTERCEPT_MALLOPT
312#endif
313
314#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
315INTERCEPTOR(void, malloc_stats, void) {
316 // FIXME: implement, but don't call REAL(malloc_stats)!
317}
318#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
319#else
320#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
321#endif
322
323INTERCEPTOR(char *, strcpy, char *dest, const char *src) {
324 ENSURE_MSAN_INITED();
325 GET_STORE_STACK_TRACE;
326 SIZE_T n = internal_strlen(s: src);
327 CHECK_UNPOISONED_STRING(src + n, 0);
328 char *res = REAL(strcpy)(dest, src);
329 CopyShadowAndOrigin(dst: dest, src, size: n + 1, stack: &stack);
330 return res;
331}
332
333INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) {
334 ENSURE_MSAN_INITED();
335 GET_STORE_STACK_TRACE;
336 SIZE_T copy_size = internal_strnlen(s: src, maxlen: n);
337 if (copy_size < n)
338 copy_size++; // trailing \0
339 char *res = REAL(strncpy)(dest, src, n);
340 CopyShadowAndOrigin(dst: dest, src, size: copy_size, stack: &stack);
341 __msan_unpoison(a: dest + copy_size, size: n - copy_size);
342 return res;
343}
344
345#if !SANITIZER_NETBSD
346INTERCEPTOR(char *, stpcpy, char *dest, const char *src) {
347 ENSURE_MSAN_INITED();
348 GET_STORE_STACK_TRACE;
349 SIZE_T n = internal_strlen(s: src);
350 CHECK_UNPOISONED_STRING(src + n, 0);
351 char *res = REAL(stpcpy)(dest, src);
352 CopyShadowAndOrigin(dst: dest, src, size: n + 1, stack: &stack);
353 return res;
354}
355
356INTERCEPTOR(char *, stpncpy, char *dest, const char *src, SIZE_T n) {
357 ENSURE_MSAN_INITED();
358 GET_STORE_STACK_TRACE;
359 SIZE_T copy_size = Min(a: n, b: internal_strnlen(s: src, maxlen: n) + 1);
360 char *res = REAL(stpncpy)(dest, src, n);
361 CopyShadowAndOrigin(dst: dest, src, size: copy_size, stack: &stack);
362 __msan_unpoison(a: dest + copy_size, size: n - copy_size);
363 return res;
364}
365# define MSAN_MAYBE_INTERCEPT_STPCPY INTERCEPT_FUNCTION(stpcpy)
366# define MSAN_MAYBE_INTERCEPT_STPNCPY INTERCEPT_FUNCTION(stpncpy)
367#else
368#define MSAN_MAYBE_INTERCEPT_STPCPY
369# define MSAN_MAYBE_INTERCEPT_STPNCPY
370#endif
371
372INTERCEPTOR(char *, strdup, char *src) {
373 ENSURE_MSAN_INITED();
374 GET_STORE_STACK_TRACE;
375 // On FreeBSD strdup() leverages strlen().
376 InterceptorScope interceptor_scope;
377 SIZE_T n = internal_strlen(s: src);
378 CHECK_UNPOISONED_STRING(src + n, 0);
379 char *res = REAL(strdup)(src);
380 CopyShadowAndOrigin(dst: res, src, size: n + 1, stack: &stack);
381 return res;
382}
383
384#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
385INTERCEPTOR(char *, __strdup, char *src) {
386 ENSURE_MSAN_INITED();
387 GET_STORE_STACK_TRACE;
388 SIZE_T n = internal_strlen(s: src);
389 CHECK_UNPOISONED_STRING(src + n, 0);
390 char *res = REAL(__strdup)(src);
391 CopyShadowAndOrigin(dst: res, src, size: n + 1, stack: &stack);
392 return res;
393}
394#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
395#else
396#define MSAN_MAYBE_INTERCEPT___STRDUP
397#endif
398
399#if !SANITIZER_NETBSD
400INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
401 ENSURE_MSAN_INITED();
402 char *res = REAL(gcvt)(number, ndigit, buf);
403 SIZE_T n = internal_strlen(s: buf);
404 __msan_unpoison(a: buf, size: n + 1);
405 return res;
406}
407#define MSAN_MAYBE_INTERCEPT_GCVT INTERCEPT_FUNCTION(gcvt)
408#else
409#define MSAN_MAYBE_INTERCEPT_GCVT
410#endif
411
412INTERCEPTOR(char *, strcat, char *dest, const char *src) {
413 ENSURE_MSAN_INITED();
414 GET_STORE_STACK_TRACE;
415 SIZE_T src_size = internal_strlen(s: src);
416 SIZE_T dest_size = internal_strlen(s: dest);
417 CHECK_UNPOISONED_STRING(src + src_size, 0);
418 CHECK_UNPOISONED_STRING(dest + dest_size, 0);
419 char *res = REAL(strcat)(dest, src);
420 CopyShadowAndOrigin(dst: dest + dest_size, src, size: src_size + 1, stack: &stack);
421 return res;
422}
423
424INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) {
425 ENSURE_MSAN_INITED();
426 GET_STORE_STACK_TRACE;
427 SIZE_T dest_size = internal_strlen(s: dest);
428 SIZE_T copy_size = internal_strnlen(s: src, maxlen: n);
429 CHECK_UNPOISONED_STRING(dest + dest_size, 0);
430 char *res = REAL(strncat)(dest, src, n);
431 CopyShadowAndOrigin(dst: dest + dest_size, src, size: copy_size, stack: &stack);
432 __msan_unpoison(a: dest + dest_size + copy_size, size: 1); // \0
433 return res;
434}
435
436// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
437// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
438#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
439 ENSURE_MSAN_INITED(); \
440 ret_type res = REAL(func)(__VA_ARGS__); \
441 __msan_unpoison(endptr, sizeof(*endptr)); \
442 return res;
443
444// On s390x, long double return values are passed via implicit reference,
445// which needs to be unpoisoned. We make the implicit pointer explicit.
446#define INTERCEPTOR_STRTO_SRET_BODY(func, sret, ...) \
447 ENSURE_MSAN_INITED(); \
448 REAL(func)(sret, __VA_ARGS__); \
449 __msan_unpoison(sret, sizeof(*sret)); \
450 __msan_unpoison(endptr, sizeof(*endptr));
451
452#define INTERCEPTOR_STRTO(ret_type, func, char_type) \
453 INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
454 INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \
455 }
456
457#define INTERCEPTOR_STRTO_SRET(ret_type, func, char_type) \
458 INTERCEPTOR(void, func, ret_type *sret, const char_type *nptr, \
459 char_type **endptr) { \
460 INTERCEPTOR_STRTO_SRET_BODY(func, sret, nptr, endptr); \
461 }
462
463#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
464 INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
465 int base) { \
466 INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \
467 }
468
469#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \
470 INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
471 void *loc) { \
472 INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \
473 }
474
475#define INTERCEPTOR_STRTO_SRET_LOC(ret_type, func, char_type) \
476 INTERCEPTOR(void, func, ret_type *sret, const char_type *nptr, \
477 char_type **endptr, void *loc) { \
478 INTERCEPTOR_STRTO_SRET_BODY(func, sret, nptr, endptr, loc); \
479 }
480
481#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \
482 INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
483 int base, void *loc) { \
484 INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \
485 }
486
487#if SANITIZER_NETBSD
488#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
489 INTERCEPTOR_STRTO(ret_type, func, char_type) \
490 INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type)
491
492#define INTERCEPTORS_STRTO_SRET(ret_type, func, char_type) \
493 INTERCEPTOR_STRTO_SRET(ret_type, func, char_type) \
494 INTERCEPTOR_STRTO_SRET_LOC(ret_type, func##_l, char_type)
495
496#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
497 INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
498 INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type)
499
500#else
501#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
502 INTERCEPTOR_STRTO(ret_type, func, char_type) \
503 INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \
504 INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
505 INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
506
507#define INTERCEPTORS_STRTO_SRET(ret_type, func, char_type) \
508 INTERCEPTOR_STRTO_SRET(ret_type, func, char_type) \
509 INTERCEPTOR_STRTO_SRET_LOC(ret_type, func##_l, char_type) \
510 INTERCEPTOR_STRTO_SRET_LOC(ret_type, __##func##_l, char_type) \
511 INTERCEPTOR_STRTO_SRET_LOC(ret_type, __##func##_internal, char_type)
512
513#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
514 INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
515 INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \
516 INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
517 INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
518#endif
519
520INTERCEPTORS_STRTO(double, strtod, char)
521INTERCEPTORS_STRTO(float, strtof, char)
522#ifdef __s390x__
523INTERCEPTORS_STRTO_SRET(long double, strtold, char)
524#else
525INTERCEPTORS_STRTO(long double, strtold, char)
526#endif
527INTERCEPTORS_STRTO_BASE(long, strtol, char)
528INTERCEPTORS_STRTO_BASE(long long, strtoll, char)
529INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char)
530INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char)
531INTERCEPTORS_STRTO_BASE(u64, strtouq, char)
532
533INTERCEPTORS_STRTO(double, wcstod, wchar_t)
534INTERCEPTORS_STRTO(float, wcstof, wchar_t)
535#ifdef __s390x__
536INTERCEPTORS_STRTO_SRET(long double, wcstold, wchar_t)
537#else
538INTERCEPTORS_STRTO(long double, wcstold, wchar_t)
539#endif
540INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t)
541INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t)
542INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t)
543INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t)
544
545#if SANITIZER_GLIBC
546INTERCEPTORS_STRTO(double, __isoc23_strtod, char)
547INTERCEPTORS_STRTO(float, __isoc23_strtof, char)
548#ifdef __s390x__
549INTERCEPTORS_STRTO_SRET(long double, __isoc23_strtold, char)
550#else
551INTERCEPTORS_STRTO(long double, __isoc23_strtold, char)
552#endif
553INTERCEPTORS_STRTO_BASE(long, __isoc23_strtol, char)
554INTERCEPTORS_STRTO_BASE(long long, __isoc23_strtoll, char)
555INTERCEPTORS_STRTO_BASE(unsigned long, __isoc23_strtoul, char)
556INTERCEPTORS_STRTO_BASE(unsigned long long, __isoc23_strtoull, char)
557INTERCEPTORS_STRTO_BASE(u64, __isoc23_strtouq, char)
558
559INTERCEPTORS_STRTO(double, __isoc23_wcstod, wchar_t)
560INTERCEPTORS_STRTO(float, __isoc23_wcstof, wchar_t)
561#ifdef __s390x__
562INTERCEPTORS_STRTO_SRET(long double, __isoc23_wcstold, wchar_t)
563#else
564INTERCEPTORS_STRTO(long double, __isoc23_wcstold, wchar_t)
565#endif
566INTERCEPTORS_STRTO_BASE(long, __isoc23_wcstol, wchar_t)
567INTERCEPTORS_STRTO_BASE(long long, __isoc23_wcstoll, wchar_t)
568INTERCEPTORS_STRTO_BASE(unsigned long, __isoc23_wcstoul, wchar_t)
569INTERCEPTORS_STRTO_BASE(unsigned long long, __isoc23_wcstoull, wchar_t)
570#endif
571
572#if SANITIZER_NETBSD
573#define INTERCEPT_STRTO(func) \
574 INTERCEPT_FUNCTION(func); \
575 INTERCEPT_FUNCTION(func##_l);
576#else
577#define INTERCEPT_STRTO(func) \
578 INTERCEPT_FUNCTION(func); \
579 INTERCEPT_FUNCTION(func##_l); \
580 INTERCEPT_FUNCTION(__##func##_l); \
581 INTERCEPT_FUNCTION(__##func##_internal);
582
583#define INTERCEPT_STRTO_VER(func, ver) \
584 INTERCEPT_FUNCTION_VER(func, ver); \
585 INTERCEPT_FUNCTION_VER(func##_l, ver); \
586 INTERCEPT_FUNCTION_VER(__##func##_l, ver); \
587 INTERCEPT_FUNCTION_VER(__##func##_internal, ver);
588#endif
589
590
591// FIXME: support *wprintf in common format interceptors.
592INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
593 ENSURE_MSAN_INITED();
594 int res = REAL(vswprintf)(str, size, format, ap);
595 if (res >= 0) {
596 __msan_unpoison(a: str, size: 4 * (res + 1));
597 }
598 return res;
599}
600
601INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
602 ENSURE_MSAN_INITED();
603 va_list ap;
604 va_start(ap, format);
605 int res = vswprintf(str, size, format, ap);
606 va_end(ap);
607 return res;
608}
609
610#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
611 ENSURE_MSAN_INITED(); \
612 InterceptorScope interceptor_scope; \
613 ret_type res = REAL(func)(s, __VA_ARGS__); \
614 if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \
615 return res;
616
617INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
618 __sanitizer_tm *tm) {
619 INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
620}
621
622INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
623 __sanitizer_tm *tm, void *loc) {
624 INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
625}
626
627#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
628INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
629 __sanitizer_tm *tm, void *loc) {
630 INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
631 loc);
632}
633#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
634#else
635#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
636#endif
637
638INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
639 __sanitizer_tm *tm) {
640 INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
641}
642
643INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
644 __sanitizer_tm *tm, void *loc) {
645 INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
646 loc);
647}
648
649#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
650INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
651 __sanitizer_tm *tm, void *loc) {
652 INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
653 loc);
654}
655#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
656#else
657#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
658#endif
659
660INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
661 ENSURE_MSAN_INITED();
662 int res = REAL(mbtowc)(dest, src, n);
663 if (res != -1 && dest) __msan_unpoison(a: dest, size: sizeof(wchar_t));
664 return res;
665}
666
667INTERCEPTOR(SIZE_T, mbrtowc, wchar_t *dest, const char *src, SIZE_T n,
668 void *ps) {
669 ENSURE_MSAN_INITED();
670 SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
671 if (res != (SIZE_T)-1 && dest) __msan_unpoison(a: dest, size: sizeof(wchar_t));
672 return res;
673}
674
675// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
676INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
677 ENSURE_MSAN_INITED();
678 GET_STORE_STACK_TRACE;
679 wchar_t *res = REAL(wmemcpy)(dest, src, n);
680 CopyShadowAndOrigin(dst: dest, src, size: n * sizeof(wchar_t), stack: &stack);
681 return res;
682}
683
684#if !SANITIZER_NETBSD
685INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
686 ENSURE_MSAN_INITED();
687 GET_STORE_STACK_TRACE;
688 wchar_t *res = REAL(wmempcpy)(dest, src, n);
689 CopyShadowAndOrigin(dst: dest, src, size: n * sizeof(wchar_t), stack: &stack);
690 return res;
691}
692#define MSAN_MAYBE_INTERCEPT_WMEMPCPY INTERCEPT_FUNCTION(wmempcpy)
693#else
694#define MSAN_MAYBE_INTERCEPT_WMEMPCPY
695#endif
696
697INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
698 CHECK(MEM_IS_APP(s));
699 ENSURE_MSAN_INITED();
700 wchar_t *res = REAL(wmemset)(s, c, n);
701 __msan_unpoison(a: s, size: n * sizeof(wchar_t));
702 return res;
703}
704
705INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
706 ENSURE_MSAN_INITED();
707 GET_STORE_STACK_TRACE;
708 wchar_t *res = REAL(wmemmove)(dest, src, n);
709 MoveShadowAndOrigin(dst: dest, src, size: n * sizeof(wchar_t), stack: &stack);
710 return res;
711}
712
713INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
714 ENSURE_MSAN_INITED();
715 int res = REAL(wcscmp)(s1, s2);
716 return res;
717}
718
719INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
720 ENSURE_MSAN_INITED();
721 int res = REAL(gettimeofday)(tv, tz);
722 if (tv)
723 __msan_unpoison(a: tv, size: 16);
724 if (tz)
725 __msan_unpoison(a: tz, size: 8);
726 return res;
727}
728
729#if !SANITIZER_NETBSD
730INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
731 ENSURE_MSAN_INITED();
732 char *res = REAL(fcvt)(x, a, b, c);
733 __msan_unpoison(a: b, size: sizeof(*b));
734 __msan_unpoison(a: c, size: sizeof(*c));
735 if (res)
736 __msan_unpoison(a: res, size: internal_strlen(s: res) + 1);
737 return res;
738}
739#define MSAN_MAYBE_INTERCEPT_FCVT INTERCEPT_FUNCTION(fcvt)
740#else
741#define MSAN_MAYBE_INTERCEPT_FCVT
742#endif
743
744INTERCEPTOR(char *, getenv, char *name) {
745 if (msan_init_is_running)
746 return REAL(getenv)(name);
747 ENSURE_MSAN_INITED();
748 char *res = REAL(getenv)(name);
749 if (res)
750 __msan_unpoison(a: res, size: internal_strlen(s: res) + 1);
751 return res;
752}
753
754extern char **environ;
755
756static void UnpoisonEnviron() {
757 char **envp = environ;
758 for (; *envp; ++envp) {
759 __msan_unpoison(a: envp, size: sizeof(*envp));
760 __msan_unpoison(a: *envp, size: internal_strlen(s: *envp) + 1);
761 }
762 // Trailing NULL pointer.
763 __msan_unpoison(a: envp, size: sizeof(*envp));
764}
765
766INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
767 ENSURE_MSAN_INITED();
768 CHECK_UNPOISONED_STRING(name, 0);
769 int res = REAL(setenv)(name, value, overwrite);
770 if (!res) UnpoisonEnviron();
771 return res;
772}
773
774INTERCEPTOR(int, putenv, char *string) {
775 ENSURE_MSAN_INITED();
776 int res = REAL(putenv)(string);
777 if (!res) UnpoisonEnviron();
778 return res;
779}
780
781#define SANITIZER_STAT_LINUX (SANITIZER_LINUX && __GLIBC_PREREQ(2, 33))
782#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX
783INTERCEPTOR(int, fstat, int fd, void *buf) {
784 ENSURE_MSAN_INITED();
785 int res = REAL(fstat)(fd, buf);
786 if (!res)
787 __msan_unpoison(a: buf, size: __sanitizer::struct_stat_sz);
788 return res;
789}
790# define MSAN_MAYBE_INTERCEPT_FSTAT MSAN_INTERCEPT_FUNC(fstat)
791#else
792#define MSAN_MAYBE_INTERCEPT_FSTAT
793#endif
794
795#if SANITIZER_STAT_LINUX
796INTERCEPTOR(int, fstat64, int fd, void *buf) {
797 ENSURE_MSAN_INITED();
798 int res = REAL(fstat64)(fd, buf);
799 if (!res)
800 __msan_unpoison(a: buf, size: __sanitizer::struct_stat64_sz);
801 return res;
802}
803# define MSAN_MAYBE_INTERCEPT_FSTAT64 MSAN_INTERCEPT_FUNC(fstat64)
804#else
805# define MSAN_MAYBE_INTERCEPT_FSTAT64
806#endif
807
808#if SANITIZER_GLIBC
809INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
810 ENSURE_MSAN_INITED();
811 int res = REAL(__fxstat)(magic, fd, buf);
812 if (!res)
813 __msan_unpoison(a: buf, size: __sanitizer::struct_stat_sz);
814 return res;
815}
816# define MSAN_MAYBE_INTERCEPT___FXSTAT MSAN_INTERCEPT_FUNC(__fxstat)
817#else
818#define MSAN_MAYBE_INTERCEPT___FXSTAT
819#endif
820
821#if SANITIZER_GLIBC
822INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
823 ENSURE_MSAN_INITED();
824 int res = REAL(__fxstat64)(magic, fd, buf);
825 if (!res)
826 __msan_unpoison(a: buf, size: __sanitizer::struct_stat64_sz);
827 return res;
828}
829# define MSAN_MAYBE_INTERCEPT___FXSTAT64 MSAN_INTERCEPT_FUNC(__fxstat64)
830#else
831# define MSAN_MAYBE_INTERCEPT___FXSTAT64
832#endif
833
834#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX
835INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) {
836 ENSURE_MSAN_INITED();
837 int res = REAL(fstatat)(fd, pathname, buf, flags);
838 if (!res) __msan_unpoison(a: buf, size: __sanitizer::struct_stat_sz);
839 return res;
840}
841# define MSAN_MAYBE_INTERCEPT_FSTATAT MSAN_INTERCEPT_FUNC(fstatat)
842#else
843# define MSAN_MAYBE_INTERCEPT_FSTATAT
844#endif
845
846#if SANITIZER_STAT_LINUX
847INTERCEPTOR(int, fstatat64, int fd, char *pathname, void *buf, int flags) {
848 ENSURE_MSAN_INITED();
849 int res = REAL(fstatat64)(fd, pathname, buf, flags);
850 if (!res)
851 __msan_unpoison(a: buf, size: __sanitizer::struct_stat64_sz);
852 return res;
853}
854# define MSAN_MAYBE_INTERCEPT_FSTATAT64 MSAN_INTERCEPT_FUNC(fstatat64)
855#else
856# define MSAN_MAYBE_INTERCEPT_FSTATAT64
857#endif
858
859#if SANITIZER_GLIBC
860INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
861 int flags) {
862 ENSURE_MSAN_INITED();
863 int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
864 if (!res) __msan_unpoison(a: buf, size: __sanitizer::struct_stat_sz);
865 return res;
866}
867# define MSAN_MAYBE_INTERCEPT___FXSTATAT MSAN_INTERCEPT_FUNC(__fxstatat)
868#else
869# define MSAN_MAYBE_INTERCEPT___FXSTATAT
870#endif
871
872#if SANITIZER_GLIBC
873INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
874 int flags) {
875 ENSURE_MSAN_INITED();
876 int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
877 if (!res) __msan_unpoison(a: buf, size: __sanitizer::struct_stat64_sz);
878 return res;
879}
880# define MSAN_MAYBE_INTERCEPT___FXSTATAT64 MSAN_INTERCEPT_FUNC(__fxstatat64)
881#else
882# define MSAN_MAYBE_INTERCEPT___FXSTATAT64
883#endif
884
885INTERCEPTOR(int, pipe, int pipefd[2]) {
886 if (msan_init_is_running)
887 return REAL(pipe)(pipefd);
888 ENSURE_MSAN_INITED();
889 int res = REAL(pipe)(pipefd);
890 if (!res)
891 __msan_unpoison(a: pipefd, size: sizeof(int[2]));
892 return res;
893}
894
895INTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
896 ENSURE_MSAN_INITED();
897 int res = REAL(pipe2)(pipefd, flags);
898 if (!res)
899 __msan_unpoison(a: pipefd, size: sizeof(int[2]));
900 return res;
901}
902
903INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
904 ENSURE_MSAN_INITED();
905 int res = REAL(socketpair)(domain, type, protocol, sv);
906 if (!res)
907 __msan_unpoison(a: sv, size: sizeof(int[2]));
908 return res;
909}
910
911#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
912INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
913 ENSURE_MSAN_INITED();
914 char *res = REAL(fgets_unlocked)(s, size, stream);
915 if (res)
916 __msan_unpoison(a: s, size: internal_strlen(s) + 1);
917 return res;
918}
919#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
920#else
921#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
922#endif
923
924#define INTERCEPTOR_GETRLIMIT_BODY(func, resource, rlim) \
925 if (msan_init_is_running) \
926 return REAL(getrlimit)(resource, rlim); \
927 ENSURE_MSAN_INITED(); \
928 int res = REAL(func)(resource, rlim); \
929 if (!res) \
930 __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz); \
931 return res
932
933INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
934 INTERCEPTOR_GETRLIMIT_BODY(getrlimit, resource, rlim);
935}
936
937#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
938INTERCEPTOR(int, __getrlimit, int resource, void *rlim) {
939 INTERCEPTOR_GETRLIMIT_BODY(__getrlimit, resource, rlim);
940}
941
942INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
943 if (msan_init_is_running) return REAL(getrlimit64)(resource, rlim);
944 ENSURE_MSAN_INITED();
945 int res = REAL(getrlimit64)(resource, rlim);
946 if (!res) __msan_unpoison(a: rlim, size: __sanitizer::struct_rlimit64_sz);
947 return res;
948}
949
950INTERCEPTOR(int, prlimit, int pid, int resource, void *new_rlimit,
951 void *old_rlimit) {
952 if (msan_init_is_running)
953 return REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
954 ENSURE_MSAN_INITED();
955 CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit_sz);
956 int res = REAL(prlimit)(pid, resource, new_rlimit, old_rlimit);
957 if (!res) __msan_unpoison(a: old_rlimit, size: __sanitizer::struct_rlimit_sz);
958 return res;
959}
960
961INTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit,
962 void *old_rlimit) {
963 if (msan_init_is_running)
964 return REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
965 ENSURE_MSAN_INITED();
966 CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit64_sz);
967 int res = REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit);
968 if (!res) __msan_unpoison(a: old_rlimit, size: __sanitizer::struct_rlimit64_sz);
969 return res;
970}
971
972#define MSAN_MAYBE_INTERCEPT___GETRLIMIT INTERCEPT_FUNCTION(__getrlimit)
973#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
974#define MSAN_MAYBE_INTERCEPT_PRLIMIT INTERCEPT_FUNCTION(prlimit)
975#define MSAN_MAYBE_INTERCEPT_PRLIMIT64 INTERCEPT_FUNCTION(prlimit64)
976#else
977#define MSAN_MAYBE_INTERCEPT___GETRLIMIT
978#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
979#define MSAN_MAYBE_INTERCEPT_PRLIMIT
980#define MSAN_MAYBE_INTERCEPT_PRLIMIT64
981#endif
982
983INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
984 ENSURE_MSAN_INITED();
985 int res = REAL(gethostname)(name, len);
986 if (!res || (res == -1 && errno == errno_ENAMETOOLONG)) {
987 SIZE_T real_len = internal_strnlen(s: name, maxlen: len);
988 if (real_len < len)
989 ++real_len;
990 __msan_unpoison(a: name, size: real_len);
991 }
992 return res;
993}
994
995#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
996INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
997 int timeout) {
998 ENSURE_MSAN_INITED();
999 int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
1000 if (res > 0) {
1001 __msan_unpoison(a: events, size: __sanitizer::struct_epoll_event_sz * res);
1002 }
1003 return res;
1004}
1005#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
1006#else
1007#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
1008#endif
1009
1010#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
1011INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
1012 int timeout, void *sigmask) {
1013 ENSURE_MSAN_INITED();
1014 int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
1015 if (res > 0) {
1016 __msan_unpoison(a: events, size: __sanitizer::struct_epoll_event_sz * res);
1017 }
1018 return res;
1019}
1020#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
1021#else
1022#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
1023#endif
1024
1025INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
1026 GET_MALLOC_STACK_TRACE;
1027 if (DlsymAlloc::Use())
1028 return DlsymAlloc::Callocate(nmemb, size);
1029 return msan_calloc(nmemb, size, stack: &stack);
1030}
1031
1032INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
1033 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
1034 return DlsymAlloc::Realloc(ptr, new_size: size);
1035 GET_MALLOC_STACK_TRACE;
1036 return msan_realloc(ptr, size, stack: &stack);
1037}
1038
1039INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) {
1040 GET_MALLOC_STACK_TRACE;
1041 return msan_reallocarray(ptr, nmemb, size, stack: &stack);
1042}
1043
1044INTERCEPTOR(void *, malloc, SIZE_T size) {
1045 if (DlsymAlloc::Use())
1046 return DlsymAlloc::Allocate(size_in_bytes: size);
1047 GET_MALLOC_STACK_TRACE;
1048 return msan_malloc(size, stack: &stack);
1049}
1050
1051void __msan_allocated_memory(const void *data, uptr size) {
1052 if (flags()->poison_in_malloc) {
1053 GET_MALLOC_STACK_TRACE;
1054 stack.tag = STACK_TRACE_TAG_POISON;
1055 PoisonMemory(dst: data, size, stack: &stack);
1056 }
1057}
1058
1059void __msan_copy_shadow(void *dest, const void *src, uptr n) {
1060 GET_STORE_STACK_TRACE;
1061 MoveShadowAndOrigin(dst: dest, src, size: n, stack: &stack);
1062}
1063
1064void __sanitizer_dtor_callback(const void *data, uptr size) {
1065 if (flags()->poison_in_dtor) {
1066 GET_MALLOC_STACK_TRACE;
1067 stack.tag = STACK_TRACE_TAG_POISON;
1068 PoisonMemory(dst: data, size, stack: &stack);
1069 }
1070}
1071
1072void __sanitizer_dtor_callback_fields(const void *data, uptr size) {
1073 if (flags()->poison_in_dtor) {
1074 GET_MALLOC_STACK_TRACE;
1075 stack.tag = STACK_TRACE_TAG_FIELDS;
1076 PoisonMemory(dst: data, size, stack: &stack);
1077 }
1078}
1079
1080void __sanitizer_dtor_callback_vptr(const void *data) {
1081 if (flags()->poison_in_dtor) {
1082 GET_MALLOC_STACK_TRACE;
1083 stack.tag = STACK_TRACE_TAG_VPTR;
1084 PoisonMemory(dst: data, size: sizeof(void *), stack: &stack);
1085 }
1086}
1087
1088template <class Mmap>
1089static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
1090 int prot, int flags, int fd, OFF64_T offset) {
1091 SIZE_T rounded_length = RoundUpTo(size: length, boundary: GetPageSize());
1092 void *end_addr = (char *)addr + (rounded_length - 1);
1093 if (addr && (!MEM_IS_APP(addr) || !MEM_IS_APP(end_addr))) {
1094 if (flags & map_fixed) {
1095 errno = errno_EINVAL;
1096 return (void *)-1;
1097 } else {
1098 addr = nullptr;
1099 }
1100 }
1101 void *res = real_mmap(addr, length, prot, flags, fd, offset);
1102 if (res != (void *)-1) {
1103 void *end_res = (char *)res + (rounded_length - 1);
1104 if (MEM_IS_APP(res) && MEM_IS_APP(end_res)) {
1105 __msan_unpoison(a: res, size: rounded_length);
1106 } else {
1107 // Application has attempted to map more memory than is supported by
1108 // MSAN. Act as if we ran out of memory.
1109 internal_munmap(addr: res, length);
1110 errno = errno_ENOMEM;
1111 return (void *)-1;
1112 }
1113 }
1114 return res;
1115}
1116
1117INTERCEPTOR(int, getrusage, int who, void *usage) {
1118 ENSURE_MSAN_INITED();
1119 int res = REAL(getrusage)(who, usage);
1120 if (res == 0) {
1121 __msan_unpoison(a: usage, size: __sanitizer::struct_rusage_sz);
1122 }
1123 return res;
1124}
1125
1126class SignalHandlerScope {
1127 public:
1128 SignalHandlerScope() {
1129 if (MsanThread *t = GetCurrentThread())
1130 t->EnterSignalHandler();
1131 }
1132 ~SignalHandlerScope() {
1133 if (MsanThread *t = GetCurrentThread())
1134 t->LeaveSignalHandler();
1135 }
1136};
1137
1138// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
1139// Access to sigactions[] is gone with relaxed atomics to avoid data race with
1140// the signal handler.
1141const int kMaxSignals = 1024;
1142static atomic_uintptr_t sigactions[kMaxSignals];
1143static StaticSpinMutex sigactions_mu;
1144
1145static void SignalHandler(int signo) {
1146 SignalHandlerScope signal_handler_scope;
1147 ScopedThreadLocalStateBackup stlsb;
1148 UnpoisonParam(n: 1);
1149
1150 typedef void (*signal_cb)(int x);
1151 signal_cb cb =
1152 (signal_cb)atomic_load(a: &sigactions[signo], mo: memory_order_relaxed);
1153 cb(signo);
1154}
1155
1156static void SignalAction(int signo, void *si, void *uc) {
1157 SignalHandlerScope signal_handler_scope;
1158 ScopedThreadLocalStateBackup stlsb;
1159 UnpoisonParam(n: 3);
1160 __msan_unpoison(a: si, size: sizeof(__sanitizer_siginfo));
1161 __msan_unpoison(a: uc, size: ucontext_t_sz(uctx: uc));
1162
1163 typedef void (*sigaction_cb)(int, void *, void *);
1164 sigaction_cb cb =
1165 (sigaction_cb)atomic_load(a: &sigactions[signo], mo: memory_order_relaxed);
1166 cb(signo, si, uc);
1167 CHECK_UNPOISONED(uc, ucontext_t_sz(uc));
1168}
1169
1170static void read_sigaction(const __sanitizer_sigaction *act) {
1171 CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags));
1172 if (act->sa_flags & __sanitizer::sa_siginfo)
1173 CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction));
1174 else
1175 CHECK_UNPOISONED(&act->handler, sizeof(act->handler));
1176 CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask));
1177}
1178
1179extern "C" int pthread_attr_init(void *attr);
1180extern "C" int pthread_attr_destroy(void *attr);
1181
1182static void *MsanThreadStartFunc(void *arg) {
1183 MsanThread *t = (MsanThread *)arg;
1184 SetCurrentThread(t);
1185 t->Init();
1186 SetSigProcMask(set: &t->starting_sigset_, oldset: nullptr);
1187 return t->ThreadStart();
1188}
1189
1190INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
1191 void * param) {
1192 ENSURE_MSAN_INITED(); // for GetTlsSize()
1193 __sanitizer_pthread_attr_t myattr;
1194 if (!attr) {
1195 pthread_attr_init(attr: &myattr);
1196 attr = &myattr;
1197 }
1198
1199 AdjustStackSize(attr);
1200
1201 MsanThread *t = MsanThread::Create(start_routine: callback, arg: param);
1202 ScopedBlockSignals block(&t->starting_sigset_);
1203 int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
1204
1205 if (attr == &myattr)
1206 pthread_attr_destroy(attr: &myattr);
1207 if (!res) {
1208 __msan_unpoison(a: th, size: __sanitizer::pthread_t_sz);
1209 }
1210 return res;
1211}
1212
1213INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
1214 void (*dtor)(void *value)) {
1215 if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
1216 ENSURE_MSAN_INITED();
1217 int res = REAL(pthread_key_create)(key, dtor);
1218 if (!res && key)
1219 __msan_unpoison(a: key, size: sizeof(*key));
1220 return res;
1221}
1222
1223#if SANITIZER_NETBSD
1224INTERCEPTOR(int, __libc_thr_keycreate, __sanitizer_pthread_key_t *m,
1225 void (*dtor)(void *value))
1226ALIAS(WRAP(pthread_key_create));
1227#endif
1228
1229INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
1230 ENSURE_MSAN_INITED();
1231 int res = REAL(pthread_join)(thread, retval);
1232 if (!res && retval)
1233 __msan_unpoison(a: retval, size: sizeof(*retval));
1234 return res;
1235}
1236
1237#if SANITIZER_GLIBC
1238INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **retval) {
1239 ENSURE_MSAN_INITED();
1240 int res = REAL(pthread_tryjoin_np)(thread, retval);
1241 if (!res && retval)
1242 __msan_unpoison(a: retval, size: sizeof(*retval));
1243 return res;
1244}
1245
1246INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **retval,
1247 const struct timespec *abstime) {
1248 int res = REAL(pthread_timedjoin_np)(thread, retval, abstime);
1249 if (!res && retval)
1250 __msan_unpoison(a: retval, size: sizeof(*retval));
1251 return res;
1252}
1253#endif
1254
1255DEFINE_INTERNAL_PTHREAD_FUNCTIONS
1256
1257extern char *tzname[2];
1258
1259INTERCEPTOR(void, tzset, int fake) {
1260 ENSURE_MSAN_INITED();
1261 InterceptorScope interceptor_scope;
1262 REAL(tzset)(fake);
1263 if (tzname[0])
1264 __msan_unpoison(a: tzname[0], size: internal_strlen(s: tzname[0]) + 1);
1265 if (tzname[1])
1266 __msan_unpoison(a: tzname[1], size: internal_strlen(s: tzname[1]) + 1);
1267 return;
1268}
1269
1270struct MSanAtExitRecord {
1271 void (*func)(void *arg);
1272 void *arg;
1273};
1274
1275struct InterceptorContext {
1276 Mutex atexit_mu;
1277 Vector<struct MSanAtExitRecord *> AtExitStack;
1278
1279 InterceptorContext()
1280 : AtExitStack() {
1281 }
1282};
1283
1284alignas(64) static char interceptor_placeholder[sizeof(InterceptorContext)];
1285InterceptorContext *interceptor_ctx() {
1286 return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
1287}
1288
1289void MSanAtExitWrapper() {
1290 MSanAtExitRecord *r;
1291 {
1292 Lock l(&interceptor_ctx()->atexit_mu);
1293
1294 uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
1295 r = interceptor_ctx()->AtExitStack[element];
1296 interceptor_ctx()->AtExitStack.PopBack();
1297 }
1298
1299 UnpoisonParam(n: 1);
1300 ((void(*)())r->func)();
1301 InternalFree(p: r);
1302}
1303
1304void MSanCxaAtExitWrapper(void *arg) {
1305 UnpoisonParam(n: 1);
1306 MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
1307 // libc before 2.27 had race which caused occasional double handler execution
1308 // https://sourceware.org/ml/libc-alpha/2017-08/msg01204.html
1309 if (!r->func)
1310 return;
1311 r->func(r->arg);
1312 r->func = nullptr;
1313}
1314
1315static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso);
1316
1317// Unpoison argument shadow for C++ module destructors.
1318INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
1319 void *dso_handle) {
1320 if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
1321 return setup_at_exit_wrapper(f: (void(*)())func, arg, dso: dso_handle);
1322}
1323
1324// Unpoison argument shadow for C++ module destructors.
1325INTERCEPTOR(int, atexit, void (*func)()) {
1326 // Avoid calling real atexit as it is unreachable on at least on Linux.
1327 if (msan_init_is_running)
1328 return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0);
1329 return setup_at_exit_wrapper(f: (void(*)())func, arg: 0, dso: 0);
1330}
1331
1332static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
1333 ENSURE_MSAN_INITED();
1334 MSanAtExitRecord *r =
1335 (MSanAtExitRecord *)InternalAlloc(size: sizeof(MSanAtExitRecord));
1336 r->func = (void(*)(void *a))f;
1337 r->arg = arg;
1338 int res;
1339 if (!dso) {
1340 // NetBSD does not preserve the 2nd argument if dso is equal to 0
1341 // Store ctx in a local stack-like structure
1342
1343 Lock l(&interceptor_ctx()->atexit_mu);
1344
1345 res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0);
1346 if (!res) {
1347 interceptor_ctx()->AtExitStack.PushBack(v: r);
1348 }
1349 } else {
1350 res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso);
1351 }
1352 return res;
1353}
1354
1355// NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly
1356// with MSan.
1357#if SANITIZER_LINUX
1358INTERCEPTOR(int, openpty, int *aparent, int *aworker, char *name,
1359 const void *termp, const void *winp) {
1360 ENSURE_MSAN_INITED();
1361 InterceptorScope interceptor_scope;
1362 int res = REAL(openpty)(aparent, aworker, name, termp, winp);
1363 if (!res) {
1364 __msan_unpoison(a: aparent, size: sizeof(*aparent));
1365 __msan_unpoison(a: aworker, size: sizeof(*aworker));
1366 }
1367 return res;
1368}
1369#define MSAN_MAYBE_INTERCEPT_OPENPTY INTERCEPT_FUNCTION(openpty)
1370#else
1371#define MSAN_MAYBE_INTERCEPT_OPENPTY
1372#endif
1373
1374// NetBSD ships with forkpty(3) in -lutil, that needs to be prebuilt explicitly
1375// with MSan.
1376#if SANITIZER_LINUX
1377INTERCEPTOR(int, forkpty, int *aparent, char *name, const void *termp,
1378 const void *winp) {
1379 ENSURE_MSAN_INITED();
1380 InterceptorScope interceptor_scope;
1381 int res = REAL(forkpty)(aparent, name, termp, winp);
1382 if (res != -1)
1383 __msan_unpoison(a: aparent, size: sizeof(*aparent));
1384 return res;
1385}
1386#define MSAN_MAYBE_INTERCEPT_FORKPTY INTERCEPT_FUNCTION(forkpty)
1387#else
1388#define MSAN_MAYBE_INTERCEPT_FORKPTY
1389#endif
1390
1391struct MSanInterceptorContext {
1392 bool in_interceptor_scope;
1393};
1394
1395namespace __msan {
1396
1397int OnExit() {
1398 // FIXME: ask frontend whether we need to return failure.
1399 return 0;
1400}
1401
1402} // namespace __msan
1403
1404// A version of CHECK_UNPOISONED using a saved scope value. Used in common
1405// interceptors.
1406#define CHECK_UNPOISONED_CTX(ctx, x, n) \
1407 do { \
1408 if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
1409 CHECK_UNPOISONED_0(x, n); \
1410 } while (0)
1411
1412#define MSAN_INTERCEPT_FUNC(name) \
1413 do { \
1414 if (!INTERCEPT_FUNCTION(name)) \
1415 VReport(1, "MemorySanitizer: failed to intercept '%s'\n", #name); \
1416 } while (0)
1417
1418#define MSAN_INTERCEPT_FUNC_VER(name, ver) \
1419 do { \
1420 if (!INTERCEPT_FUNCTION_VER(name, ver)) \
1421 VReport(1, "MemorySanitizer: failed to intercept '%s@@%s'\n", #name, \
1422 ver); \
1423 } while (0)
1424#define MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \
1425 do { \
1426 if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \
1427 VReport(1, "MemorySanitizer: failed to intercept '%s@@%s' or '%s'\n", \
1428 #name, ver, #name); \
1429 } while (0)
1430
1431#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
1432#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
1433 MSAN_INTERCEPT_FUNC_VER(name, ver)
1434#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
1435 MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
1436#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \
1437 UnpoisonParam(count)
1438#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
1439 __msan_unpoison(ptr, size)
1440#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
1441 CHECK_UNPOISONED_CTX(ctx, ptr, size)
1442#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
1443 __msan_unpoison(ptr, size)
1444#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
1445 if (msan_init_is_running) \
1446 return REAL(func)(__VA_ARGS__); \
1447 ENSURE_MSAN_INITED(); \
1448 MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
1449 ctx = (void *)&msan_ctx; \
1450 (void)ctx; \
1451 InterceptorScope interceptor_scope; \
1452 __msan_unpoison(__errno_location(), sizeof(int));
1453#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
1454 do { \
1455 } while (false)
1456#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
1457 do { \
1458 } while (false)
1459#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
1460 do { \
1461 } while (false)
1462#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
1463 do { \
1464 } while (false)
1465#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
1466 do { \
1467 } while (false) // FIXME
1468#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
1469 do { \
1470 } while (false) // FIXME
1471#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
1472#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
1473#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
1474 do { \
1475 link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \
1476 if (filename && map) \
1477 ForEachMappedRegion(map, __msan_unpoison); \
1478 } while (false)
1479
1480#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!msan_inited)
1481
1482#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
1483 if (MsanThread *t = GetCurrentThread()) { \
1484 *begin = t->tls_begin(); \
1485 *end = t->tls_end(); \
1486 } else { \
1487 *begin = *end = 0; \
1488 }
1489
1490#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
1491 { \
1492 (void)ctx; \
1493 return __msan_memset(block, c, size); \
1494 }
1495#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
1496 { \
1497 (void)ctx; \
1498 return __msan_memmove(to, from, size); \
1499 }
1500#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
1501 { \
1502 (void)ctx; \
1503 return __msan_memcpy(to, from, size); \
1504 }
1505
1506#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \
1507 do { \
1508 GET_STORE_STACK_TRACE; \
1509 CopyShadowAndOrigin(to, from, size, &stack); \
1510 __msan_unpoison(to + size, 1); \
1511 } while (false)
1512
1513#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \
1514 offset) \
1515 do { \
1516 return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
1517 } while (false)
1518
1519#include "sanitizer_common/sanitizer_platform_interceptors.h"
1520#include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
1521#include "sanitizer_common/sanitizer_common_interceptors.inc"
1522
1523static uptr signal_impl(int signo, uptr cb);
1524static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
1525 __sanitizer_sigaction *oldact);
1526
1527#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \
1528 { return sigaction_impl(signo, act, oldact); }
1529
1530#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \
1531 { \
1532 handler = signal_impl(signo, handler); \
1533 InterceptorScope interceptor_scope; \
1534 return REAL(func)(signo, handler); \
1535 }
1536
1537#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_MSAN_INITED()
1538
1539#include "sanitizer_common/sanitizer_signal_interceptors.inc"
1540
1541static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
1542 __sanitizer_sigaction *oldact) {
1543 ENSURE_MSAN_INITED();
1544 if (signo <= 0 || signo >= kMaxSignals) {
1545 errno = errno_EINVAL;
1546 return -1;
1547 }
1548 if (act) read_sigaction(act);
1549 int res;
1550 if (flags()->wrap_signals) {
1551 SpinMutexLock lock(&sigactions_mu);
1552 uptr old_cb = atomic_load(a: &sigactions[signo], mo: memory_order_relaxed);
1553 __sanitizer_sigaction new_act;
1554 __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
1555 if (act) {
1556 REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
1557 uptr cb = (uptr)pnew_act->sigaction;
1558 uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
1559 ? (uptr)SignalAction
1560 : (uptr)SignalHandler;
1561 if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
1562 atomic_store(a: &sigactions[signo], v: cb, mo: memory_order_relaxed);
1563 pnew_act->sigaction = (decltype(pnew_act->sigaction))new_cb;
1564 }
1565 }
1566 res = REAL(SIGACTION_SYMNAME)(signo, pnew_act, oldact);
1567 if (res == 0 && oldact) {
1568 uptr cb = (uptr)oldact->sigaction;
1569 if (cb == (uptr)SignalAction || cb == (uptr)SignalHandler) {
1570 oldact->sigaction = (decltype(oldact->sigaction))old_cb;
1571 }
1572 }
1573 } else {
1574 res = REAL(SIGACTION_SYMNAME)(signo, act, oldact);
1575 }
1576
1577 if (res == 0 && oldact) {
1578 __msan_unpoison(a: oldact, size: sizeof(__sanitizer_sigaction));
1579 }
1580 return res;
1581}
1582
1583static uptr signal_impl(int signo, uptr cb) {
1584 ENSURE_MSAN_INITED();
1585 if (signo <= 0 || signo >= kMaxSignals) {
1586 errno = errno_EINVAL;
1587 return -1;
1588 }
1589 if (flags()->wrap_signals) {
1590 SpinMutexLock lock(&sigactions_mu);
1591 if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
1592 atomic_store(a: &sigactions[signo], v: cb, mo: memory_order_relaxed);
1593 cb = (uptr)&SignalHandler;
1594 }
1595 }
1596 return cb;
1597}
1598
1599#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
1600#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
1601 do { \
1602 } while (false)
1603#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
1604 do { \
1605 } while (false)
1606#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
1607#include "sanitizer_common/sanitizer_common_syscalls.inc"
1608#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
1609
1610INTERCEPTOR(const char *, strsignal, int sig) {
1611 void *ctx;
1612 COMMON_INTERCEPTOR_ENTER(ctx, strsignal, sig);
1613 const char *res = REAL(strsignal)(sig);
1614 if (res)
1615 __msan_unpoison(a: res, size: internal_strlen(s: res) + 1);
1616 return res;
1617}
1618
1619INTERCEPTOR(int, dladdr, void *addr, void *info) {
1620 void *ctx;
1621 COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info);
1622 int res = REAL(dladdr)(addr, info);
1623 if (res != 0)
1624 UnpoisonDllAddrInfo(info);
1625 return res;
1626}
1627
1628#if SANITIZER_GLIBC
1629INTERCEPTOR(int, dladdr1, void *addr, void *info, void **extra_info,
1630 int flags) {
1631 void *ctx;
1632 COMMON_INTERCEPTOR_ENTER(ctx, dladdr1, addr, info, extra_info, flags);
1633 int res = REAL(dladdr1)(addr, info, extra_info, flags);
1634 if (res != 0) {
1635 UnpoisonDllAddrInfo(info);
1636 UnpoisonDllAddr1ExtraInfo(extra_info, flags);
1637 }
1638 return res;
1639}
1640# define MSAN_MAYBE_INTERCEPT_DLADDR1 MSAN_INTERCEPT_FUNC(dladdr1)
1641#else
1642#define MSAN_MAYBE_INTERCEPT_DLADDR1
1643#endif
1644
1645INTERCEPTOR(char *, dlerror, int fake) {
1646 void *ctx;
1647 COMMON_INTERCEPTOR_ENTER(ctx, dlerror, fake);
1648 char *res = REAL(dlerror)(fake);
1649 if (res)
1650 __msan_unpoison(a: res, size: internal_strlen(s: res) + 1);
1651 return res;
1652}
1653
1654typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
1655 void *data);
1656struct dl_iterate_phdr_data {
1657 dl_iterate_phdr_cb callback;
1658 void *data;
1659};
1660
1661static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
1662 void *data) {
1663 if (info) {
1664 __msan_unpoison(a: info, size);
1665 if (info->dlpi_phdr && info->dlpi_phnum)
1666 __msan_unpoison(a: info->dlpi_phdr, size: struct_ElfW_Phdr_sz * info->dlpi_phnum);
1667 if (info->dlpi_name)
1668 __msan_unpoison(a: info->dlpi_name, size: internal_strlen(s: info->dlpi_name) + 1);
1669 }
1670 dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
1671 UnpoisonParam(n: 3);
1672 return cbdata->callback(info, size, cbdata->data);
1673}
1674
1675INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
1676 ENSURE_MSAN_INITED();
1677 void *p = REAL(shmat)(shmid, shmaddr, shmflg);
1678 if (p != (void *)-1) {
1679 __sanitizer_shmid_ds ds;
1680 int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
1681 if (!res) {
1682 __msan_unpoison(a: p, size: ds.shm_segsz);
1683 }
1684 }
1685 return p;
1686}
1687
1688INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
1689 void *ctx;
1690 COMMON_INTERCEPTOR_ENTER(ctx, dl_iterate_phdr, callback, data);
1691 dl_iterate_phdr_data cbdata;
1692 cbdata.callback = callback;
1693 cbdata.data = data;
1694 int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
1695 return res;
1696}
1697
1698// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
1699INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
1700 ENSURE_MSAN_INITED();
1701 wchar_t *res = REAL(wcschr)(s, wc, ps);
1702 return res;
1703}
1704
1705// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
1706INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
1707 ENSURE_MSAN_INITED();
1708 GET_STORE_STACK_TRACE;
1709 wchar_t *res = REAL(wcscpy)(dest, src);
1710 CopyShadowAndOrigin(dst: dest, src, size: sizeof(wchar_t) * (internal_wcslen(s: src) + 1),
1711 stack: &stack);
1712 return res;
1713}
1714
1715INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
1716 ENSURE_MSAN_INITED();
1717 GET_STORE_STACK_TRACE;
1718 SIZE_T copy_size = internal_wcsnlen(s: src, maxlen: n);
1719 if (copy_size < n) copy_size++; // trailing \0
1720 wchar_t *res = REAL(wcsncpy)(dest, src, n);
1721 CopyShadowAndOrigin(dst: dest, src, size: copy_size * sizeof(wchar_t), stack: &stack);
1722 __msan_unpoison(a: dest + copy_size, size: (n - copy_size) * sizeof(wchar_t));
1723 return res;
1724}
1725
1726// These interface functions reside here so that they can use
1727// REAL(memset), etc.
1728void __msan_unpoison(const void *a, uptr size) {
1729 if (!MEM_IS_APP(a)) return;
1730 SetShadow(ptr: a, size, value: 0);
1731}
1732
1733void __msan_poison(const void *a, uptr size) {
1734 if (!MEM_IS_APP(a)) return;
1735 SetShadow(ptr: a, size, value: __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
1736}
1737
1738void __msan_poison_stack(void *a, uptr size) {
1739 if (!MEM_IS_APP(a)) return;
1740 SetShadow(ptr: a, size, value: __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
1741}
1742
1743void __msan_unpoison_param(uptr n) { UnpoisonParam(n); }
1744
1745void __msan_clear_and_unpoison(void *a, uptr size) {
1746 REAL(memset)(a, 0, size);
1747 SetShadow(ptr: a, size, value: 0);
1748}
1749
1750void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
1751 if (!msan_inited) return internal_memcpy(dest, src, n);
1752 if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
1753 return REAL(memcpy)(dest, src, n);
1754 ENSURE_MSAN_INITED();
1755 GET_STORE_STACK_TRACE;
1756 void *res = REAL(memcpy)(dest, src, n);
1757 CopyShadowAndOrigin(dst: dest, src, size: n, stack: &stack);
1758 return res;
1759}
1760
1761void *__msan_memset(void *s, int c, SIZE_T n) {
1762 if (!msan_inited) return internal_memset(s, c, n);
1763 if (msan_init_is_running) return REAL(memset)(s, c, n);
1764 ENSURE_MSAN_INITED();
1765 void *res = REAL(memset)(s, c, n);
1766 __msan_unpoison(a: s, size: n);
1767 return res;
1768}
1769
1770void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
1771 if (!msan_inited) return internal_memmove(dest, src, n);
1772 if (msan_init_is_running) return REAL(memmove)(dest, src, n);
1773 ENSURE_MSAN_INITED();
1774 GET_STORE_STACK_TRACE;
1775 void *res = REAL(memmove)(dest, src, n);
1776 MoveShadowAndOrigin(dst: dest, src, size: n, stack: &stack);
1777 return res;
1778}
1779
1780void __msan_unpoison_string(const char* s) {
1781 if (!MEM_IS_APP(s)) return;
1782 __msan_unpoison(a: s, size: internal_strlen(s) + 1);
1783}
1784
1785namespace __msan {
1786
1787void InitializeInterceptors() {
1788 static int inited = 0;
1789 CHECK_EQ(inited, 0);
1790
1791 __interception::DoesNotSupportStaticLinking();
1792
1793 new(interceptor_ctx()) InterceptorContext();
1794
1795 InitializeCommonInterceptors();
1796 InitializeSignalInterceptors();
1797
1798 INTERCEPT_FUNCTION(posix_memalign);
1799 MSAN_MAYBE_INTERCEPT_MEMALIGN;
1800 MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
1801 INTERCEPT_FUNCTION(valloc);
1802 MSAN_MAYBE_INTERCEPT_PVALLOC;
1803 INTERCEPT_FUNCTION(malloc);
1804 INTERCEPT_FUNCTION(calloc);
1805 INTERCEPT_FUNCTION(realloc);
1806 INTERCEPT_FUNCTION(reallocarray);
1807 INTERCEPT_FUNCTION(free);
1808 MSAN_MAYBE_INTERCEPT_FREE_SIZED;
1809 MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED;
1810 MSAN_MAYBE_INTERCEPT_CFREE;
1811 MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
1812 MSAN_MAYBE_INTERCEPT_MALLINFO;
1813 MSAN_MAYBE_INTERCEPT_MALLINFO2;
1814 MSAN_MAYBE_INTERCEPT_MALLOPT;
1815 MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
1816 INTERCEPT_FUNCTION(fread);
1817 MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
1818 INTERCEPT_FUNCTION(memccpy);
1819 MSAN_MAYBE_INTERCEPT_MEMPCPY;
1820 INTERCEPT_FUNCTION(bcopy);
1821 INTERCEPT_FUNCTION(wmemset);
1822 INTERCEPT_FUNCTION(wmemcpy);
1823 MSAN_MAYBE_INTERCEPT_WMEMPCPY;
1824 INTERCEPT_FUNCTION(wmemmove);
1825 INTERCEPT_FUNCTION(strcpy);
1826 MSAN_MAYBE_INTERCEPT_STPCPY;
1827 MSAN_MAYBE_INTERCEPT_STPNCPY;
1828 INTERCEPT_FUNCTION(strdup);
1829 MSAN_MAYBE_INTERCEPT___STRDUP;
1830 INTERCEPT_FUNCTION(strncpy);
1831 MSAN_MAYBE_INTERCEPT_GCVT;
1832 INTERCEPT_FUNCTION(strcat);
1833 INTERCEPT_FUNCTION(strncat);
1834 INTERCEPT_STRTO(strtod);
1835 INTERCEPT_STRTO(strtof);
1836#ifdef SANITIZER_NLDBL_VERSION
1837 INTERCEPT_STRTO_VER(strtold, SANITIZER_NLDBL_VERSION);
1838#else
1839 INTERCEPT_STRTO(strtold);
1840#endif
1841 INTERCEPT_STRTO(strtol);
1842 INTERCEPT_STRTO(strtoul);
1843 INTERCEPT_STRTO(strtoll);
1844 INTERCEPT_STRTO(strtoull);
1845 INTERCEPT_STRTO(strtouq);
1846 INTERCEPT_STRTO(wcstod);
1847 INTERCEPT_STRTO(wcstof);
1848#ifdef SANITIZER_NLDBL_VERSION
1849 INTERCEPT_STRTO_VER(wcstold, SANITIZER_NLDBL_VERSION);
1850#else
1851 INTERCEPT_STRTO(wcstold);
1852#endif
1853 INTERCEPT_STRTO(wcstol);
1854 INTERCEPT_STRTO(wcstoul);
1855 INTERCEPT_STRTO(wcstoll);
1856 INTERCEPT_STRTO(wcstoull);
1857#if SANITIZER_GLIBC
1858 INTERCEPT_STRTO(__isoc23_strtod);
1859 INTERCEPT_STRTO(__isoc23_strtof);
1860 INTERCEPT_STRTO(__isoc23_strtold);
1861 INTERCEPT_STRTO(__isoc23_strtol);
1862 INTERCEPT_STRTO(__isoc23_strtoul);
1863 INTERCEPT_STRTO(__isoc23_strtoll);
1864 INTERCEPT_STRTO(__isoc23_strtoull);
1865 INTERCEPT_STRTO(__isoc23_strtouq);
1866 INTERCEPT_STRTO(__isoc23_wcstod);
1867 INTERCEPT_STRTO(__isoc23_wcstof);
1868 INTERCEPT_STRTO(__isoc23_wcstold);
1869 INTERCEPT_STRTO(__isoc23_wcstol);
1870 INTERCEPT_STRTO(__isoc23_wcstoul);
1871 INTERCEPT_STRTO(__isoc23_wcstoll);
1872 INTERCEPT_STRTO(__isoc23_wcstoull);
1873#endif
1874
1875#ifdef SANITIZER_NLDBL_VERSION
1876 INTERCEPT_FUNCTION_VER(vswprintf, SANITIZER_NLDBL_VERSION);
1877 INTERCEPT_FUNCTION_VER(swprintf, SANITIZER_NLDBL_VERSION);
1878#else
1879 INTERCEPT_FUNCTION(vswprintf);
1880 INTERCEPT_FUNCTION(swprintf);
1881#endif
1882 INTERCEPT_FUNCTION(strftime);
1883 INTERCEPT_FUNCTION(strftime_l);
1884 MSAN_MAYBE_INTERCEPT___STRFTIME_L;
1885 INTERCEPT_FUNCTION(wcsftime);
1886 INTERCEPT_FUNCTION(wcsftime_l);
1887 MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
1888 INTERCEPT_FUNCTION(mbtowc);
1889 INTERCEPT_FUNCTION(mbrtowc);
1890 INTERCEPT_FUNCTION(wcslen);
1891 INTERCEPT_FUNCTION(wcsnlen);
1892 INTERCEPT_FUNCTION(wcschr);
1893 INTERCEPT_FUNCTION(wcscpy);
1894 INTERCEPT_FUNCTION(wcsncpy);
1895 INTERCEPT_FUNCTION(wcscmp);
1896 INTERCEPT_FUNCTION(getenv);
1897 INTERCEPT_FUNCTION(setenv);
1898 INTERCEPT_FUNCTION(putenv);
1899 INTERCEPT_FUNCTION(gettimeofday);
1900 MSAN_MAYBE_INTERCEPT_FCVT;
1901 MSAN_MAYBE_INTERCEPT_FSTAT;
1902 MSAN_MAYBE_INTERCEPT_FSTAT64;
1903 MSAN_MAYBE_INTERCEPT___FXSTAT;
1904 MSAN_MAYBE_INTERCEPT_FSTATAT;
1905 MSAN_MAYBE_INTERCEPT_FSTATAT64;
1906 MSAN_MAYBE_INTERCEPT___FXSTATAT;
1907 MSAN_MAYBE_INTERCEPT___FXSTAT64;
1908 MSAN_MAYBE_INTERCEPT___FXSTATAT64;
1909 INTERCEPT_FUNCTION(pipe);
1910 INTERCEPT_FUNCTION(pipe2);
1911 INTERCEPT_FUNCTION(socketpair);
1912 MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
1913 INTERCEPT_FUNCTION(getrlimit);
1914 MSAN_MAYBE_INTERCEPT___GETRLIMIT;
1915 MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
1916 MSAN_MAYBE_INTERCEPT_PRLIMIT;
1917 MSAN_MAYBE_INTERCEPT_PRLIMIT64;
1918 INTERCEPT_FUNCTION(gethostname);
1919 MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
1920 MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
1921 INTERCEPT_FUNCTION(strsignal);
1922 INTERCEPT_FUNCTION(dladdr);
1923 MSAN_MAYBE_INTERCEPT_DLADDR1;
1924 INTERCEPT_FUNCTION(dlerror);
1925 INTERCEPT_FUNCTION(dl_iterate_phdr);
1926 INTERCEPT_FUNCTION(getrusage);
1927#if defined(__mips__)
1928 INTERCEPT_FUNCTION_VER(pthread_create, "GLIBC_2.2");
1929#else
1930 INTERCEPT_FUNCTION(pthread_create);
1931#endif
1932 INTERCEPT_FUNCTION(pthread_join);
1933 INTERCEPT_FUNCTION(pthread_key_create);
1934#if SANITIZER_GLIBC
1935 INTERCEPT_FUNCTION(pthread_tryjoin_np);
1936 INTERCEPT_FUNCTION(pthread_timedjoin_np);
1937#endif
1938
1939#if SANITIZER_NETBSD
1940 INTERCEPT_FUNCTION(__libc_thr_keycreate);
1941#endif
1942
1943 INTERCEPT_FUNCTION(pthread_join);
1944 INTERCEPT_FUNCTION(tzset);
1945 INTERCEPT_FUNCTION(atexit);
1946 INTERCEPT_FUNCTION(__cxa_atexit);
1947 INTERCEPT_FUNCTION(shmat);
1948 MSAN_MAYBE_INTERCEPT_OPENPTY;
1949 MSAN_MAYBE_INTERCEPT_FORKPTY;
1950
1951 inited = 1;
1952}
1953} // namespace __msan
1954