1 //===-- asan_linux.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of AddressSanitizer, an address sanity checker. 10 // 11 // Linux-specific details. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_platform.h" 15 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 16 SANITIZER_SOLARIS 17 18 # include <dlfcn.h> 19 # include <fcntl.h> 20 # include <limits.h> 21 # include <pthread.h> 22 # include <stdio.h> 23 # include <sys/mman.h> 24 # include <sys/resource.h> 25 # include <sys/syscall.h> 26 # include <sys/time.h> 27 # include <sys/types.h> 28 # include <unistd.h> 29 # include <unwind.h> 30 31 # include "asan_interceptors.h" 32 # include "asan_internal.h" 33 # include "asan_premap_shadow.h" 34 # include "asan_thread.h" 35 # include "sanitizer_common/sanitizer_flags.h" 36 # include "sanitizer_common/sanitizer_hash.h" 37 # include "sanitizer_common/sanitizer_libc.h" 38 # include "sanitizer_common/sanitizer_procmaps.h" 39 40 # if SANITIZER_FREEBSD 41 # include <sys/link_elf.h> 42 # endif 43 44 # if SANITIZER_SOLARIS 45 # include <link.h> 46 # endif 47 48 # if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS 49 # include <ucontext.h> 50 extern "C" void *_DYNAMIC; 51 # elif SANITIZER_NETBSD 52 # include <link_elf.h> 53 # include <ucontext.h> 54 extern Elf_Dyn _DYNAMIC; 55 # else 56 # include <link.h> 57 # include <sys/ucontext.h> 58 extern ElfW(Dyn) _DYNAMIC[]; 59 # endif 60 61 typedef enum { 62 ASAN_RT_VERSION_UNDEFINED = 0, 63 ASAN_RT_VERSION_DYNAMIC, 64 ASAN_RT_VERSION_STATIC, 65 } asan_rt_version_t; 66 67 // FIXME: perhaps also store abi version here? 68 extern "C" { 69 SANITIZER_INTERFACE_ATTRIBUTE 70 asan_rt_version_t __asan_rt_version; 71 } 72 73 namespace __asan { 74 75 void InitializePlatformInterceptors() {} 76 void InitializePlatformExceptionHandlers() {} 77 bool IsSystemHeapAddress(uptr addr) { return false; } 78 79 void *AsanDoesNotSupportStaticLinkage() { 80 // This will fail to link with -static. 81 return &_DYNAMIC; 82 } 83 84 # if ASAN_PREMAP_SHADOW 85 uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 86 uptr granularity = GetMmapGranularity(); 87 uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 88 uptr premap_shadow_size = PremapShadowSize(); 89 uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 90 // We may have mapped too much. Release extra memory. 91 UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 92 return shadow_start; 93 } 94 # endif 95 96 uptr FindDynamicShadowStart() { 97 uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); 98 # if ASAN_PREMAP_SHADOW 99 if (!PremapShadowFailed()) 100 return FindPremappedShadowStart(shadow_size_bytes); 101 # endif 102 103 return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, 104 /*min_shadow_base_alignment*/ 0, kHighMemEnd); 105 } 106 107 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 108 UNIMPLEMENTED(); 109 } 110 111 void FlushUnneededASanShadowMemory(uptr p, uptr size) { 112 // Since asan's mapping is compacting, the shadow chunk may be 113 // not page-aligned, so we only flush the page-aligned portion. 114 ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 115 } 116 117 # if SANITIZER_ANDROID 118 // FIXME: should we do anything for Android? 119 void AsanCheckDynamicRTPrereqs() {} 120 void AsanCheckIncompatibleRT() {} 121 # else 122 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 123 void *data) { 124 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, 125 (void *)info->dlpi_addr); 126 127 const char **name = (const char **)data; 128 129 // Ignore first entry (the main program) 130 if (!*name) { 131 *name = ""; 132 return 0; 133 } 134 135 # if SANITIZER_LINUX 136 // Ignore vDSO. glibc versions earlier than 2.15 (and some patched 137 // by distributors) return an empty name for the vDSO entry, so 138 // detect this as well. 139 if (!info->dlpi_name[0] || 140 internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 141 return 0; 142 # endif 143 # if SANITIZER_FREEBSD 144 // Ignore vDSO. 145 if (internal_strcmp(info->dlpi_name, "[vdso]") == 0) 146 return 0; 147 # endif 148 149 *name = info->dlpi_name; 150 return 1; 151 } 152 153 static bool IsDynamicRTName(const char *libname) { 154 return internal_strstr(libname, "libclang_rt.asan") || 155 internal_strstr(libname, "libasan.so"); 156 } 157 158 static void ReportIncompatibleRT() { 159 Report("Your application is linked against incompatible ASan runtimes.\n"); 160 Die(); 161 } 162 163 void AsanCheckDynamicRTPrereqs() { 164 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 165 return; 166 167 // Ensure that dynamic RT is the first DSO in the list 168 const char *first_dso_name = nullptr; 169 dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 170 if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) { 171 Report( 172 "ASan runtime does not come first in initial library list; " 173 "you should either link runtime to your application or " 174 "manually preload it with LD_PRELOAD.\n"); 175 Die(); 176 } 177 } 178 179 void AsanCheckIncompatibleRT() { 180 if (ASAN_DYNAMIC) { 181 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 182 __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 183 } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 184 ReportIncompatibleRT(); 185 } 186 } else { 187 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 188 // Ensure that dynamic runtime is not present. We should detect it 189 // as early as possible, otherwise ASan interceptors could bind to 190 // the functions in dynamic ASan runtime instead of the functions in 191 // system libraries, causing crashes later in ASan initialization. 192 MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 193 char filename[PATH_MAX]; 194 MemoryMappedSegment segment(filename, sizeof(filename)); 195 while (proc_maps.Next(&segment)) { 196 if (IsDynamicRTName(segment.filename)) { 197 Report( 198 "Your application is linked against " 199 "incompatible ASan runtimes.\n"); 200 Die(); 201 } 202 } 203 __asan_rt_version = ASAN_RT_VERSION_STATIC; 204 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 205 ReportIncompatibleRT(); 206 } 207 } 208 } 209 # endif // SANITIZER_ANDROID 210 211 # if ASAN_INTERCEPT_SWAPCONTEXT 212 constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea; 213 214 static int HashContextStack(const ucontext_t &ucp) { 215 MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic); 216 hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp)); 217 hash.add(ucp.uc_stack.ss_size); 218 return static_cast<int>(hash.get()); 219 } 220 221 void SignContextStack(void *context) { 222 ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context); 223 ucp->uc_stack.ss_flags = HashContextStack(*ucp); 224 } 225 226 void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 227 const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context); 228 if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) { 229 *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp); 230 *ssize = ucp->uc_stack.ss_size; 231 return; 232 } 233 *stack = 0; 234 *ssize = 0; 235 } 236 # endif // ASAN_INTERCEPT_SWAPCONTEXT 237 238 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } 239 240 bool HandleDlopenInit() { 241 // Not supported on this platform. 242 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 243 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 244 return false; 245 } 246 247 } // namespace __asan 248 249 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || 250 // SANITIZER_SOLARIS 251