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 # elif SANITIZER_NETBSD 51 # include <link_elf.h> 52 # include <ucontext.h> 53 # else 54 # include <link.h> 55 # include <sys/ucontext.h> 56 # endif 57 58 typedef enum { 59 ASAN_RT_VERSION_UNDEFINED = 0, 60 ASAN_RT_VERSION_DYNAMIC, 61 ASAN_RT_VERSION_STATIC, 62 } asan_rt_version_t; 63 64 // FIXME: perhaps also store abi version here? 65 extern "C" { 66 SANITIZER_INTERFACE_ATTRIBUTE 67 asan_rt_version_t __asan_rt_version; 68 } 69 70 namespace __asan { 71 72 void InitializePlatformInterceptors() {} 73 void InitializePlatformExceptionHandlers() {} 74 bool IsSystemHeapAddress(uptr addr) { return false; } 75 76 # if ASAN_PREMAP_SHADOW 77 uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 78 uptr granularity = GetMmapGranularity(); 79 uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 80 uptr premap_shadow_size = PremapShadowSize(); 81 uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 82 // We may have mapped too much. Release extra memory. 83 UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 84 return shadow_start; 85 } 86 # endif 87 88 uptr FindDynamicShadowStart() { 89 uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); 90 # if ASAN_PREMAP_SHADOW 91 if (!PremapShadowFailed()) 92 return FindPremappedShadowStart(shadow_size_bytes); 93 # endif 94 95 return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, 96 /*min_shadow_base_alignment*/ 0, kHighMemEnd, 97 GetMmapGranularity()); 98 } 99 100 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 101 UNIMPLEMENTED(); 102 } 103 104 void FlushUnneededASanShadowMemory(uptr p, uptr size) { 105 // Since asan's mapping is compacting, the shadow chunk may be 106 // not page-aligned, so we only flush the page-aligned portion. 107 ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 108 } 109 110 # if SANITIZER_ANDROID 111 // FIXME: should we do anything for Android? 112 void AsanCheckDynamicRTPrereqs() {} 113 void AsanCheckIncompatibleRT() {} 114 # else 115 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 116 void *data) { 117 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, 118 (void *)info->dlpi_addr); 119 120 const char **name = (const char **)data; 121 122 // Ignore first entry (the main program) 123 if (!*name) { 124 *name = ""; 125 return 0; 126 } 127 128 # if SANITIZER_LINUX 129 // Ignore vDSO. glibc versions earlier than 2.15 (and some patched 130 // by distributors) return an empty name for the vDSO entry, so 131 // detect this as well. 132 if (!info->dlpi_name[0] || 133 internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 134 return 0; 135 # endif 136 # if SANITIZER_FREEBSD 137 // Ignore vDSO. 138 if (internal_strcmp(info->dlpi_name, "[vdso]") == 0) 139 return 0; 140 # endif 141 142 *name = info->dlpi_name; 143 return 1; 144 } 145 146 static bool IsDynamicRTName(const char *libname) { 147 return internal_strstr(libname, "libclang_rt.asan") || 148 internal_strstr(libname, "libasan.so"); 149 } 150 151 static void ReportIncompatibleRT() { 152 Report("Your application is linked against incompatible ASan runtimes.\n"); 153 Die(); 154 } 155 156 void AsanCheckDynamicRTPrereqs() { 157 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 158 return; 159 160 // Ensure that dynamic RT is the first DSO in the list 161 const char *first_dso_name = nullptr; 162 dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 163 if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) { 164 Report( 165 "ASan runtime does not come first in initial library list; " 166 "you should either link runtime to your application or " 167 "manually preload it with LD_PRELOAD.\n"); 168 Die(); 169 } 170 } 171 172 void AsanCheckIncompatibleRT() { 173 if (ASAN_DYNAMIC) { 174 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 175 __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 176 } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 177 ReportIncompatibleRT(); 178 } 179 } else { 180 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 181 // Ensure that dynamic runtime is not present. We should detect it 182 // as early as possible, otherwise ASan interceptors could bind to 183 // the functions in dynamic ASan runtime instead of the functions in 184 // system libraries, causing crashes later in ASan initialization. 185 MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 186 char filename[PATH_MAX]; 187 MemoryMappedSegment segment(filename, sizeof(filename)); 188 while (proc_maps.Next(&segment)) { 189 if (IsDynamicRTName(segment.filename)) { 190 Report( 191 "Your application is linked against " 192 "incompatible ASan runtimes.\n"); 193 Die(); 194 } 195 } 196 __asan_rt_version = ASAN_RT_VERSION_STATIC; 197 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 198 ReportIncompatibleRT(); 199 } 200 } 201 } 202 # endif // SANITIZER_ANDROID 203 204 # if ASAN_INTERCEPT_SWAPCONTEXT 205 constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea; 206 207 static int HashContextStack(const ucontext_t &ucp) { 208 MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic); 209 hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp)); 210 hash.add(ucp.uc_stack.ss_size); 211 return static_cast<int>(hash.get()); 212 } 213 214 void SignContextStack(void *context) { 215 ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context); 216 ucp->uc_stack.ss_flags = HashContextStack(*ucp); 217 } 218 219 void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 220 const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context); 221 if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) { 222 *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp); 223 *ssize = ucp->uc_stack.ss_size; 224 return; 225 } 226 *stack = 0; 227 *ssize = 0; 228 } 229 # endif // ASAN_INTERCEPT_SWAPCONTEXT 230 231 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } 232 233 bool HandleDlopenInit() { 234 // Not supported on this platform. 235 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 236 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 237 return false; 238 } 239 240 } // namespace __asan 241 242 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || 243 // SANITIZER_SOLARIS 244