168d75effSDimitry Andric //===-- asan_linux.cpp ----------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Linux-specific details. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 1568d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 1668d75effSDimitry Andric SANITIZER_SOLARIS 1768d75effSDimitry Andric 189e7101a8SDimitry Andric # include <dlfcn.h> 199e7101a8SDimitry Andric # include <fcntl.h> 209e7101a8SDimitry Andric # include <limits.h> 219e7101a8SDimitry Andric # include <pthread.h> 229e7101a8SDimitry Andric # include <stdio.h> 239e7101a8SDimitry Andric # include <sys/mman.h> 249e7101a8SDimitry Andric # include <sys/resource.h> 259e7101a8SDimitry Andric # include <sys/syscall.h> 269e7101a8SDimitry Andric # include <sys/time.h> 279e7101a8SDimitry Andric # include <sys/types.h> 289e7101a8SDimitry Andric # include <unistd.h> 299e7101a8SDimitry Andric # include <unwind.h> 309e7101a8SDimitry Andric 3168d75effSDimitry Andric # include "asan_interceptors.h" 3268d75effSDimitry Andric # include "asan_internal.h" 3368d75effSDimitry Andric # include "asan_premap_shadow.h" 3468d75effSDimitry Andric # include "asan_thread.h" 3568d75effSDimitry Andric # include "sanitizer_common/sanitizer_flags.h" 369e7101a8SDimitry Andric # include "sanitizer_common/sanitizer_hash.h" 3768d75effSDimitry Andric # include "sanitizer_common/sanitizer_libc.h" 3868d75effSDimitry Andric # include "sanitizer_common/sanitizer_procmaps.h" 3968d75effSDimitry Andric 4068d75effSDimitry Andric # if SANITIZER_FREEBSD 4168d75effSDimitry Andric # include <sys/link_elf.h> 4268d75effSDimitry Andric # endif 4368d75effSDimitry Andric 4468d75effSDimitry Andric # if SANITIZER_SOLARIS 4568d75effSDimitry Andric # include <link.h> 4668d75effSDimitry Andric # endif 4768d75effSDimitry Andric 4868d75effSDimitry Andric # if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS 4968d75effSDimitry Andric # include <ucontext.h> 5068d75effSDimitry Andric # elif SANITIZER_NETBSD 5168d75effSDimitry Andric # include <link_elf.h> 5268d75effSDimitry Andric # include <ucontext.h> 5368d75effSDimitry Andric # else 5468d75effSDimitry Andric # include <link.h> 559e7101a8SDimitry Andric # include <sys/ucontext.h> 5668d75effSDimitry Andric # endif 5768d75effSDimitry Andric 5868d75effSDimitry Andric typedef enum { 5968d75effSDimitry Andric ASAN_RT_VERSION_UNDEFINED = 0, 6068d75effSDimitry Andric ASAN_RT_VERSION_DYNAMIC, 6168d75effSDimitry Andric ASAN_RT_VERSION_STATIC, 6268d75effSDimitry Andric } asan_rt_version_t; 6368d75effSDimitry Andric 6468d75effSDimitry Andric // FIXME: perhaps also store abi version here? 6568d75effSDimitry Andric extern "C" { 6668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 6768d75effSDimitry Andric asan_rt_version_t __asan_rt_version; 6868d75effSDimitry Andric } 6968d75effSDimitry Andric 7068d75effSDimitry Andric namespace __asan { 7168d75effSDimitry Andric 7268d75effSDimitry Andric void InitializePlatformInterceptors() {} 7368d75effSDimitry Andric void InitializePlatformExceptionHandlers() {} 7468d75effSDimitry Andric bool IsSystemHeapAddress(uptr addr) { return false; } 7568d75effSDimitry Andric 7668d75effSDimitry Andric # if ASAN_PREMAP_SHADOW 77e8d8bef9SDimitry Andric uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 7868d75effSDimitry Andric uptr granularity = GetMmapGranularity(); 7968d75effSDimitry Andric uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 8068d75effSDimitry Andric uptr premap_shadow_size = PremapShadowSize(); 81e8d8bef9SDimitry Andric uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 8268d75effSDimitry Andric // We may have mapped too much. Release extra memory. 8368d75effSDimitry Andric UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 8468d75effSDimitry Andric return shadow_start; 8568d75effSDimitry Andric } 8668d75effSDimitry Andric # endif 8768d75effSDimitry Andric 8868d75effSDimitry Andric uptr FindDynamicShadowStart() { 89e8d8bef9SDimitry Andric uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); 9068d75effSDimitry Andric # if ASAN_PREMAP_SHADOW 9168d75effSDimitry Andric if (!PremapShadowFailed()) 92e8d8bef9SDimitry Andric return FindPremappedShadowStart(shadow_size_bytes); 9368d75effSDimitry Andric # endif 9468d75effSDimitry Andric 950eae32dcSDimitry Andric return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, 96*0fca6ea1SDimitry Andric /*min_shadow_base_alignment*/ 0, kHighMemEnd, 97*0fca6ea1SDimitry Andric GetMmapGranularity()); 9868d75effSDimitry Andric } 9968d75effSDimitry Andric 10068d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 10168d75effSDimitry Andric UNIMPLEMENTED(); 10268d75effSDimitry Andric } 10368d75effSDimitry Andric 104e8d8bef9SDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) { 105e8d8bef9SDimitry Andric // Since asan's mapping is compacting, the shadow chunk may be 106e8d8bef9SDimitry Andric // not page-aligned, so we only flush the page-aligned portion. 107e8d8bef9SDimitry Andric ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 108e8d8bef9SDimitry Andric } 109e8d8bef9SDimitry Andric 11068d75effSDimitry Andric # if SANITIZER_ANDROID 11168d75effSDimitry Andric // FIXME: should we do anything for Android? 11268d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 11368d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 11468d75effSDimitry Andric # else 11568d75effSDimitry Andric static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 11668d75effSDimitry Andric void *data) { 117349cc55cSDimitry Andric VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, 118349cc55cSDimitry Andric (void *)info->dlpi_addr); 11968d75effSDimitry Andric 1203a9a9c0cSDimitry Andric const char **name = (const char **)data; 12168d75effSDimitry Andric 12268d75effSDimitry Andric // Ignore first entry (the main program) 1233a9a9c0cSDimitry Andric if (!*name) { 1243a9a9c0cSDimitry Andric *name = ""; 12568d75effSDimitry Andric return 0; 12668d75effSDimitry Andric } 12768d75effSDimitry Andric 1283a9a9c0cSDimitry Andric # if SANITIZER_LINUX 1293a9a9c0cSDimitry Andric // Ignore vDSO. glibc versions earlier than 2.15 (and some patched 1303a9a9c0cSDimitry Andric // by distributors) return an empty name for the vDSO entry, so 1313a9a9c0cSDimitry Andric // detect this as well. 1323a9a9c0cSDimitry Andric if (!info->dlpi_name[0] || 1333a9a9c0cSDimitry Andric internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 13468d75effSDimitry Andric return 0; 13568d75effSDimitry Andric # endif 136647cbc5dSDimitry Andric # if SANITIZER_FREEBSD 137647cbc5dSDimitry Andric // Ignore vDSO. 138647cbc5dSDimitry Andric if (internal_strcmp(info->dlpi_name, "[vdso]") == 0) 139647cbc5dSDimitry Andric return 0; 140647cbc5dSDimitry Andric # endif 14168d75effSDimitry Andric 1423a9a9c0cSDimitry Andric *name = info->dlpi_name; 14368d75effSDimitry Andric return 1; 14468d75effSDimitry Andric } 14568d75effSDimitry Andric 14668d75effSDimitry Andric static bool IsDynamicRTName(const char *libname) { 14768d75effSDimitry Andric return internal_strstr(libname, "libclang_rt.asan") || 14868d75effSDimitry Andric internal_strstr(libname, "libasan.so"); 14968d75effSDimitry Andric } 15068d75effSDimitry Andric 15168d75effSDimitry Andric static void ReportIncompatibleRT() { 15268d75effSDimitry Andric Report("Your application is linked against incompatible ASan runtimes.\n"); 15368d75effSDimitry Andric Die(); 15468d75effSDimitry Andric } 15568d75effSDimitry Andric 15668d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() { 15768d75effSDimitry Andric if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 15868d75effSDimitry Andric return; 15968d75effSDimitry Andric 16068d75effSDimitry Andric // Ensure that dynamic RT is the first DSO in the list 16168d75effSDimitry Andric const char *first_dso_name = nullptr; 16268d75effSDimitry Andric dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 1633a9a9c0cSDimitry Andric if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) { 1649e7101a8SDimitry Andric Report( 1659e7101a8SDimitry Andric "ASan runtime does not come first in initial library list; " 16668d75effSDimitry Andric "you should either link runtime to your application or " 16768d75effSDimitry Andric "manually preload it with LD_PRELOAD.\n"); 16868d75effSDimitry Andric Die(); 16968d75effSDimitry Andric } 17068d75effSDimitry Andric } 17168d75effSDimitry Andric 17268d75effSDimitry Andric void AsanCheckIncompatibleRT() { 17368d75effSDimitry Andric if (ASAN_DYNAMIC) { 17468d75effSDimitry Andric if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 17568d75effSDimitry Andric __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 17668d75effSDimitry Andric } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 17768d75effSDimitry Andric ReportIncompatibleRT(); 17868d75effSDimitry Andric } 17968d75effSDimitry Andric } else { 18068d75effSDimitry Andric if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 18168d75effSDimitry Andric // Ensure that dynamic runtime is not present. We should detect it 18268d75effSDimitry Andric // as early as possible, otherwise ASan interceptors could bind to 18368d75effSDimitry Andric // the functions in dynamic ASan runtime instead of the functions in 18468d75effSDimitry Andric // system libraries, causing crashes later in ASan initialization. 18568d75effSDimitry Andric MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 18668d75effSDimitry Andric char filename[PATH_MAX]; 18768d75effSDimitry Andric MemoryMappedSegment segment(filename, sizeof(filename)); 18868d75effSDimitry Andric while (proc_maps.Next(&segment)) { 18968d75effSDimitry Andric if (IsDynamicRTName(segment.filename)) { 1909e7101a8SDimitry Andric Report( 1919e7101a8SDimitry Andric "Your application is linked against " 19268d75effSDimitry Andric "incompatible ASan runtimes.\n"); 19368d75effSDimitry Andric Die(); 19468d75effSDimitry Andric } 19568d75effSDimitry Andric } 19668d75effSDimitry Andric __asan_rt_version = ASAN_RT_VERSION_STATIC; 19768d75effSDimitry Andric } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 19868d75effSDimitry Andric ReportIncompatibleRT(); 19968d75effSDimitry Andric } 20068d75effSDimitry Andric } 20168d75effSDimitry Andric } 20268d75effSDimitry Andric # endif // SANITIZER_ANDROID 20368d75effSDimitry Andric 204bdd1243dSDimitry Andric # if ASAN_INTERCEPT_SWAPCONTEXT 2059e7101a8SDimitry Andric constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea; 2069e7101a8SDimitry Andric 2079e7101a8SDimitry Andric static int HashContextStack(const ucontext_t &ucp) { 2089e7101a8SDimitry Andric MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic); 2099e7101a8SDimitry Andric hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp)); 2109e7101a8SDimitry Andric hash.add(ucp.uc_stack.ss_size); 2119e7101a8SDimitry Andric return static_cast<int>(hash.get()); 21268d75effSDimitry Andric } 213fcaf7f86SDimitry Andric 2149e7101a8SDimitry Andric void SignContextStack(void *context) { 2159e7101a8SDimitry Andric ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context); 2169e7101a8SDimitry Andric ucp->uc_stack.ss_flags = HashContextStack(*ucp); 2179e7101a8SDimitry Andric } 2189e7101a8SDimitry Andric 2199e7101a8SDimitry Andric void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 2209e7101a8SDimitry Andric const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context); 2219e7101a8SDimitry Andric if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) { 2229e7101a8SDimitry Andric *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp); 2239e7101a8SDimitry Andric *ssize = ucp->uc_stack.ss_size; 2249e7101a8SDimitry Andric return; 2259e7101a8SDimitry Andric } 2269e7101a8SDimitry Andric *stack = 0; 2279e7101a8SDimitry Andric *ssize = 0; 228fcaf7f86SDimitry Andric } 229bdd1243dSDimitry Andric # endif // ASAN_INTERCEPT_SWAPCONTEXT 23068d75effSDimitry Andric 2319e7101a8SDimitry Andric void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } 23268d75effSDimitry Andric 23368d75effSDimitry Andric bool HandleDlopenInit() { 23468d75effSDimitry Andric // Not supported on this platform. 23568d75effSDimitry Andric static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 23668d75effSDimitry Andric "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 23768d75effSDimitry Andric return false; 23868d75effSDimitry Andric } 23968d75effSDimitry Andric 24068d75effSDimitry Andric } // namespace __asan 24168d75effSDimitry Andric 24268d75effSDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || 24368d75effSDimitry Andric // SANITIZER_SOLARIS 244