Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 1 | //===-- asan_linux.cc -----------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of AddressSanitizer, an address sanity checker. |
| 11 | // |
| 12 | // Linux-specific details. |
| 13 | //===----------------------------------------------------------------------===// |
Evgeniy Stepanov | 0af6723 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 14 | |
| 15 | #include "sanitizer_common/sanitizer_platform.h" |
Kamil Rytarowski | 271018d | 2017-12-14 20:14:29 +0000 | [diff] [blame] | 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ |
| 17 | SANITIZER_SOLARIS |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 18 | |
Kostya Serebryany | cd271f5 | 2012-01-05 00:44:33 +0000 | [diff] [blame] | 19 | #include "asan_interceptors.h" |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 20 | #include "asan_internal.h" |
Evgeniy Stepanov | 8e7018d | 2017-11-20 17:41:57 +0000 | [diff] [blame] | 21 | #include "asan_premap_shadow.h" |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 22 | #include "asan_thread.h" |
Alexey Samsonov | 3d9adc0 | 2014-03-04 13:12:25 +0000 | [diff] [blame] | 23 | #include "sanitizer_common/sanitizer_flags.h" |
Viktor Kutuzov | 1f386f0 | 2014-06-15 13:56:28 +0000 | [diff] [blame] | 24 | #include "sanitizer_common/sanitizer_freebsd.h" |
Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 25 | #include "sanitizer_common/sanitizer_libc.h" |
Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 26 | #include "sanitizer_common/sanitizer_procmaps.h" |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 27 | |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 28 | #include <sys/time.h> |
| 29 | #include <sys/resource.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 30 | #include <sys/mman.h> |
| 31 | #include <sys/syscall.h> |
Kostya Serebryany | 6c4bd80 | 2011-12-28 22:58:01 +0000 | [diff] [blame] | 32 | #include <sys/types.h> |
Evgeniy Stepanov | e5c34ac | 2014-06-06 10:57:21 +0000 | [diff] [blame] | 33 | #include <dlfcn.h> |
Kostya Serebryany | 6c4bd80 | 2011-12-28 22:58:01 +0000 | [diff] [blame] | 34 | #include <fcntl.h> |
Yvan Roux | cae4970 | 2018-02-07 18:27:25 +0000 | [diff] [blame] | 35 | #include <limits.h> |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 36 | #include <pthread.h> |
Kostya Serebryany | cd271f5 | 2012-01-05 00:44:33 +0000 | [diff] [blame] | 37 | #include <stdio.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 38 | #include <unistd.h> |
Evgeniy Stepanov | 84c44a8 | 2012-01-19 11:34:18 +0000 | [diff] [blame] | 39 | #include <unwind.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 40 | |
Viktor Kutuzov | 82185a2 | 2014-04-09 13:37:19 +0000 | [diff] [blame] | 41 | #if SANITIZER_FREEBSD |
| 42 | #include <sys/link_elf.h> |
| 43 | #endif |
| 44 | |
Kamil Rytarowski | 271018d | 2017-12-14 20:14:29 +0000 | [diff] [blame] | 45 | #if SANITIZER_SOLARIS |
| 46 | #include <link.h> |
| 47 | #endif |
| 48 | |
| 49 | #if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS |
Evgeniy Stepanov | 6db97e8 | 2014-02-10 13:34:43 +0000 | [diff] [blame] | 50 | #include <ucontext.h> |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 51 | extern "C" void* _DYNAMIC; |
Kamil Rytarowski | 4ad374e | 2017-08-10 18:51:51 +0000 | [diff] [blame] | 52 | #elif SANITIZER_NETBSD |
| 53 | #include <link_elf.h> |
| 54 | #include <ucontext.h> |
| 55 | extern Elf_Dyn _DYNAMIC; |
Evgeniy Stepanov | 6db97e8 | 2014-02-10 13:34:43 +0000 | [diff] [blame] | 56 | #else |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 57 | #include <sys/ucontext.h> |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 58 | #include <link.h> |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 59 | #endif |
| 60 | |
Viktor Kutuzov | 1f386f0 | 2014-06-15 13:56:28 +0000 | [diff] [blame] | 61 | // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in |
| 62 | // 32-bit mode. |
| 63 | #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ |
| 64 | __FreeBSD_version <= 902001 // v9.2 |
| 65 | #define ucontext_t xucontext_t |
Viktor Kutuzov | ebb00e1 | 2014-03-12 12:44:36 +0000 | [diff] [blame] | 66 | #endif |
| 67 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 68 | typedef enum { |
| 69 | ASAN_RT_VERSION_UNDEFINED = 0, |
| 70 | ASAN_RT_VERSION_DYNAMIC, |
| 71 | ASAN_RT_VERSION_STATIC, |
| 72 | } asan_rt_version_t; |
| 73 | |
| 74 | // FIXME: perhaps also store abi version here? |
| 75 | extern "C" { |
| 76 | SANITIZER_INTERFACE_ATTRIBUTE |
| 77 | asan_rt_version_t __asan_rt_version; |
| 78 | } |
Evgeniy Stepanov | 4cc2631 | 2012-03-26 09:48:41 +0000 | [diff] [blame] | 79 | |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 80 | namespace __asan { |
| 81 | |
Timur Iskhodzhanov | 817ac72 | 2015-03-16 14:22:53 +0000 | [diff] [blame] | 82 | void InitializePlatformInterceptors() {} |
Etienne Bergeron | 1128db8 | 2016-07-11 21:40:59 +0000 | [diff] [blame] | 83 | void InitializePlatformExceptionHandlers() {} |
Etienne Bergeron | fc68c2c | 2017-02-21 16:09:38 +0000 | [diff] [blame] | 84 | bool IsSystemHeapAddress (uptr addr) { return false; } |
Timur Iskhodzhanov | 817ac72 | 2015-03-16 14:22:53 +0000 | [diff] [blame] | 85 | |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 86 | void *AsanDoesNotSupportStaticLinkage() { |
| 87 | // This will fail to link with -static. |
Kostya Serebryany | 3b7fb10 | 2012-01-05 23:50:34 +0000 | [diff] [blame] | 88 | return &_DYNAMIC; // defined in link.h |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 89 | } |
| 90 | |
Evgeniy Stepanov | 8e7018d | 2017-11-20 17:41:57 +0000 | [diff] [blame] | 91 | static void UnmapFromTo(uptr from, uptr to) { |
| 92 | CHECK(to >= from); |
| 93 | if (to == from) return; |
| 94 | uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); |
| 95 | if (UNLIKELY(internal_iserror(res))) { |
| 96 | Report( |
| 97 | "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address " |
| 98 | "%p\n", |
| 99 | to - from, to - from, from); |
| 100 | CHECK("unable to unmap" && 0); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | #if ASAN_PREMAP_SHADOW |
| 105 | uptr FindPremappedShadowStart() { |
| 106 | uptr granularity = GetMmapGranularity(); |
| 107 | uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); |
| 108 | uptr premap_shadow_size = PremapShadowSize(); |
| 109 | uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); |
| 110 | // We may have mapped too much. Release extra memory. |
| 111 | UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); |
| 112 | return shadow_start; |
| 113 | } |
| 114 | #endif |
| 115 | |
Evgeniy Stepanov | 989299c | 2017-11-10 22:27:48 +0000 | [diff] [blame] | 116 | uptr FindDynamicShadowStart() { |
Evgeniy Stepanov | 8e7018d | 2017-11-20 17:41:57 +0000 | [diff] [blame] | 117 | #if ASAN_PREMAP_SHADOW |
| 118 | if (!PremapShadowFailed()) |
| 119 | return FindPremappedShadowStart(); |
| 120 | #endif |
| 121 | |
| 122 | uptr granularity = GetMmapGranularity(); |
| 123 | uptr alignment = granularity * 8; |
| 124 | uptr left_padding = granularity; |
| 125 | uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); |
| 126 | uptr map_size = shadow_size + left_padding + alignment; |
| 127 | |
| 128 | uptr map_start = (uptr)MmapNoAccess(map_size); |
| 129 | CHECK_NE(map_start, ~(uptr)0); |
| 130 | |
| 131 | uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); |
| 132 | UnmapFromTo(map_start, shadow_start - left_padding); |
| 133 | UnmapFromTo(shadow_start + shadow_size, map_start + map_size); |
| 134 | |
| 135 | return shadow_start; |
Evgeniy Stepanov | 989299c | 2017-11-10 22:27:48 +0000 | [diff] [blame] | 136 | } |
Kuba Mracek | c1e903b | 2017-07-12 23:29:21 +0000 | [diff] [blame] | 137 | |
Ryan Govostes | dc91fe5 | 2016-03-28 20:28:17 +0000 | [diff] [blame] | 138 | void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { |
| 139 | UNIMPLEMENTED(); |
| 140 | } |
| 141 | |
Alexey Samsonov | 2c66a22 | 2014-04-02 09:36:36 +0000 | [diff] [blame] | 142 | #if SANITIZER_ANDROID |
| 143 | // FIXME: should we do anything for Android? |
| 144 | void AsanCheckDynamicRTPrereqs() {} |
| 145 | void AsanCheckIncompatibleRT() {} |
| 146 | #else |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 147 | static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, |
| 148 | void *data) { |
Kamil Rytarowski | 271018d | 2017-12-14 20:14:29 +0000 | [diff] [blame] | 149 | VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", |
| 150 | info->dlpi_name, info->dlpi_addr); |
| 151 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 152 | // Continue until the first dynamic library is found |
| 153 | if (!info->dlpi_name || info->dlpi_name[0] == 0) |
| 154 | return 0; |
| 155 | |
Kostya Serebryany | 5181dd3 | 2014-06-02 10:39:40 +0000 | [diff] [blame] | 156 | // Ignore vDSO |
| 157 | if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) |
| 158 | return 0; |
| 159 | |
Dimitry Andric | 95af9e6 | 2017-10-24 19:45:59 +0000 | [diff] [blame] | 160 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD |
Kamil Rytarowski | 4ad374e | 2017-08-10 18:51:51 +0000 | [diff] [blame] | 161 | // Ignore first entry (the main program) |
| 162 | char **p = (char **)data; |
| 163 | if (!(*p)) { |
| 164 | *p = (char *)-1; |
| 165 | return 0; |
| 166 | } |
| 167 | #endif |
| 168 | |
Kamil Rytarowski | 271018d | 2017-12-14 20:14:29 +0000 | [diff] [blame] | 169 | #if SANITIZER_SOLARIS |
| 170 | // Ignore executable on Solaris |
| 171 | if (info->dlpi_addr == 0) |
| 172 | return 0; |
| 173 | #endif |
| 174 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 175 | *(const char **)data = info->dlpi_name; |
| 176 | return 1; |
| 177 | } |
| 178 | |
| 179 | static bool IsDynamicRTName(const char *libname) { |
| 180 | return internal_strstr(libname, "libclang_rt.asan") || |
| 181 | internal_strstr(libname, "libasan.so"); |
| 182 | } |
| 183 | |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame] | 184 | static void ReportIncompatibleRT() { |
| 185 | Report("Your application is linked against incompatible ASan runtimes.\n"); |
| 186 | Die(); |
| 187 | } |
| 188 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 189 | void AsanCheckDynamicRTPrereqs() { |
Maxim Ostapenko | f73b73d | 2017-03-31 06:36:37 +0000 | [diff] [blame] | 190 | if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) |
Yury Gribov | c5243f0 | 2015-06-04 07:23:09 +0000 | [diff] [blame] | 191 | return; |
| 192 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 193 | // Ensure that dynamic RT is the first DSO in the list |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 194 | const char *first_dso_name = nullptr; |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 195 | dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); |
| 196 | if (first_dso_name && !IsDynamicRTName(first_dso_name)) { |
| 197 | Report("ASan runtime does not come first in initial library list; " |
| 198 | "you should either link runtime to your application or " |
| 199 | "manually preload it with LD_PRELOAD.\n"); |
| 200 | Die(); |
| 201 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | void AsanCheckIncompatibleRT() { |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 205 | if (ASAN_DYNAMIC) { |
| 206 | if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { |
| 207 | __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; |
| 208 | } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame] | 209 | ReportIncompatibleRT(); |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 210 | } |
| 211 | } else { |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame] | 212 | if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { |
| 213 | // Ensure that dynamic runtime is not present. We should detect it |
| 214 | // as early as possible, otherwise ASan interceptors could bind to |
| 215 | // the functions in dynamic ASan runtime instead of the functions in |
| 216 | // system libraries, causing crashes later in ASan initialization. |
| 217 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); |
Yvan Roux | cae4970 | 2018-02-07 18:27:25 +0000 | [diff] [blame] | 218 | char filename[PATH_MAX]; |
Francis Ricci | f6a4329 | 2017-07-11 18:54:00 +0000 | [diff] [blame] | 219 | MemoryMappedSegment segment(filename, sizeof(filename)); |
| 220 | while (proc_maps.Next(&segment)) { |
| 221 | if (IsDynamicRTName(segment.filename)) { |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame] | 222 | Report("Your application is linked against " |
| 223 | "incompatible ASan runtimes.\n"); |
| 224 | Die(); |
| 225 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 226 | } |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame] | 227 | __asan_rt_version = ASAN_RT_VERSION_STATIC; |
| 228 | } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { |
| 229 | ReportIncompatibleRT(); |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 230 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 231 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 232 | } |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 233 | #endif // SANITIZER_ANDROID |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 234 | |
Evgeniy Stepanov | d3b5660 | 2013-03-19 13:54:41 +0000 | [diff] [blame] | 235 | #if !SANITIZER_ANDROID |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 236 | void ReadContextStack(void *context, uptr *stack, uptr *ssize) { |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 237 | ucontext_t *ucp = (ucontext_t*)context; |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 238 | *stack = (uptr)ucp->uc_stack.ss_sp; |
| 239 | *ssize = ucp->uc_stack.ss_size; |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 240 | } |
| 241 | #else |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 242 | void ReadContextStack(void *context, uptr *stack, uptr *ssize) { |
Alexey Samsonov | 9585613 | 2013-01-18 09:20:06 +0000 | [diff] [blame] | 243 | UNIMPLEMENTED(); |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 244 | } |
| 245 | #endif |
| 246 | |
Evgeniy Stepanov | e5c34ac | 2014-06-06 10:57:21 +0000 | [diff] [blame] | 247 | void *AsanDlSymNext(const char *sym) { |
| 248 | return dlsym(RTLD_NEXT, sym); |
| 249 | } |
| 250 | |
Vedant Kumar | 59ba7b8 | 2015-10-01 00:22:21 +0000 | [diff] [blame] | 251 | } // namespace __asan |
Kostya Serebryany | 5dfa4da | 2011-12-01 21:40:52 +0000 | [diff] [blame] | 252 | |
Kamil Rytarowski | 271018d | 2017-12-14 20:14:29 +0000 | [diff] [blame] | 253 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || |
| 254 | // SANITIZER_SOLARIS |