Sergey Matveev | e86e35f | 2013-10-14 12:01:05 +0000 | [diff] [blame] | 1 | //===-- asan_posix.cc -----------------------------------------------------===// |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 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 AddressSanitizer, an address sanity checker. |
| 11 | // |
| 12 | // Posix-specific details. |
| 13 | //===----------------------------------------------------------------------===// |
Evgeniy Stepanov | 24e1372 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 14 | |
| 15 | #include "sanitizer_common/sanitizer_platform.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 16 | #if SANITIZER_POSIX |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 17 | |
| 18 | #include "asan_internal.h" |
| 19 | #include "asan_interceptors.h" |
Evgeniy Stepanov | c99f700 | 2012-05-23 15:21:50 +0000 | [diff] [blame] | 20 | #include "asan_mapping.h" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 21 | #include "asan_report.h" |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 22 | #include "asan_stack.h" |
Alexey Samsonov | 2221f55 | 2012-06-05 08:48:10 +0000 | [diff] [blame] | 23 | #include "sanitizer_common/sanitizer_libc.h" |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 24 | #include "sanitizer_common/sanitizer_posix.h" |
Alexey Samsonov | 6895adc | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 25 | #include "sanitizer_common/sanitizer_procmaps.h" |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 26 | |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 27 | #include <pthread.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 28 | #include <signal.h> |
Alexey Samsonov | b823e3c | 2012-02-22 14:07:06 +0000 | [diff] [blame] | 29 | #include <stdlib.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 30 | #include <sys/time.h> |
| 31 | #include <sys/resource.h> |
Kostya Serebryany | 0ecf5eb | 2012-01-09 23:11:26 +0000 | [diff] [blame] | 32 | #include <unistd.h> |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 33 | |
| 34 | namespace __asan { |
| 35 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 36 | void AsanOnSIGSEGV(int, void *siginfo, void *context) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 37 | ScopedDeadlySignal signal_scope(GetCurrentThread()); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 38 | int code = (int)((siginfo_t*)siginfo)->si_code; |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 39 | // Write the first message using the bullet-proof write. |
Alexey Samsonov | 47657ce | 2012-06-06 07:02:44 +0000 | [diff] [blame] | 40 | if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 41 | SignalContext sig = SignalContext::Create(siginfo, context); |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 42 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 43 | // Access at a reasonable offset above SP, or slightly below it (to account |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 44 | // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is |
| 45 | // probably a stack overflow. |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 46 | bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 47 | |
| 48 | #if __powerpc__ |
| 49 | // Large stack frames can be allocated with e.g. |
| 50 | // lis r0,-10000 |
| 51 | // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 |
| 52 | // If the store faults then sp will not have been updated, so test above |
| 53 | // will not work, becase the fault address will be more than just "slightly" |
| 54 | // below sp. |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 55 | if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { |
| 56 | u32 inst = *(unsigned *)sig.pc; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 57 | u32 ra = (inst >> 16) & 0x1F; |
| 58 | u32 opcd = inst >> 26; |
| 59 | u32 xo = (inst >> 1) & 0x3FF; |
| 60 | // Check for store-with-update to sp. The instructions we accept are: |
| 61 | // stbu rs,d(ra) stbux rs,ra,rb |
| 62 | // sthu rs,d(ra) sthux rs,ra,rb |
| 63 | // stwu rs,d(ra) stwux rs,ra,rb |
| 64 | // stdu rs,ds(ra) stdux rs,ra,rb |
| 65 | // where ra is r1 (the stack pointer). |
| 66 | if (ra == 1 && |
| 67 | (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || |
| 68 | (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) |
| 69 | IsStackAccess = true; |
| 70 | } |
| 71 | #endif // __powerpc__ |
| 72 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 73 | // We also check si_code to filter out SEGV caused by something else other |
| 74 | // then hitting the guard page or unmapped memory, like, for example, |
| 75 | // unaligned memory access. |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 76 | if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 77 | ReportStackOverflow(sig); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 78 | else |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 79 | ReportSIGSEGV("SEGV", sig); |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 80 | } |
| 81 | |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 82 | // ---------------------- TSD ---------------- {{{1 |
| 83 | |
| 84 | static pthread_key_t tsd_key; |
| 85 | static bool tsd_key_inited = false; |
Kostya Serebryany | f58f998 | 2012-02-07 00:27:15 +0000 | [diff] [blame] | 86 | void AsanTSDInit(void (*destructor)(void *tsd)) { |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 87 | CHECK(!tsd_key_inited); |
| 88 | tsd_key_inited = true; |
Kostya Serebryany | a27bdf7 | 2013-04-05 14:40:25 +0000 | [diff] [blame] | 89 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); |
Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | void *AsanTSDGet() { |
| 93 | CHECK(tsd_key_inited); |
| 94 | return pthread_getspecific(tsd_key); |
| 95 | } |
| 96 | |
| 97 | void AsanTSDSet(void *tsd) { |
| 98 | CHECK(tsd_key_inited); |
| 99 | pthread_setspecific(tsd_key, tsd); |
| 100 | } |
| 101 | |
Sergey Matveev | e86e35f | 2013-10-14 12:01:05 +0000 | [diff] [blame] | 102 | void PlatformTSDDtor(void *tsd) { |
| 103 | AsanThreadContext *context = (AsanThreadContext*)tsd; |
| 104 | if (context->destructor_iterations > 1) { |
| 105 | context->destructor_iterations--; |
| 106 | CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); |
| 107 | return; |
| 108 | } |
| 109 | AsanThread::TSDDtor(tsd); |
| 110 | } |
Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 111 | } // namespace __asan |
| 112 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 113 | #endif // SANITIZER_POSIX |