1353944Sdim//===-- asan_linux.cpp ----------------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker. 10353944Sdim// 11353944Sdim// Linux-specific details. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "sanitizer_common/sanitizer_platform.h" 15353944Sdim#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 16353944Sdim SANITIZER_SOLARIS 17353944Sdim 18353944Sdim#include "asan_interceptors.h" 19353944Sdim#include "asan_internal.h" 20353944Sdim#include "asan_premap_shadow.h" 21353944Sdim#include "asan_thread.h" 22353944Sdim#include "sanitizer_common/sanitizer_flags.h" 23353944Sdim#include "sanitizer_common/sanitizer_freebsd.h" 24353944Sdim#include "sanitizer_common/sanitizer_libc.h" 25353944Sdim#include "sanitizer_common/sanitizer_procmaps.h" 26353944Sdim 27353944Sdim#include <sys/time.h> 28353944Sdim#include <sys/resource.h> 29353944Sdim#include <sys/mman.h> 30353944Sdim#include <sys/syscall.h> 31353944Sdim#include <sys/types.h> 32353944Sdim#include <dlfcn.h> 33353944Sdim#include <fcntl.h> 34353944Sdim#include <limits.h> 35353944Sdim#include <pthread.h> 36353944Sdim#include <stdio.h> 37353944Sdim#include <unistd.h> 38353944Sdim#include <unwind.h> 39353944Sdim 40353944Sdim#if SANITIZER_FREEBSD 41353944Sdim#include <sys/link_elf.h> 42353944Sdim#endif 43353944Sdim 44353944Sdim#if SANITIZER_SOLARIS 45353944Sdim#include <link.h> 46353944Sdim#endif 47353944Sdim 48353944Sdim#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS 49353944Sdim#include <ucontext.h> 50353944Sdimextern "C" void* _DYNAMIC; 51353944Sdim#elif SANITIZER_NETBSD 52353944Sdim#include <link_elf.h> 53353944Sdim#include <ucontext.h> 54353944Sdimextern Elf_Dyn _DYNAMIC; 55353944Sdim#else 56353944Sdim#include <sys/ucontext.h> 57353944Sdim#include <link.h> 58353944Sdim#endif 59353944Sdim 60353944Sdim// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in 61353944Sdim// 32-bit mode. 62353944Sdim#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ 63353944Sdim __FreeBSD_version <= 902001 // v9.2 64353944Sdim#define ucontext_t xucontext_t 65353944Sdim#endif 66353944Sdim 67353944Sdimtypedef enum { 68353944Sdim ASAN_RT_VERSION_UNDEFINED = 0, 69353944Sdim ASAN_RT_VERSION_DYNAMIC, 70353944Sdim ASAN_RT_VERSION_STATIC, 71353944Sdim} asan_rt_version_t; 72353944Sdim 73353944Sdim// FIXME: perhaps also store abi version here? 74353944Sdimextern "C" { 75353944SdimSANITIZER_INTERFACE_ATTRIBUTE 76353944Sdimasan_rt_version_t __asan_rt_version; 77353944Sdim} 78353944Sdim 79353944Sdimnamespace __asan { 80353944Sdim 81353944Sdimvoid InitializePlatformInterceptors() {} 82353944Sdimvoid InitializePlatformExceptionHandlers() {} 83353944Sdimbool IsSystemHeapAddress (uptr addr) { return false; } 84353944Sdim 85353944Sdimvoid *AsanDoesNotSupportStaticLinkage() { 86353944Sdim // This will fail to link with -static. 87353944Sdim return &_DYNAMIC; // defined in link.h 88353944Sdim} 89353944Sdim 90353944Sdimstatic void UnmapFromTo(uptr from, uptr to) { 91353944Sdim CHECK(to >= from); 92353944Sdim if (to == from) return; 93353944Sdim uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); 94353944Sdim if (UNLIKELY(internal_iserror(res))) { 95353944Sdim Report( 96353944Sdim "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address " 97353944Sdim "%p\n", 98353944Sdim to - from, to - from, from); 99353944Sdim CHECK("unable to unmap" && 0); 100353944Sdim } 101353944Sdim} 102353944Sdim 103353944Sdim#if ASAN_PREMAP_SHADOW 104353944Sdimuptr FindPremappedShadowStart() { 105353944Sdim uptr granularity = GetMmapGranularity(); 106353944Sdim uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); 107353944Sdim uptr premap_shadow_size = PremapShadowSize(); 108353944Sdim uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); 109353944Sdim // We may have mapped too much. Release extra memory. 110353944Sdim UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 111353944Sdim return shadow_start; 112353944Sdim} 113353944Sdim#endif 114353944Sdim 115353944Sdimuptr FindDynamicShadowStart() { 116353944Sdim#if ASAN_PREMAP_SHADOW 117353944Sdim if (!PremapShadowFailed()) 118353944Sdim return FindPremappedShadowStart(); 119353944Sdim#endif 120353944Sdim 121353944Sdim uptr granularity = GetMmapGranularity(); 122353944Sdim uptr alignment = granularity * 8; 123353944Sdim uptr left_padding = granularity; 124353944Sdim uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); 125353944Sdim uptr map_size = shadow_size + left_padding + alignment; 126353944Sdim 127353944Sdim uptr map_start = (uptr)MmapNoAccess(map_size); 128353944Sdim CHECK_NE(map_start, ~(uptr)0); 129353944Sdim 130353944Sdim uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); 131353944Sdim UnmapFromTo(map_start, shadow_start - left_padding); 132353944Sdim UnmapFromTo(shadow_start + shadow_size, map_start + map_size); 133353944Sdim 134353944Sdim return shadow_start; 135353944Sdim} 136353944Sdim 137353944Sdimvoid AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 138353944Sdim UNIMPLEMENTED(); 139353944Sdim} 140353944Sdim 141353944Sdim#if SANITIZER_ANDROID 142353944Sdim// FIXME: should we do anything for Android? 143353944Sdimvoid AsanCheckDynamicRTPrereqs() {} 144353944Sdimvoid AsanCheckIncompatibleRT() {} 145353944Sdim#else 146353944Sdimstatic int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, 147353944Sdim void *data) { 148353944Sdim VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", 149353944Sdim info->dlpi_name, info->dlpi_addr); 150353944Sdim 151353944Sdim // Continue until the first dynamic library is found 152353944Sdim if (!info->dlpi_name || info->dlpi_name[0] == 0) 153353944Sdim return 0; 154353944Sdim 155353944Sdim // Ignore vDSO 156353944Sdim if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) 157353944Sdim return 0; 158353944Sdim 159353944Sdim#if SANITIZER_FREEBSD || SANITIZER_NETBSD 160353944Sdim // Ignore first entry (the main program) 161353944Sdim char **p = (char **)data; 162353944Sdim if (!(*p)) { 163353944Sdim *p = (char *)-1; 164353944Sdim return 0; 165353944Sdim } 166353944Sdim#endif 167353944Sdim 168353944Sdim#if SANITIZER_SOLARIS 169353944Sdim // Ignore executable on Solaris 170353944Sdim if (info->dlpi_addr == 0) 171353944Sdim return 0; 172353944Sdim#endif 173353944Sdim 174353944Sdim *(const char **)data = info->dlpi_name; 175353944Sdim return 1; 176353944Sdim} 177353944Sdim 178353944Sdimstatic bool IsDynamicRTName(const char *libname) { 179353944Sdim return internal_strstr(libname, "libclang_rt.asan") || 180353944Sdim internal_strstr(libname, "libasan.so"); 181353944Sdim} 182353944Sdim 183353944Sdimstatic void ReportIncompatibleRT() { 184353944Sdim Report("Your application is linked against incompatible ASan runtimes.\n"); 185353944Sdim Die(); 186353944Sdim} 187353944Sdim 188353944Sdimvoid AsanCheckDynamicRTPrereqs() { 189353944Sdim if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) 190353944Sdim return; 191353944Sdim 192353944Sdim // Ensure that dynamic RT is the first DSO in the list 193353944Sdim const char *first_dso_name = nullptr; 194353944Sdim dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); 195353944Sdim if (first_dso_name && !IsDynamicRTName(first_dso_name)) { 196353944Sdim Report("ASan runtime does not come first in initial library list; " 197353944Sdim "you should either link runtime to your application or " 198353944Sdim "manually preload it with LD_PRELOAD.\n"); 199353944Sdim Die(); 200353944Sdim } 201353944Sdim} 202353944Sdim 203353944Sdimvoid AsanCheckIncompatibleRT() { 204353944Sdim if (ASAN_DYNAMIC) { 205353944Sdim if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 206353944Sdim __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; 207353944Sdim } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { 208353944Sdim ReportIncompatibleRT(); 209353944Sdim } 210353944Sdim } else { 211353944Sdim if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { 212353944Sdim // Ensure that dynamic runtime is not present. We should detect it 213353944Sdim // as early as possible, otherwise ASan interceptors could bind to 214353944Sdim // the functions in dynamic ASan runtime instead of the functions in 215353944Sdim // system libraries, causing crashes later in ASan initialization. 216353944Sdim MemoryMappingLayout proc_maps(/*cache_enabled*/true); 217353944Sdim char filename[PATH_MAX]; 218353944Sdim MemoryMappedSegment segment(filename, sizeof(filename)); 219353944Sdim while (proc_maps.Next(&segment)) { 220353944Sdim if (IsDynamicRTName(segment.filename)) { 221353944Sdim Report("Your application is linked against " 222353944Sdim "incompatible ASan runtimes.\n"); 223353944Sdim Die(); 224353944Sdim } 225353944Sdim } 226353944Sdim __asan_rt_version = ASAN_RT_VERSION_STATIC; 227353944Sdim } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { 228353944Sdim ReportIncompatibleRT(); 229353944Sdim } 230353944Sdim } 231353944Sdim} 232353944Sdim#endif // SANITIZER_ANDROID 233353944Sdim 234353944Sdim#if !SANITIZER_ANDROID 235353944Sdimvoid ReadContextStack(void *context, uptr *stack, uptr *ssize) { 236353944Sdim ucontext_t *ucp = (ucontext_t*)context; 237353944Sdim *stack = (uptr)ucp->uc_stack.ss_sp; 238353944Sdim *ssize = ucp->uc_stack.ss_size; 239353944Sdim} 240353944Sdim#else 241353944Sdimvoid ReadContextStack(void *context, uptr *stack, uptr *ssize) { 242353944Sdim UNIMPLEMENTED(); 243353944Sdim} 244353944Sdim#endif 245353944Sdim 246353944Sdimvoid *AsanDlSymNext(const char *sym) { 247353944Sdim return dlsym(RTLD_NEXT, sym); 248353944Sdim} 249353944Sdim 250353944Sdimbool HandleDlopenInit() { 251353944Sdim // Not supported on this platform. 252353944Sdim static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 253353944Sdim "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 254353944Sdim return false; 255353944Sdim} 256353944Sdim 257353944Sdim} // namespace __asan 258353944Sdim 259353944Sdim#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || 260353944Sdim // SANITIZER_SOLARIS 261