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 1868d75effSDimitry Andric #include "asan_interceptors.h" 1968d75effSDimitry Andric #include "asan_internal.h" 2068d75effSDimitry Andric #include "asan_premap_shadow.h" 2168d75effSDimitry Andric #include "asan_thread.h" 2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h" 2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_freebsd.h" 2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h" 2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h" 2668d75effSDimitry Andric 2768d75effSDimitry Andric #include <sys/time.h> 2868d75effSDimitry Andric #include <sys/resource.h> 2968d75effSDimitry Andric #include <sys/mman.h> 3068d75effSDimitry Andric #include <sys/syscall.h> 3168d75effSDimitry Andric #include <sys/types.h> 3268d75effSDimitry Andric #include <dlfcn.h> 3368d75effSDimitry Andric #include <fcntl.h> 3468d75effSDimitry Andric #include <limits.h> 3568d75effSDimitry Andric #include <pthread.h> 3668d75effSDimitry Andric #include <stdio.h> 3768d75effSDimitry Andric #include <unistd.h> 3868d75effSDimitry Andric #include <unwind.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 extern "C" void* _DYNAMIC; 5168d75effSDimitry Andric #elif SANITIZER_NETBSD 5268d75effSDimitry Andric #include <link_elf.h> 5368d75effSDimitry Andric #include <ucontext.h> 5468d75effSDimitry Andric extern Elf_Dyn _DYNAMIC; 5568d75effSDimitry Andric #else 5668d75effSDimitry Andric #include <sys/ucontext.h> 5768d75effSDimitry Andric #include <link.h> 58e8d8bef9SDimitry Andric extern ElfW(Dyn) _DYNAMIC[]; 5968d75effSDimitry Andric #endif 6068d75effSDimitry Andric 6168d75effSDimitry Andric // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in 6268d75effSDimitry Andric // 32-bit mode. 6368d75effSDimitry Andric #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ 6468d75effSDimitry Andric __FreeBSD_version <= 902001 // v9.2 6568d75effSDimitry Andric #define ucontext_t xucontext_t 6668d75effSDimitry Andric #endif 6768d75effSDimitry Andric 6868d75effSDimitry Andric typedef enum { 6968d75effSDimitry Andric ASAN_RT_VERSION_UNDEFINED = 0, 7068d75effSDimitry Andric ASAN_RT_VERSION_DYNAMIC, 7168d75effSDimitry Andric ASAN_RT_VERSION_STATIC, 7268d75effSDimitry Andric } asan_rt_version_t; 7368d75effSDimitry Andric 7468d75effSDimitry Andric // FIXME: perhaps also store abi version here? 7568d75effSDimitry Andric extern "C" { 7668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 7768d75effSDimitry Andric asan_rt_version_t __asan_rt_version; 7868d75effSDimitry Andric } 7968d75effSDimitry Andric 8068d75effSDimitry Andric namespace __asan { 8168d75effSDimitry Andric 8268d75effSDimitry Andric void InitializePlatformInterceptors() {} 8368d75effSDimitry Andric void InitializePlatformExceptionHandlers() {} 8468d75effSDimitry Andric bool IsSystemHeapAddress (uptr addr) { return false; } 8568d75effSDimitry Andric 8668d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { 8768d75effSDimitry Andric // This will fail to link with -static. 88e8d8bef9SDimitry Andric return &_DYNAMIC; 8968d75effSDimitry Andric } 9068d75effSDimitry Andric 9168d75effSDimitry Andric #if ASAN_PREMAP_SHADOW 92e8d8bef9SDimitry Andric uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 9368d75effSDimitry Andric uptr granularity = GetMmapGranularity(); 9468d75effSDimitry Andric uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 9568d75effSDimitry Andric uptr premap_shadow_size = PremapShadowSize(); 96e8d8bef9SDimitry Andric uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 9768d75effSDimitry Andric // We may have mapped too much. Release extra memory. 9868d75effSDimitry Andric UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 9968d75effSDimitry Andric return shadow_start; 10068d75effSDimitry Andric } 10168d75effSDimitry Andric #endif 10268d75effSDimitry Andric 10368d75effSDimitry Andric uptr FindDynamicShadowStart() { 104e8d8bef9SDimitry Andric uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); 10568d75effSDimitry Andric #if ASAN_PREMAP_SHADOW 10668d75effSDimitry Andric if (!PremapShadowFailed()) 107e8d8bef9SDimitry Andric return FindPremappedShadowStart(shadow_size_bytes); 10868d75effSDimitry Andric #endif 10968d75effSDimitry Andric 110*0eae32dcSDimitry Andric return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, 111e8d8bef9SDimitry Andric /*min_shadow_base_alignment*/ 0, kHighMemEnd); 11268d75effSDimitry Andric } 11368d75effSDimitry Andric 11468d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 11568d75effSDimitry Andric UNIMPLEMENTED(); 11668d75effSDimitry Andric } 11768d75effSDimitry Andric 118e8d8bef9SDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) { 119e8d8bef9SDimitry Andric // Since asan's mapping is compacting, the shadow chunk may be 120e8d8bef9SDimitry Andric // not page-aligned, so we only flush the page-aligned portion. 121e8d8bef9SDimitry Andric ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 122e8d8bef9SDimitry Andric } 123e8d8bef9SDimitry Andric 12468d75effSDimitry Andric #if SANITIZER_ANDROID 12568d75effSDimitry Andric // FIXME: should we do anything for Android? 12668d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 12768d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 12868d75effSDimitry Andric #else 12968d75effSDimitry Andric static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 13068d75effSDimitry Andric void *data) { 131349cc55cSDimitry Andric VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, 132349cc55cSDimitry Andric (void *)info->dlpi_addr); 13368d75effSDimitry Andric 13468d75effSDimitry Andric // Continue until the first dynamic library is found 13568d75effSDimitry Andric if (!info->dlpi_name || info->dlpi_name[0] == 0) 13668d75effSDimitry Andric return 0; 13768d75effSDimitry Andric 13868d75effSDimitry Andric // Ignore vDSO 13968d75effSDimitry Andric if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 14068d75effSDimitry Andric return 0; 14168d75effSDimitry Andric 14268d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_NETBSD 14368d75effSDimitry Andric // Ignore first entry (the main program) 14468d75effSDimitry Andric char **p = (char **)data; 14568d75effSDimitry Andric if (!(*p)) { 14668d75effSDimitry Andric *p = (char *)-1; 14768d75effSDimitry Andric return 0; 14868d75effSDimitry Andric } 14968d75effSDimitry Andric #endif 15068d75effSDimitry Andric 15168d75effSDimitry Andric #if SANITIZER_SOLARIS 15268d75effSDimitry Andric // Ignore executable on Solaris 15368d75effSDimitry Andric if (info->dlpi_addr == 0) 15468d75effSDimitry Andric return 0; 15568d75effSDimitry Andric #endif 15668d75effSDimitry Andric 15768d75effSDimitry Andric *(const char **)data = info->dlpi_name; 15868d75effSDimitry Andric return 1; 15968d75effSDimitry Andric } 16068d75effSDimitry Andric 16168d75effSDimitry Andric static bool IsDynamicRTName(const char *libname) { 16268d75effSDimitry Andric return internal_strstr(libname, "libclang_rt.asan") || 16368d75effSDimitry Andric internal_strstr(libname, "libasan.so"); 16468d75effSDimitry Andric } 16568d75effSDimitry Andric 16668d75effSDimitry Andric static void ReportIncompatibleRT() { 16768d75effSDimitry Andric Report("Your application is linked against incompatible ASan runtimes.\n"); 16868d75effSDimitry Andric Die(); 16968d75effSDimitry Andric } 17068d75effSDimitry Andric 17168d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() { 17268d75effSDimitry Andric if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 17368d75effSDimitry Andric return; 17468d75effSDimitry Andric 17568d75effSDimitry Andric // Ensure that dynamic RT is the first DSO in the list 17668d75effSDimitry Andric const char *first_dso_name = nullptr; 17768d75effSDimitry Andric dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 17868d75effSDimitry Andric if (first_dso_name && !IsDynamicRTName(first_dso_name)) { 17968d75effSDimitry Andric Report("ASan runtime does not come first in initial library list; " 18068d75effSDimitry Andric "you should either link runtime to your application or " 18168d75effSDimitry Andric "manually preload it with LD_PRELOAD.\n"); 18268d75effSDimitry Andric Die(); 18368d75effSDimitry Andric } 18468d75effSDimitry Andric } 18568d75effSDimitry Andric 18668d75effSDimitry Andric void AsanCheckIncompatibleRT() { 18768d75effSDimitry Andric if (ASAN_DYNAMIC) { 18868d75effSDimitry Andric if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 18968d75effSDimitry Andric __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 19068d75effSDimitry Andric } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 19168d75effSDimitry Andric ReportIncompatibleRT(); 19268d75effSDimitry Andric } 19368d75effSDimitry Andric } else { 19468d75effSDimitry Andric if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 19568d75effSDimitry Andric // Ensure that dynamic runtime is not present. We should detect it 19668d75effSDimitry Andric // as early as possible, otherwise ASan interceptors could bind to 19768d75effSDimitry Andric // the functions in dynamic ASan runtime instead of the functions in 19868d75effSDimitry Andric // system libraries, causing crashes later in ASan initialization. 19968d75effSDimitry Andric MemoryMappingLayout proc_maps(/*cache_enabled*/true); 20068d75effSDimitry Andric char filename[PATH_MAX]; 20168d75effSDimitry Andric MemoryMappedSegment segment(filename, sizeof(filename)); 20268d75effSDimitry Andric while (proc_maps.Next(&segment)) { 20368d75effSDimitry Andric if (IsDynamicRTName(segment.filename)) { 20468d75effSDimitry Andric Report("Your application is linked against " 20568d75effSDimitry Andric "incompatible ASan runtimes.\n"); 20668d75effSDimitry Andric Die(); 20768d75effSDimitry Andric } 20868d75effSDimitry Andric } 20968d75effSDimitry Andric __asan_rt_version = ASAN_RT_VERSION_STATIC; 21068d75effSDimitry Andric } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 21168d75effSDimitry Andric ReportIncompatibleRT(); 21268d75effSDimitry Andric } 21368d75effSDimitry Andric } 21468d75effSDimitry Andric } 21568d75effSDimitry Andric #endif // SANITIZER_ANDROID 21668d75effSDimitry Andric 21768d75effSDimitry Andric #if !SANITIZER_ANDROID 21868d75effSDimitry Andric void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 21968d75effSDimitry Andric ucontext_t *ucp = (ucontext_t*)context; 22068d75effSDimitry Andric *stack = (uptr)ucp->uc_stack.ss_sp; 22168d75effSDimitry Andric *ssize = ucp->uc_stack.ss_size; 22268d75effSDimitry Andric } 22368d75effSDimitry Andric #else 22468d75effSDimitry Andric void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 22568d75effSDimitry Andric UNIMPLEMENTED(); 22668d75effSDimitry Andric } 22768d75effSDimitry Andric #endif 22868d75effSDimitry Andric 22968d75effSDimitry Andric void *AsanDlSymNext(const char *sym) { 23068d75effSDimitry Andric return dlsym(RTLD_NEXT, sym); 23168d75effSDimitry Andric } 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