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 || SANITIZER_HAIKU 17 18 # if SANITIZER_HAIKU 19 # define _DEFAULT_SOURCE 20 # endif 21 22 # include <dlfcn.h> 23 # include <fcntl.h> 24 # include <limits.h> 25 # include <pthread.h> 26 # include <stdio.h> 27 # include <sys/mman.h> 28 # include <sys/resource.h> 29 # if !SANITIZER_HAIKU 30 # include <sys/syscall.h> 31 # endif 32 # include <sys/time.h> 33 # include <sys/types.h> 34 # include <unistd.h> 35 # include <unwind.h> 36 37 # include "asan_interceptors.h" 38 # include "asan_internal.h" 39 # include "asan_premap_shadow.h" 40 # include "asan_thread.h" 41 # include "sanitizer_common/sanitizer_flags.h" 42 # include "sanitizer_common/sanitizer_hash.h" 43 # include "sanitizer_common/sanitizer_libc.h" 44 # include "sanitizer_common/sanitizer_procmaps.h" 45 46 # if SANITIZER_FREEBSD || SANITIZER_HAIKU 47 # include <sys/link_elf.h> 48 # endif 49 50 # if SANITIZER_LINUX 51 # include <sys/personality.h> 52 # endif 53 54 # if SANITIZER_SOLARIS 55 # include <link.h> 56 # endif 57 58 # if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS 59 # include <ucontext.h> 60 # elif SANITIZER_NETBSD 61 # include <link_elf.h> 62 # include <ucontext.h> 63 # elif SANITIZER_HAIKU 64 extern "C" void *_DYNAMIC; 65 # else 66 # include <link.h> 67 # include <sys/ucontext.h> 68 # endif 69 70 typedef 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? 77 extern "C" { 78 SANITIZER_INTERFACE_ATTRIBUTE 79 asan_rt_version_t __asan_rt_version; 80 } 81 82 namespace __asan { 83 84 void InitializePlatformInterceptors() {} 85 void InitializePlatformExceptionHandlers() {} 86 bool IsSystemHeapAddress(uptr addr) { return false; } 87 88 # if ASAN_PREMAP_SHADOW 89 uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 90 uptr granularity = GetMmapGranularity(); 91 uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 92 uptr premap_shadow_size = PremapShadowSize(); 93 uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 94 // We may have mapped too much. Release extra memory. 95 UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 96 return shadow_start; 97 } 98 # endif 99 100 uptr FindDynamicShadowStart() { 101 uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); 102 # if ASAN_PREMAP_SHADOW 103 if (!PremapShadowFailed()) 104 return FindPremappedShadowStart(shadow_size_bytes); 105 # endif 106 107 return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, 108 /*min_shadow_base_alignment*/ 0, kHighMemEnd, 109 GetMmapGranularity()); 110 } 111 112 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 113 UNIMPLEMENTED(); 114 } 115 116 void FlushUnneededASanShadowMemory(uptr p, uptr size) { 117 // Since asan's mapping is compacting, the shadow chunk may be 118 // not page-aligned, so we only flush the page-aligned portion. 119 ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 120 } 121 122 void TryReExecWithoutASLR() { 123 # if SANITIZER_LINUX 124 // ASLR personality check. 125 // Caution: 'personality' is sometimes forbidden by sandboxes, so only call 126 // this function as a last resort (when the memory mapping is incompatible 127 // and ASan would fail anyway). 128 int old_personality = personality(0xffffffff); 129 if (old_personality == -1) { 130 VReport(1, "WARNING: unable to run personality check.\n"); 131 return; 132 } 133 134 bool aslr_on = (old_personality & ADDR_NO_RANDOMIZE) == 0; 135 136 if (aslr_on) { 137 // Disable ASLR if the memory layout was incompatible. 138 // Alternatively, we could just keep re-execing until we get lucky 139 // with a compatible randomized layout, but the risk is that if it's 140 // not an ASLR-related issue, we will be stuck in an infinite loop of 141 // re-execing (unless we change ReExec to pass a parameter of the 142 // number of retries allowed.) 143 VReport(1, 144 "WARNING: AddressSanitizer: memory layout is incompatible, " 145 "possibly due to high-entropy ASLR.\n" 146 "Re-execing with fixed virtual address space.\n" 147 "N.B. reducing ASLR entropy is preferable.\n"); 148 CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); 149 150 ReExec(); 151 } 152 # endif 153 } 154 155 # if SANITIZER_ANDROID 156 // FIXME: should we do anything for Android? 157 void AsanCheckDynamicRTPrereqs() {} 158 void AsanCheckIncompatibleRT() {} 159 # else 160 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 161 void *data) { 162 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, 163 (void *)info->dlpi_addr); 164 165 const char **name = (const char **)data; 166 167 // Ignore first entry (the main program) 168 if (!*name) { 169 *name = ""; 170 return 0; 171 } 172 173 # if SANITIZER_HAIKU 174 if (!info->dlpi_name[0] || 175 internal_strncmp(info->dlpi_name, "/boot/system/runtime_loader", 176 sizeof("/boot/system/runtime_loader") - 1) == 0) 177 return 0; 178 # endif 179 # if SANITIZER_LINUX 180 // Ignore vDSO. glibc versions earlier than 2.15 (and some patched 181 // by distributors) return an empty name for the vDSO entry, so 182 // detect this as well. 183 if (!info->dlpi_name[0] || 184 internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 185 return 0; 186 # endif 187 # if SANITIZER_FREEBSD 188 // Ignore vDSO. 189 if (internal_strcmp(info->dlpi_name, "[vdso]") == 0) 190 return 0; 191 # endif 192 193 *name = info->dlpi_name; 194 return 1; 195 } 196 197 static bool IsDynamicRTName(const char *libname) { 198 return internal_strstr(libname, "libclang_rt.asan") || 199 internal_strstr(libname, "libasan.so"); 200 } 201 202 static void ReportIncompatibleRT() { 203 Report("Your application is linked against incompatible ASan runtimes.\n"); 204 Die(); 205 } 206 207 void AsanCheckDynamicRTPrereqs() { 208 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 209 return; 210 211 // Ensure that dynamic RT is the first DSO in the list 212 const char *first_dso_name = nullptr; 213 dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 214 if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) { 215 Report( 216 "ASan runtime does not come first in initial library list; " 217 "you should either link runtime to your application or " 218 "manually preload it with LD_PRELOAD.\n"); 219 Die(); 220 } 221 } 222 223 void AsanCheckIncompatibleRT() { 224 if (ASAN_DYNAMIC) { 225 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 226 __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 227 } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 228 ReportIncompatibleRT(); 229 } 230 } else { 231 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 232 // Ensure that dynamic runtime is not present. We should detect it 233 // as early as possible, otherwise ASan interceptors could bind to 234 // the functions in dynamic ASan runtime instead of the functions in 235 // system libraries, causing crashes later in ASan initialization. 236 MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 237 char filename[PATH_MAX]; 238 MemoryMappedSegment segment(filename, sizeof(filename)); 239 while (proc_maps.Next(&segment)) { 240 if (IsDynamicRTName(segment.filename)) { 241 ReportIncompatibleRT(); 242 } 243 } 244 __asan_rt_version = ASAN_RT_VERSION_STATIC; 245 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 246 ReportIncompatibleRT(); 247 } 248 } 249 } 250 # endif // SANITIZER_ANDROID 251 252 # if ASAN_INTERCEPT_SWAPCONTEXT 253 constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea; 254 255 static int HashContextStack(const ucontext_t &ucp) { 256 MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic); 257 hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp)); 258 hash.add(ucp.uc_stack.ss_size); 259 return static_cast<int>(hash.get()); 260 } 261 262 void SignContextStack(void *context) { 263 ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context); 264 ucp->uc_stack.ss_flags = HashContextStack(*ucp); 265 } 266 267 void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 268 const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context); 269 if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) { 270 *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp); 271 *ssize = ucp->uc_stack.ss_size; 272 return; 273 } 274 *stack = 0; 275 *ssize = 0; 276 } 277 # endif // ASAN_INTERCEPT_SWAPCONTEXT 278 279 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } 280 281 bool HandleDlopenInit() { 282 // Not supported on this platform. 283 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 284 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 285 return false; 286 } 287 288 } // namespace __asan 289 290 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || 291 // SANITIZER_SOLARIS || SANITIZER_HAIKU 292