diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2014-11-06 22:49:13 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2014-11-06 22:49:13 +0000 |
commit | 8ef50bf3d1c287b5013c3168de77a462dfce3495 (patch) | |
tree | 3467f3372c1195b1546172d89af2205a50b1866d /lib/asan/asan_interceptors.cc | |
parent | 11023dc647fd8f41418da90d59db138400d0f334 (diff) |
Notes
Diffstat (limited to 'lib/asan/asan_interceptors.cc')
-rw-r--r-- | lib/asan/asan_interceptors.cc | 219 |
1 files changed, 117 insertions, 102 deletions
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 7e7deea29634f..a25827b6b9aef 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -53,7 +53,7 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { } while (0) #define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false) -#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true); +#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true) // Behavior of functions like "memcpy" or "strcpy" is undefined // if memory intervals overlap. We report error in this case. @@ -94,9 +94,9 @@ void SetThreadName(const char *name) { asanThreadRegistry().SetThreadName(t->tid(), name); } -static void DisableStrictInitOrderChecker() { - if (flags()->strict_init_order) - flags()->check_initialization_order = false; +int OnExit() { + // FIXME: ask frontend whether we need to return failure. + return 0; } } // namespace __asan @@ -104,26 +104,69 @@ static void DisableStrictInitOrderChecker() { // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) + +#if !SANITIZER_MAC +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \ + common_flags()->verbosity > 0) \ + Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ + } while (0) +#else +// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. +#define ASAN_INTERCEPT_FUNC(name) +#endif // SANITIZER_MAC + +#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) +#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \ + do { \ + } while (false) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ ASAN_WRITE_RANGE(ptr, size) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size) -#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - do { \ - if (asan_init_is_running) \ - return REAL(func)(__VA_ARGS__); \ - ctx = 0; \ - (void)ctx; \ - ENSURE_ASAN_INITED(); \ +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + do { \ + if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \ + ctx = 0; \ + (void) ctx; \ + if (SANITIZER_MAC && !asan_inited) return REAL(func)(__VA_ARGS__); \ + ENSURE_ASAN_INITED(); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + do { \ } while (false) -#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false) -#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) +// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) +// But asan does not remember UserId's for threads (pthread_t); +// and remembers all ever existed threads, so the linear search by UserId +// can be slow. +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #include "sanitizer_common/sanitizer_common_interceptors.inc" #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s) #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s) -#define COMMON_SYSCALL_POST_READ_RANGE(p, s) -#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) +#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) +#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { @@ -133,16 +176,16 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { } #if ASAN_INTERCEPT_PTHREAD_CREATE -extern "C" int pthread_attr_getdetachstate(void *attr, int *v); - INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { + EnsureMainThreadIDIsCorrect(); // Strict init-order checking in thread-hostile. - DisableStrictInitOrderChecker(); + if (flags()->strict_init_order) + StopInitOrderChecking(); GET_STACK_TRACE_THREAD; int detached = 0; if (attr != 0) - pthread_attr_getdetachstate(attr, &detached); + REAL(pthread_attr_getdetachstate)(attr, &detached); u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg); @@ -170,7 +213,7 @@ INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, #elif SANITIZER_POSIX // We need to have defined REAL(sigaction) on posix systems. DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act, - struct sigaction *oldact); + struct sigaction *oldact) #endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION #if ASAN_INTERCEPT_SWAPCONTEXT @@ -240,13 +283,15 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { // Since asan maps 16T of RAM, mlock is completely unfriendly to asan. // All functions return 0 (success). static void MlockIsUnsupported() { - static bool printed = 0; + static bool printed = false; if (printed) return; printed = true; - Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n"); + if (common_flags()->verbosity > 0) { + Printf("INFO: AddressSanitizer ignores " + "mlock/mlockall/munlock/munlockall\n"); + } } -extern "C" { INTERCEPTOR(int, mlock, const void *addr, uptr len) { MlockIsUnsupported(); return 0; @@ -266,7 +311,6 @@ INTERCEPTOR(int, munlockall, void) { MlockIsUnsupported(); return 0; } -} // extern "C" static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; @@ -300,7 +344,23 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { return REAL(memcmp(a1, a2, size)); } +#define MEMMOVE_BODY { \ + if (!asan_inited) return internal_memmove(to, from, size); \ + if (asan_init_is_running) { \ + return REAL(memmove)(to, from, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_READ_RANGE(from, size); \ + ASAN_WRITE_RANGE(to, size); \ + } \ + return internal_memmove(to, from, size); \ +} + +INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY + INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { +#if !SANITIZER_MAC if (!asan_inited) return internal_memcpy(to, from, size); // memcpy is called during __asan_init() from the internals // of printf(...). @@ -317,24 +377,19 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { ASAN_READ_RANGE(from, size); ASAN_WRITE_RANGE(to, size); } - // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8. + // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so + // calling REAL(memcpy) here leads to infinite recursion. // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116. return internal_memcpy(to, from, size); -} - -INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) { - if (!asan_inited) return internal_memmove(to, from, size); - if (asan_init_is_running) { - return REAL(memmove)(to, from, size); - } - ENSURE_ASAN_INITED(); - if (flags()->replace_intrin) { - ASAN_READ_RANGE(from, size); - ASAN_WRITE_RANGE(to, size); - } - // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8. - // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116. - return internal_memmove(to, from, size); +#else + // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced + // with WRAP(memcpy). As a result, false positives are reported for memmove() + // calls. If we just disable error reporting with + // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with + // internal_memcpy(), which may lead to crashes, see + // http://llvm.org/bugs/show_bug.cgi?id=16362. + MEMMOVE_BODY +#endif // !SANITIZER_MAC } INTERCEPTOR(void*, memset, void *block, int c, uptr size) { @@ -375,7 +430,7 @@ INTERCEPTOR(char*, index, const char *string, int c) DECLARE_REAL(char*, index, const char *string, int c) OVERRIDE_FUNCTION(index, strchr); # else -DEFINE_REAL(char*, index, const char *string, int c); +DEFINE_REAL(char*, index, const char *string, int c) # endif # endif #endif // ASAN_INTERCEPT_INDEX @@ -418,24 +473,6 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { return REAL(strncat)(to, from, size); } -INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { - if (!asan_inited) return internal_strcmp(s1, s2); - if (asan_init_is_running) { - return REAL(strcmp)(s1, s2); - } - ENSURE_ASAN_INITED(); - unsigned char c1, c2; - uptr i; - for (i = 0; ; i++) { - c1 = (unsigned char)s1[i]; - c2 = (unsigned char)s2[i]; - if (c1 != c2 || c1 == '\0') break; - } - ASAN_READ_RANGE(s1, i + 1); - ASAN_READ_RANGE(s2, i + 1); - return CharCmp(c1, c2); -} - INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT #if SANITIZER_MAC if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT @@ -457,21 +494,16 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT #if ASAN_INTERCEPT_STRDUP INTERCEPTOR(char*, strdup, const char *s) { -#if SANITIZER_MAC - // FIXME: because internal_strdup() uses InternalAlloc(), which currently - // just calls malloc() on Mac, we can't use internal_strdup() with the - // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc - // starts using mmap() instead. - // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123. - if (!asan_inited) return REAL(strdup)(s); -#endif if (!asan_inited) return internal_strdup(s); ENSURE_ASAN_INITED(); + uptr length = REAL(strlen)(s); if (flags()->replace_str) { - uptr length = REAL(strlen)(s); ASAN_READ_RANGE(s, length + 1); } - return REAL(strdup)(s); + GET_STACK_TRACE_MALLOC; + void *new_mem = asan_malloc(length + 1, &stack); + REAL(memcpy)(new_mem, s, length + 1); + return reinterpret_cast<char*>(new_mem); } #endif @@ -490,24 +522,13 @@ INTERCEPTOR(uptr, strlen, const char *s) { return length; } -INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { - if (!asan_inited) return internal_strncmp(s1, s2, size); - // strncmp is called from malloc_default_purgeable_zone() - // in __asan::ReplaceSystemAlloc() on Mac. - if (asan_init_is_running) { - return REAL(strncmp)(s1, s2, size); +INTERCEPTOR(uptr, wcslen, const wchar_t *s) { + uptr length = REAL(wcslen)(s); + if (!asan_init_is_running) { + ENSURE_ASAN_INITED(); + ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t)); } - ENSURE_ASAN_INITED(); - unsigned char c1 = 0, c2 = 0; - uptr i; - for (i = 0; i < size; i++) { - c1 = (unsigned char)s1[i]; - c2 = (unsigned char)s2[i]; - if (c1 != c2 || c1 == '\0') break; - } - ASAN_READ_RANGE(s1, Min(i + 1, size)); - ASAN_READ_RANGE(s2, Min(i + 1, size)); - return CharCmp(c1, c2); + return length; } INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { @@ -644,6 +665,9 @@ static void AtCxaAtexit(void *unused) { #if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { +#if SANITIZER_MAC + if (!asan_inited) return REAL(__cxa_atexit)(func, arg, dso_handle); +#endif ENSURE_ASAN_INITED(); int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, 0, 0); @@ -651,26 +675,22 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, } #endif // ASAN_INTERCEPT___CXA_ATEXIT -#define ASAN_INTERCEPT_FUNC(name) do { \ - if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \ - Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ - } while (0) - #if SANITIZER_WINDOWS INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, DWORD (__stdcall *start_routine)(void*), void* arg, - DWORD flags, void* tid) { + DWORD thr_flags, void* tid) { // Strict init-order checking in thread-hostile. - DisableStrictInitOrderChecker(); + if (flags()->strict_init_order) + StopInitOrderChecking(); GET_STACK_TRACE_THREAD; u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg); CreateThreadContextArgs args = { t, &stack }; - int detached = 0; // FIXME: how can we determine it on Windows? + bool detached = false; // FIXME: how can we determine it on Windows? asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args); return REAL(CreateThread)(security, stack_size, - asan_thread_start, t, flags, tid); + asan_thread_start, t, thr_flags, tid); } namespace __asan { @@ -687,9 +707,6 @@ void InitializeAsanInterceptors() { static bool was_called_once; CHECK(was_called_once == false); was_called_once = true; -#if SANITIZER_MAC - return; -#else SANITIZER_COMMON_INTERCEPTORS_INIT; // Intercept mem* functions. @@ -703,11 +720,10 @@ void InitializeAsanInterceptors() { // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT ASAN_INTERCEPT_FUNC(strchr); - ASAN_INTERCEPT_FUNC(strcmp); ASAN_INTERCEPT_FUNC(strcpy); // NOLINT ASAN_INTERCEPT_FUNC(strlen); + ASAN_INTERCEPT_FUNC(wcslen); ASAN_INTERCEPT_FUNC(strncat); - ASAN_INTERCEPT_FUNC(strncmp); ASAN_INTERCEPT_FUNC(strncpy); #if ASAN_INTERCEPT_STRDUP ASAN_INTERCEPT_FUNC(strdup); @@ -771,10 +787,9 @@ void InitializeAsanInterceptors() { InitializeWindowsInterceptors(); #endif - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Report("AddressSanitizer: libc interceptors initialized\n"); } -#endif // SANITIZER_MAC } } // namespace __asan |