From cba008e9c50388db568123bc5b887aed43131211 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 19 Feb 2014 13:40:41 +0000 Subject: [PATCH] [asan] A different way of detectinb stack overflow. Instead of checking stack limits that are not well defined for the main thread, we rely on siginfo::si_code and distance from SP. llvm-svn: 201673 --- compiler-rt/lib/asan/asan_posix.cc | 14 +++++++- compiler-rt/lib/asan/asan_report.cc | 35 ++++++++----------- compiler-rt/lib/asan/asan_report.h | 2 ++ .../sanitizer_platform_limits_posix.cc | 7 ++-- .../sanitizer_platform_limits_posix.h | 3 ++ 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/compiler-rt/lib/asan/asan_posix.cc b/compiler-rt/lib/asan/asan_posix.cc index 05064f4598ef..6322d82229b9 100644 --- a/compiler-rt/lib/asan/asan_posix.cc +++ b/compiler-rt/lib/asan/asan_posix.cc @@ -34,11 +34,23 @@ namespace __asan { void AsanOnSIGSEGV(int, void *siginfo, void *context) { uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; + int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using the bullet-proof write. if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); uptr pc, sp, bp; GetPcSpBp(context, &pc, &sp, &bp); - ReportSIGSEGV(pc, sp, bp, context, addr); + + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 redzone, ARM push of multiple registers, etc) is probably a + // stack overflow. + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + if (addr + 128 > sp && addr < sp + 0xFFFF && + (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) + ReportStackOverflow(pc, sp, bp, context, addr); + else + ReportSIGSEGV(pc, sp, bp, context, addr); } // ---------------------- TSD ---------------- {{{1 diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 4937773adfa5..1af4f7e8a50a 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -568,40 +568,35 @@ class ScopedInErrorReport { } }; -static bool IsStackOverflow(uptr addr, uptr sp) { - uptr stack_frame_bottom = sp; - // x86_64 stack redzone: leaf functions can access up to 128 bytes below SP. - // ARM has push-multiple instruction that stores up to 64(?) bytes below SP. - stack_frame_bottom -= 128; - - // Access below SP (minus redzone) is probably something else (like stack of - // another thread). - if (addr < stack_frame_bottom) - return false; - - AsanThread *t = GetCurrentThread(); - // Anything below stack_bottom, but not too far away is a stack overflow. - // Bottom 4k may be a guard page. Treat it as stack-overflow as well. - return addr < t->stack_bottom() + GetPageSizeCached() && - addr > t->stack_bottom() - 0xFFFF; +void ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr) { + ScopedInErrorReport in_report; + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: stack-overflow on address %p" + " (pc %p sp %p bp %p T%d)\n", + (void *)addr, (void *)pc, (void *)sp, (void *)bp, + GetCurrentTidOrInvalid()); + Printf("%s", d.EndWarning()); + GET_STACK_TRACE_SIGNAL(pc, bp, context); + stack.Print(); + ReportErrorSummary("stack-overflow", &stack); } void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); - bool stack_overflow = IsStackOverflow(addr, sp); Report( - "ERROR: AddressSanitizer: %s %p" + "ERROR: AddressSanitizer: SEGV on unknown address %p" " (pc %p sp %p bp %p T%d)\n", - stack_overflow ? "stack-overflow on address" : "SEGV on unknown address", (void *)addr, (void *)pc, (void *)sp, (void *)bp, GetCurrentTidOrInvalid()); Printf("%s", d.EndWarning()); GET_STACK_TRACE_SIGNAL(pc, bp, context); stack.Print(); Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary(stack_overflow ? "stack-overflow" : "SEGV", &stack); + ReportErrorSummary("SEGV", &stack); } void ReportDoubleFree(uptr addr, StackTrace *free_stack) { diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h index c4e8611d2354..84111b163ad7 100644 --- a/compiler-rt/lib/asan/asan_report.h +++ b/compiler-rt/lib/asan/asan_report.h @@ -32,6 +32,8 @@ void DescribeAddress(uptr addr, uptr access_size); void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. +void NORETURN + ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr); void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr); void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 83a9d7672cd2..9e776ce94a40 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -772,10 +772,13 @@ namespace __sanitizer { const int errno_EINVAL = EINVAL; // EOWNERDEAD is not present in some older platforms. #if defined(EOWNERDEAD) - extern const int errno_EOWNERDEAD = EOWNERDEAD; + const int errno_EOWNERDEAD = EOWNERDEAD; #else - extern const int errno_EOWNERDEAD = -1; + const int errno_EOWNERDEAD = -1; #endif + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; } // namespace __sanitizer COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index b82b4cfb1665..a8cc75dddf06 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -1054,6 +1054,9 @@ namespace __sanitizer { extern const int errno_EINVAL; extern const int errno_EOWNERDEAD; + + extern const int si_SEGV_MAPERR; + extern const int si_SEGV_ACCERR; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ -- GitLab