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