10b57cec5SDimitry Andric //===-- hwasan_linux.cpp ----------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file is a part of HWAddressSanitizer and contains Linux-, NetBSD- and 110b57cec5SDimitry Andric /// FreeBSD-specific code. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 160b57cec5SDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 170b57cec5SDimitry Andric 18349cc55cSDimitry Andric # include <dlfcn.h> 19349cc55cSDimitry Andric # include <elf.h> 20349cc55cSDimitry Andric # include <errno.h> 21349cc55cSDimitry Andric # include <link.h> 22349cc55cSDimitry Andric # include <pthread.h> 23349cc55cSDimitry Andric # include <signal.h> 24349cc55cSDimitry Andric # include <stdio.h> 25349cc55cSDimitry Andric # include <stdlib.h> 26349cc55cSDimitry Andric # include <sys/prctl.h> 27349cc55cSDimitry Andric # include <sys/resource.h> 28349cc55cSDimitry Andric # include <sys/time.h> 29349cc55cSDimitry Andric # include <unistd.h> 30349cc55cSDimitry Andric # include <unwind.h> 31349cc55cSDimitry Andric 320b57cec5SDimitry Andric # include "hwasan.h" 330b57cec5SDimitry Andric # include "hwasan_dynamic_shadow.h" 340b57cec5SDimitry Andric # include "hwasan_interface_internal.h" 350b57cec5SDimitry Andric # include "hwasan_mapping.h" 360b57cec5SDimitry Andric # include "hwasan_report.h" 370b57cec5SDimitry Andric # include "hwasan_thread.h" 380b57cec5SDimitry Andric # include "hwasan_thread_list.h" 390b57cec5SDimitry Andric # include "sanitizer_common/sanitizer_common.h" 400b57cec5SDimitry Andric # include "sanitizer_common/sanitizer_procmaps.h" 41349cc55cSDimitry Andric # include "sanitizer_common/sanitizer_stackdepot.h" 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric // Configurations of HWASAN_WITH_INTERCEPTORS and SANITIZER_ANDROID. 440b57cec5SDimitry Andric // 450b57cec5SDimitry Andric // HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=OFF 460b57cec5SDimitry Andric // Not currently tested. 470b57cec5SDimitry Andric // HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=ON 480b57cec5SDimitry Andric // Integration tests downstream exist. 490b57cec5SDimitry Andric // HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=OFF 500b57cec5SDimitry Andric // Tested with check-hwasan on x86_64-linux. 510b57cec5SDimitry Andric // HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=ON 520b57cec5SDimitry Andric // Tested with check-hwasan on aarch64-linux-android. 530b57cec5SDimitry Andric # if !SANITIZER_ANDROID 540b57cec5SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 550b57cec5SDimitry Andric THREADLOCAL uptr __hwasan_tls; 560b57cec5SDimitry Andric # endif 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric namespace __hwasan { 590b57cec5SDimitry Andric 60e8d8bef9SDimitry Andric // With the zero shadow base we can not actually map pages starting from 0. 61e8d8bef9SDimitry Andric // This constant is somewhat arbitrary. 62e8d8bef9SDimitry Andric constexpr uptr kZeroBaseShadowStart = 0; 63e8d8bef9SDimitry Andric constexpr uptr kZeroBaseMaxShadowStart = 1 << 18; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric static void ProtectGap(uptr addr, uptr size) { 66e8d8bef9SDimitry Andric __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart, 67e8d8bef9SDimitry Andric kZeroBaseMaxShadowStart); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 70e8d8bef9SDimitry Andric uptr kLowMemStart; 71e8d8bef9SDimitry Andric uptr kLowMemEnd; 72e8d8bef9SDimitry Andric uptr kHighMemStart; 73e8d8bef9SDimitry Andric uptr kHighMemEnd; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric static void PrintRange(uptr start, uptr end, const char *name) { 760b57cec5SDimitry Andric Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric static void PrintAddressSpaceLayout() { 800b57cec5SDimitry Andric PrintRange(kHighMemStart, kHighMemEnd, "HighMem"); 810b57cec5SDimitry Andric if (kHighShadowEnd + 1 < kHighMemStart) 820b57cec5SDimitry Andric PrintRange(kHighShadowEnd + 1, kHighMemStart - 1, "ShadowGap"); 830b57cec5SDimitry Andric else 840b57cec5SDimitry Andric CHECK_EQ(kHighShadowEnd + 1, kHighMemStart); 850b57cec5SDimitry Andric PrintRange(kHighShadowStart, kHighShadowEnd, "HighShadow"); 860b57cec5SDimitry Andric if (kLowShadowEnd + 1 < kHighShadowStart) 870b57cec5SDimitry Andric PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap"); 880b57cec5SDimitry Andric else 890b57cec5SDimitry Andric CHECK_EQ(kLowMemEnd + 1, kHighShadowStart); 900b57cec5SDimitry Andric PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow"); 910b57cec5SDimitry Andric if (kLowMemEnd + 1 < kLowShadowStart) 920b57cec5SDimitry Andric PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap"); 930b57cec5SDimitry Andric else 940b57cec5SDimitry Andric CHECK_EQ(kLowMemEnd + 1, kLowShadowStart); 950b57cec5SDimitry Andric PrintRange(kLowMemStart, kLowMemEnd, "LowMem"); 960b57cec5SDimitry Andric CHECK_EQ(0, kLowMemStart); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric static uptr GetHighMemEnd() { 1000b57cec5SDimitry Andric // HighMem covers the upper part of the address space. 1010b57cec5SDimitry Andric uptr max_address = GetMaxUserVirtualAddress(); 1020b57cec5SDimitry Andric // Adjust max address to make sure that kHighMemEnd and kHighMemStart are 1030b57cec5SDimitry Andric // properly aligned: 1040b57cec5SDimitry Andric max_address |= (GetMmapGranularity() << kShadowScale) - 1; 1050b57cec5SDimitry Andric return max_address; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { 109*0fca6ea1SDimitry Andric // FIXME: Android should init flags before shadow. 110*0fca6ea1SDimitry Andric if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) { 1115f757f3fSDimitry Andric __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base; 112*0fca6ea1SDimitry Andric uptr beg = __hwasan_shadow_memory_dynamic_address; 113*0fca6ea1SDimitry Andric uptr end = beg + shadow_size_bytes; 114*0fca6ea1SDimitry Andric if (!MemoryRangeIsAvailable(beg, end)) { 115*0fca6ea1SDimitry Andric Report( 116*0fca6ea1SDimitry Andric "FATAL: HWAddressSanitizer: Shadow range %p-%p is not available.\n", 117*0fca6ea1SDimitry Andric (void *)beg, (void *)end); 118*0fca6ea1SDimitry Andric DumpProcessMap(); 119*0fca6ea1SDimitry Andric CHECK(MemoryRangeIsAvailable(beg, end)); 120*0fca6ea1SDimitry Andric } 1215f757f3fSDimitry Andric } else { 1220b57cec5SDimitry Andric __hwasan_shadow_memory_dynamic_address = 1230b57cec5SDimitry Andric FindDynamicShadowStart(shadow_size_bytes); 1240b57cec5SDimitry Andric } 1255f757f3fSDimitry Andric } 1260b57cec5SDimitry Andric 127bdd1243dSDimitry Andric static void MaybeDieIfNoTaggingAbi(const char *message) { 128bdd1243dSDimitry Andric if (!flags()->fail_without_syscall_abi) 129bdd1243dSDimitry Andric return; 130bdd1243dSDimitry Andric Printf("FATAL: %s\n", message); 131bdd1243dSDimitry Andric Die(); 132bdd1243dSDimitry Andric } 133bdd1243dSDimitry Andric 13468d75effSDimitry Andric # define PR_SET_TAGGED_ADDR_CTRL 55 13568d75effSDimitry Andric # define PR_GET_TAGGED_ADDR_CTRL 56 13668d75effSDimitry Andric # define PR_TAGGED_ADDR_ENABLE (1UL << 0) 137753f127fSDimitry Andric # define ARCH_GET_UNTAG_MASK 0x4001 138753f127fSDimitry Andric # define ARCH_ENABLE_TAGGED_ADDR 0x4002 139bdd1243dSDimitry Andric # define ARCH_GET_MAX_TAG_BITS 0x4003 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric static bool CanUseTaggingAbi() { 142753f127fSDimitry Andric # if defined(__x86_64__) 143bdd1243dSDimitry Andric unsigned long num_bits = 0; 144bdd1243dSDimitry Andric // Check for x86 LAM support. This API is based on a currently unsubmitted 145bdd1243dSDimitry Andric // patch to the Linux kernel (as of August 2022) and is thus subject to 146bdd1243dSDimitry Andric // change. The patch is here: 147bdd1243dSDimitry Andric // https://lore.kernel.org/all/20220815041803.17954-1-kirill.shutemov@linux.intel.com/ 148bdd1243dSDimitry Andric // 149bdd1243dSDimitry Andric // arch_prctl(ARCH_GET_MAX_TAG_BITS, &bits) returns the maximum number of tag 150bdd1243dSDimitry Andric // bits the user can request, or zero if LAM is not supported by the hardware. 151bdd1243dSDimitry Andric if (internal_iserror(internal_arch_prctl(ARCH_GET_MAX_TAG_BITS, 152bdd1243dSDimitry Andric reinterpret_cast<uptr>(&num_bits)))) 153bdd1243dSDimitry Andric return false; 154bdd1243dSDimitry Andric // The platform must provide enough bits for HWASan tags. 155bdd1243dSDimitry Andric if (num_bits < kTagBits) 156bdd1243dSDimitry Andric return false; 157bdd1243dSDimitry Andric return true; 158753f127fSDimitry Andric # else 159bdd1243dSDimitry Andric // Check for ARM TBI support. 160bdd1243dSDimitry Andric return !internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)); 161bdd1243dSDimitry Andric # endif // __x86_64__ 162bdd1243dSDimitry Andric } 163bdd1243dSDimitry Andric 164bdd1243dSDimitry Andric static bool EnableTaggingAbi() { 165bdd1243dSDimitry Andric # if defined(__x86_64__) 166bdd1243dSDimitry Andric // Enable x86 LAM tagging for the process. 167bdd1243dSDimitry Andric // 168bdd1243dSDimitry Andric // arch_prctl(ARCH_ENABLE_TAGGED_ADDR, bits) enables tagging if the number of 169bdd1243dSDimitry Andric // tag bits requested by the user does not exceed that provided by the system. 170bdd1243dSDimitry Andric // arch_prctl(ARCH_GET_UNTAG_MASK, &mask) returns the mask of significant 171bdd1243dSDimitry Andric // address bits. It is ~0ULL if either LAM is disabled for the process or LAM 172bdd1243dSDimitry Andric // is not supported by the hardware. 173bdd1243dSDimitry Andric if (internal_iserror(internal_arch_prctl(ARCH_ENABLE_TAGGED_ADDR, kTagBits))) 174bdd1243dSDimitry Andric return false; 175bdd1243dSDimitry Andric unsigned long mask = 0; 176bdd1243dSDimitry Andric // Make sure the tag bits are where we expect them to be. 177bdd1243dSDimitry Andric if (internal_iserror(internal_arch_prctl(ARCH_GET_UNTAG_MASK, 178bdd1243dSDimitry Andric reinterpret_cast<uptr>(&mask)))) 179bdd1243dSDimitry Andric return false; 180bdd1243dSDimitry Andric // @mask has ones for non-tag bits, whereas @kAddressTagMask has ones for tag 181bdd1243dSDimitry Andric // bits. Therefore these masks must not overlap. 182bdd1243dSDimitry Andric if (mask & kAddressTagMask) 183bdd1243dSDimitry Andric return false; 184bdd1243dSDimitry Andric return true; 185bdd1243dSDimitry Andric # else 186bdd1243dSDimitry Andric // Enable ARM TBI tagging for the process. If for some reason tagging is not 187bdd1243dSDimitry Andric // supported, prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE) returns 188bdd1243dSDimitry Andric // -EINVAL. 189bdd1243dSDimitry Andric if (internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL, 190bdd1243dSDimitry Andric PR_TAGGED_ADDR_ENABLE, 0, 0, 0))) 191bdd1243dSDimitry Andric return false; 192bdd1243dSDimitry Andric // Ensure that TBI is enabled. 193bdd1243dSDimitry Andric if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) != 194bdd1243dSDimitry Andric PR_TAGGED_ADDR_ENABLE) 195bdd1243dSDimitry Andric return false; 196bdd1243dSDimitry Andric return true; 197bdd1243dSDimitry Andric # endif // __x86_64__ 198bdd1243dSDimitry Andric } 199bdd1243dSDimitry Andric 200bdd1243dSDimitry Andric void InitializeOsSupport() { 201bdd1243dSDimitry Andric // Check we're running on a kernel that can use the tagged address ABI. 202bdd1243dSDimitry Andric bool has_abi = CanUseTaggingAbi(); 203bdd1243dSDimitry Andric 204bdd1243dSDimitry Andric if (!has_abi) { 205fe6060f1SDimitry Andric # if SANITIZER_ANDROID || defined(HWASAN_ALIASING_MODE) 20668d75effSDimitry Andric // Some older Android kernels have the tagged pointer ABI on 20768d75effSDimitry Andric // unconditionally, and hence don't have the tagged-addr prctl while still 20868d75effSDimitry Andric // allow the ABI. 20968d75effSDimitry Andric // If targeting Android and the prctl is not around we assume this is the 21068d75effSDimitry Andric // case. 21168d75effSDimitry Andric return; 21268d75effSDimitry Andric # else 213bdd1243dSDimitry Andric MaybeDieIfNoTaggingAbi( 214bdd1243dSDimitry Andric "HWAddressSanitizer requires a kernel with tagged address ABI."); 21568d75effSDimitry Andric # endif 21668d75effSDimitry Andric } 21768d75effSDimitry Andric 218bdd1243dSDimitry Andric if (EnableTaggingAbi()) 219fe6060f1SDimitry Andric return; 220bdd1243dSDimitry Andric 221bdd1243dSDimitry Andric # if SANITIZER_ANDROID 222bdd1243dSDimitry Andric MaybeDieIfNoTaggingAbi( 223bdd1243dSDimitry Andric "HWAddressSanitizer failed to enable tagged address syscall ABI.\n" 224bdd1243dSDimitry Andric "Check the `sysctl abi.tagged_addr_disabled` configuration."); 225bdd1243dSDimitry Andric # else 226bdd1243dSDimitry Andric MaybeDieIfNoTaggingAbi( 227bdd1243dSDimitry Andric "HWAddressSanitizer failed to enable tagged address syscall ABI.\n"); 228bdd1243dSDimitry Andric # endif 22968d75effSDimitry Andric } 23068d75effSDimitry Andric 2310b57cec5SDimitry Andric bool InitShadow() { 2320b57cec5SDimitry Andric // Define the entire memory range. 2330b57cec5SDimitry Andric kHighMemEnd = GetHighMemEnd(); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Determine shadow memory base offset. 2360b57cec5SDimitry Andric InitializeShadowBaseAddress(MemToShadowSize(kHighMemEnd)); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric // Place the low memory first. 2390b57cec5SDimitry Andric kLowMemEnd = __hwasan_shadow_memory_dynamic_address - 1; 2400b57cec5SDimitry Andric kLowMemStart = 0; 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // Define the low shadow based on the already placed low memory. 2430b57cec5SDimitry Andric kLowShadowEnd = MemToShadow(kLowMemEnd); 2440b57cec5SDimitry Andric kLowShadowStart = __hwasan_shadow_memory_dynamic_address; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // High shadow takes whatever memory is left up there (making sure it is not 2470b57cec5SDimitry Andric // interfering with low memory in the fixed case). 2480b57cec5SDimitry Andric kHighShadowEnd = MemToShadow(kHighMemEnd); 2490b57cec5SDimitry Andric kHighShadowStart = Max(kLowMemEnd, MemToShadow(kHighShadowEnd)) + 1; 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // High memory starts where allocated shadow allows. 2520b57cec5SDimitry Andric kHighMemStart = ShadowToMem(kHighShadowStart); 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // Check the sanity of the defined memory ranges (there might be gaps). 2550b57cec5SDimitry Andric CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0); 2560b57cec5SDimitry Andric CHECK_GT(kHighMemStart, kHighShadowEnd); 2570b57cec5SDimitry Andric CHECK_GT(kHighShadowEnd, kHighShadowStart); 2580b57cec5SDimitry Andric CHECK_GT(kHighShadowStart, kLowMemEnd); 2590b57cec5SDimitry Andric CHECK_GT(kLowMemEnd, kLowMemStart); 2600b57cec5SDimitry Andric CHECK_GT(kLowShadowEnd, kLowShadowStart); 2610b57cec5SDimitry Andric CHECK_GT(kLowShadowStart, kLowMemEnd); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric // Reserve shadow memory. 2640b57cec5SDimitry Andric ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd, "low shadow"); 2650b57cec5SDimitry Andric ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd, "high shadow"); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric // Protect all the gaps. 2680b57cec5SDimitry Andric ProtectGap(0, Min(kLowMemStart, kLowShadowStart)); 2690b57cec5SDimitry Andric if (kLowMemEnd + 1 < kLowShadowStart) 2700b57cec5SDimitry Andric ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1); 2710b57cec5SDimitry Andric if (kLowShadowEnd + 1 < kHighShadowStart) 2720b57cec5SDimitry Andric ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1); 2730b57cec5SDimitry Andric if (kHighShadowEnd + 1 < kHighMemStart) 2740b57cec5SDimitry Andric ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1); 2750b57cec5SDimitry Andric 276*0fca6ea1SDimitry Andric if (Verbosity()) 277*0fca6ea1SDimitry Andric PrintAddressSpaceLayout(); 278*0fca6ea1SDimitry Andric 2790b57cec5SDimitry Andric return true; 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric void InitThreads() { 2830b57cec5SDimitry Andric CHECK(__hwasan_shadow_memory_dynamic_address); 2840b57cec5SDimitry Andric uptr guard_page_size = GetMmapGranularity(); 2850b57cec5SDimitry Andric uptr thread_space_start = 2860b57cec5SDimitry Andric __hwasan_shadow_memory_dynamic_address - (1ULL << kShadowBaseAlignment); 2870b57cec5SDimitry Andric uptr thread_space_end = 2880b57cec5SDimitry Andric __hwasan_shadow_memory_dynamic_address - guard_page_size; 2890b57cec5SDimitry Andric ReserveShadowMemoryRange(thread_space_start, thread_space_end - 1, 290e8d8bef9SDimitry Andric "hwasan threads", /*madvise_shadow*/ false); 2910b57cec5SDimitry Andric ProtectGap(thread_space_end, 2920b57cec5SDimitry Andric __hwasan_shadow_memory_dynamic_address - thread_space_end); 2930b57cec5SDimitry Andric InitThreadList(thread_space_start, thread_space_end - thread_space_start); 294fe6060f1SDimitry Andric hwasanThreadList().CreateCurrentThread(); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric bool MemIsApp(uptr p) { 298fe6060f1SDimitry Andric // Memory outside the alias range has non-zero tags. 299fe6060f1SDimitry Andric # if !defined(HWASAN_ALIASING_MODE) 30006c3fb27SDimitry Andric CHECK_EQ(GetTagFromPointer(p), 0); 301fe6060f1SDimitry Andric # endif 3020b57cec5SDimitry Andric 303349cc55cSDimitry Andric return (p >= kHighMemStart && p <= kHighMemEnd) || 304349cc55cSDimitry Andric (p >= kLowMemStart && p <= kLowMemEnd); 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric 307349cc55cSDimitry Andric void InstallAtExitHandler() { atexit(HwasanAtExit); } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric // ---------------------- TSD ---------------- {{{1 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric # if HWASAN_WITH_INTERCEPTORS 3120b57cec5SDimitry Andric static pthread_key_t tsd_key; 3130b57cec5SDimitry Andric static bool tsd_key_inited = false; 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric void HwasanTSDThreadInit() { 3160b57cec5SDimitry Andric if (tsd_key_inited) 3170b57cec5SDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, 3180b57cec5SDimitry Andric (void *)GetPthreadDestructorIterations())); 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric void HwasanTSDDtor(void *tsd) { 3220b57cec5SDimitry Andric uptr iterations = (uptr)tsd; 3230b57cec5SDimitry Andric if (iterations > 1) { 3240b57cec5SDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, (void *)(iterations - 1))); 3250b57cec5SDimitry Andric return; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric __hwasan_thread_exit(); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric void HwasanTSDInit() { 3310b57cec5SDimitry Andric CHECK(!tsd_key_inited); 3320b57cec5SDimitry Andric tsd_key_inited = true; 3330b57cec5SDimitry Andric CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor)); 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric # else 3360b57cec5SDimitry Andric void HwasanTSDInit() {} 3370b57cec5SDimitry Andric void HwasanTSDThreadInit() {} 3380b57cec5SDimitry Andric # endif 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric # if SANITIZER_ANDROID 341349cc55cSDimitry Andric uptr *GetCurrentThreadLongPtr() { return (uptr *)get_android_tls_ptr(); } 3420b57cec5SDimitry Andric # else 343349cc55cSDimitry Andric uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; } 3440b57cec5SDimitry Andric # endif 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric # if SANITIZER_ANDROID 3470b57cec5SDimitry Andric void AndroidTestTlsSlot() { 3480b57cec5SDimitry Andric uptr kMagicValue = 0x010203040A0B0C0D; 3490b57cec5SDimitry Andric uptr *tls_ptr = GetCurrentThreadLongPtr(); 3500b57cec5SDimitry Andric uptr old_value = *tls_ptr; 3510b57cec5SDimitry Andric *tls_ptr = kMagicValue; 3520b57cec5SDimitry Andric dlerror(); 3530b57cec5SDimitry Andric if (*(uptr *)get_android_tls_ptr() != kMagicValue) { 3540b57cec5SDimitry Andric Printf( 3550b57cec5SDimitry Andric "ERROR: Incompatible version of Android: TLS_SLOT_SANITIZER(6) is used " 3560b57cec5SDimitry Andric "for dlerror().\n"); 3570b57cec5SDimitry Andric Die(); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric *tls_ptr = old_value; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric # else 3620b57cec5SDimitry Andric void AndroidTestTlsSlot() {} 3630b57cec5SDimitry Andric # endif 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { 3660b57cec5SDimitry Andric // Access type is passed in a platform dependent way (see below) and encoded 3670b57cec5SDimitry Andric // as 0xXY, where X&1 is 1 for store, 0 for load, and X&2 is 1 if the error is 3680b57cec5SDimitry Andric // recoverable. Valid values of Y are 0 to 4, which are interpreted as 3690b57cec5SDimitry Andric // log2(access_size), and 0xF, which means that access size is passed via 3700b57cec5SDimitry Andric // platform dependent register (see below). 3710b57cec5SDimitry Andric # if defined(__aarch64__) 3720b57cec5SDimitry Andric // Access type is encoded in BRK immediate as 0x900 + 0xXY. For Y == 0xF, 3730b57cec5SDimitry Andric // access size is stored in X1 register. Access address is always in X0 3740b57cec5SDimitry Andric // register. 3750b57cec5SDimitry Andric uptr pc = (uptr)info->si_addr; 3760b57cec5SDimitry Andric const unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; 3770b57cec5SDimitry Andric if ((code & 0xff00) != 0x900) 3780b57cec5SDimitry Andric return AccessInfo{}; // Not ours. 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric const bool is_store = code & 0x10; 3810b57cec5SDimitry Andric const bool recover = code & 0x20; 3820b57cec5SDimitry Andric const uptr addr = uc->uc_mcontext.regs[0]; 3830b57cec5SDimitry Andric const unsigned size_log = code & 0xf; 3840b57cec5SDimitry Andric if (size_log > 4 && size_log != 0xf) 3850b57cec5SDimitry Andric return AccessInfo{}; // Not ours. 3860b57cec5SDimitry Andric const uptr size = size_log == 0xf ? uc->uc_mcontext.regs[1] : 1U << size_log; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric # elif defined(__x86_64__) 3890b57cec5SDimitry Andric // Access type is encoded in the instruction following INT3 as 3900b57cec5SDimitry Andric // NOP DWORD ptr [EAX + 0x40 + 0xXY]. For Y == 0xF, access size is stored in 3910b57cec5SDimitry Andric // RSI register. Access address is always in RDI register. 3920b57cec5SDimitry Andric uptr pc = (uptr)uc->uc_mcontext.gregs[REG_RIP]; 3930b57cec5SDimitry Andric uint8_t *nop = (uint8_t *)pc; 3940b57cec5SDimitry Andric if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || 3950b57cec5SDimitry Andric *(nop + 3) < 0x40) 3960b57cec5SDimitry Andric return AccessInfo{}; // Not ours. 3970b57cec5SDimitry Andric const unsigned code = *(nop + 3); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric const bool is_store = code & 0x10; 4000b57cec5SDimitry Andric const bool recover = code & 0x20; 4010b57cec5SDimitry Andric const uptr addr = uc->uc_mcontext.gregs[REG_RDI]; 4020b57cec5SDimitry Andric const unsigned size_log = code & 0xf; 4030b57cec5SDimitry Andric if (size_log > 4 && size_log != 0xf) 4040b57cec5SDimitry Andric return AccessInfo{}; // Not ours. 4050b57cec5SDimitry Andric const uptr size = 4060b57cec5SDimitry Andric size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; 4070b57cec5SDimitry Andric 408bdd1243dSDimitry Andric # elif SANITIZER_RISCV64 409bdd1243dSDimitry Andric // Access type is encoded in the instruction following EBREAK as 410bdd1243dSDimitry Andric // ADDI x0, x0, [0x40 + 0xXY]. For Y == 0xF, access size is stored in 411bdd1243dSDimitry Andric // X11 register. Access address is always in X10 register. 412bdd1243dSDimitry Andric uptr pc = (uptr)uc->uc_mcontext.__gregs[REG_PC]; 413bdd1243dSDimitry Andric uint8_t byte1 = *((u8 *)(pc + 0)); 414bdd1243dSDimitry Andric uint8_t byte2 = *((u8 *)(pc + 1)); 415bdd1243dSDimitry Andric uint8_t byte3 = *((u8 *)(pc + 2)); 416bdd1243dSDimitry Andric uint8_t byte4 = *((u8 *)(pc + 3)); 417bdd1243dSDimitry Andric uint32_t ebreak = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); 418bdd1243dSDimitry Andric bool isFaultShort = false; 419bdd1243dSDimitry Andric bool isEbreak = (ebreak == 0x100073); 420bdd1243dSDimitry Andric bool isShortEbreak = false; 421bdd1243dSDimitry Andric # if defined(__riscv_compressed) 422bdd1243dSDimitry Andric isFaultShort = ((ebreak & 0x3) != 0x3); 423bdd1243dSDimitry Andric isShortEbreak = ((ebreak & 0xffff) == 0x9002); 424bdd1243dSDimitry Andric # endif 425bdd1243dSDimitry Andric // faulted insn is not ebreak, not our case 426bdd1243dSDimitry Andric if (!(isEbreak || isShortEbreak)) 427bdd1243dSDimitry Andric return AccessInfo{}; 428bdd1243dSDimitry Andric // advance pc to point after ebreak and reconstruct addi instruction 429bdd1243dSDimitry Andric pc += isFaultShort ? 2 : 4; 430bdd1243dSDimitry Andric byte1 = *((u8 *)(pc + 0)); 431bdd1243dSDimitry Andric byte2 = *((u8 *)(pc + 1)); 432bdd1243dSDimitry Andric byte3 = *((u8 *)(pc + 2)); 433bdd1243dSDimitry Andric byte4 = *((u8 *)(pc + 3)); 434bdd1243dSDimitry Andric // reconstruct instruction 435bdd1243dSDimitry Andric uint32_t instr = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); 436bdd1243dSDimitry Andric // check if this is really 32 bit instruction 437bdd1243dSDimitry Andric // code is encoded in top 12 bits, since instruction is supposed to be with 438bdd1243dSDimitry Andric // imm 439bdd1243dSDimitry Andric const unsigned code = (instr >> 20) & 0xffff; 440bdd1243dSDimitry Andric const uptr addr = uc->uc_mcontext.__gregs[10]; 441bdd1243dSDimitry Andric const bool is_store = code & 0x10; 442bdd1243dSDimitry Andric const bool recover = code & 0x20; 443bdd1243dSDimitry Andric const unsigned size_log = code & 0xf; 444bdd1243dSDimitry Andric if (size_log > 4 && size_log != 0xf) 445bdd1243dSDimitry Andric return AccessInfo{}; // Not our case 446bdd1243dSDimitry Andric const uptr size = 447bdd1243dSDimitry Andric size_log == 0xf ? uc->uc_mcontext.__gregs[11] : 1U << size_log; 448bdd1243dSDimitry Andric 4490b57cec5SDimitry Andric # else 4500b57cec5SDimitry Andric # error Unsupported architecture 4510b57cec5SDimitry Andric # endif 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric return AccessInfo{addr, size, is_store, !is_store, recover}; 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) { 4570b57cec5SDimitry Andric AccessInfo ai = GetAccessInfo(info, uc); 4580b57cec5SDimitry Andric if (!ai.is_store && !ai.is_load) 4590b57cec5SDimitry Andric return false; 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric SignalContext sig{info, uc}; 4620b57cec5SDimitry Andric HandleTagMismatch(ai, StackTrace::GetNextInstructionPc(sig.pc), sig.bp, uc); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric # if defined(__aarch64__) 4650b57cec5SDimitry Andric uc->uc_mcontext.pc += 4; 4660b57cec5SDimitry Andric # elif defined(__x86_64__) 467bdd1243dSDimitry Andric # elif SANITIZER_RISCV64 468bdd1243dSDimitry Andric // pc points to EBREAK which is 2 bytes long 469bdd1243dSDimitry Andric uint8_t *exception_source = (uint8_t *)(uc->uc_mcontext.__gregs[REG_PC]); 470bdd1243dSDimitry Andric uint8_t byte1 = (uint8_t)(*(exception_source + 0)); 471bdd1243dSDimitry Andric uint8_t byte2 = (uint8_t)(*(exception_source + 1)); 472bdd1243dSDimitry Andric uint8_t byte3 = (uint8_t)(*(exception_source + 2)); 473bdd1243dSDimitry Andric uint8_t byte4 = (uint8_t)(*(exception_source + 3)); 474bdd1243dSDimitry Andric uint32_t faulted = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); 475bdd1243dSDimitry Andric bool isFaultShort = false; 476bdd1243dSDimitry Andric # if defined(__riscv_compressed) 477bdd1243dSDimitry Andric isFaultShort = ((faulted & 0x3) != 0x3); 478bdd1243dSDimitry Andric # endif 479bdd1243dSDimitry Andric uc->uc_mcontext.__gregs[REG_PC] += isFaultShort ? 2 : 4; 4800b57cec5SDimitry Andric # else 4810b57cec5SDimitry Andric # error Unsupported architecture 4820b57cec5SDimitry Andric # endif 4830b57cec5SDimitry Andric return true; 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric static void OnStackUnwind(const SignalContext &sig, const void *, 4870b57cec5SDimitry Andric BufferedStackTrace *stack) { 4880b57cec5SDimitry Andric stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, 4890b57cec5SDimitry Andric common_flags()->fast_unwind_on_fatal); 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric void HwasanOnDeadlySignal(int signo, void *info, void *context) { 4930b57cec5SDimitry Andric // Probably a tag mismatch. 4940b57cec5SDimitry Andric if (signo == SIGTRAP) 4950b57cec5SDimitry Andric if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t *)context)) 4960b57cec5SDimitry Andric return; 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric HandleDeadlySignal(info, context, GetTid(), &OnStackUnwind, nullptr); 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 501fe6060f1SDimitry Andric void Thread::InitStackAndTls(const InitState *) { 502fe6060f1SDimitry Andric uptr tls_size; 503fe6060f1SDimitry Andric uptr stack_size; 504fe6060f1SDimitry Andric GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_, 505fe6060f1SDimitry Andric &tls_size); 506fe6060f1SDimitry Andric stack_top_ = stack_bottom_ + stack_size; 507fe6060f1SDimitry Andric tls_end_ = tls_begin_ + tls_size; 508fe6060f1SDimitry Andric } 509fe6060f1SDimitry Andric 510fe6060f1SDimitry Andric uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { 511fe6060f1SDimitry Andric CHECK(IsAligned(p, kShadowAlignment)); 512fe6060f1SDimitry Andric CHECK(IsAligned(size, kShadowAlignment)); 513fe6060f1SDimitry Andric uptr shadow_start = MemToShadow(p); 514fe6060f1SDimitry Andric uptr shadow_size = MemToShadowSize(size); 515fe6060f1SDimitry Andric 516fe6060f1SDimitry Andric uptr page_size = GetPageSizeCached(); 517fe6060f1SDimitry Andric uptr page_start = RoundUpTo(shadow_start, page_size); 518fe6060f1SDimitry Andric uptr page_end = RoundDownTo(shadow_start + shadow_size, page_size); 519fe6060f1SDimitry Andric uptr threshold = common_flags()->clear_shadow_mmap_threshold; 520fe6060f1SDimitry Andric if (SANITIZER_LINUX && 521fe6060f1SDimitry Andric UNLIKELY(page_end >= page_start + threshold && tag == 0)) { 522fe6060f1SDimitry Andric internal_memset((void *)shadow_start, tag, page_start - shadow_start); 523fe6060f1SDimitry Andric internal_memset((void *)page_end, tag, 524fe6060f1SDimitry Andric shadow_start + shadow_size - page_end); 525fe6060f1SDimitry Andric // For an anonymous private mapping MADV_DONTNEED will return a zero page on 526fe6060f1SDimitry Andric // Linux. 527fe6060f1SDimitry Andric ReleaseMemoryPagesToOSAndZeroFill(page_start, page_end); 528fe6060f1SDimitry Andric } else { 529fe6060f1SDimitry Andric internal_memset((void *)shadow_start, tag, shadow_size); 530fe6060f1SDimitry Andric } 531fe6060f1SDimitry Andric return AddTagToPointer(p, tag); 532fe6060f1SDimitry Andric } 5330b57cec5SDimitry Andric 534cb14a3feSDimitry Andric static void BeforeFork() { 5355f757f3fSDimitry Andric if (CAN_SANITIZE_LEAKS) { 5365f757f3fSDimitry Andric __lsan::LockGlobal(); 5375f757f3fSDimitry Andric } 5385f757f3fSDimitry Andric // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the 5395f757f3fSDimitry Andric // stuff we need. 5405f757f3fSDimitry Andric __lsan::LockThreads(); 5415f757f3fSDimitry Andric __lsan::LockAllocator(); 542cb14a3feSDimitry Andric StackDepotLockBeforeFork(); 543cb14a3feSDimitry Andric } 544cb14a3feSDimitry Andric 545cb14a3feSDimitry Andric static void AfterFork(bool fork_child) { 546cb14a3feSDimitry Andric StackDepotUnlockAfterFork(fork_child); 5475f757f3fSDimitry Andric // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock 5485f757f3fSDimitry Andric // the stuff we need. 5495f757f3fSDimitry Andric __lsan::UnlockAllocator(); 5505f757f3fSDimitry Andric __lsan::UnlockThreads(); 5515f757f3fSDimitry Andric if (CAN_SANITIZE_LEAKS) { 5525f757f3fSDimitry Andric __lsan::UnlockGlobal(); 5535f757f3fSDimitry Andric } 554cb14a3feSDimitry Andric } 555cb14a3feSDimitry Andric 556cb14a3feSDimitry Andric void HwasanInstallAtForkHandler() { 557cb14a3feSDimitry Andric pthread_atfork( 558cb14a3feSDimitry Andric &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, 559cb14a3feSDimitry Andric []() { AfterFork(/* fork_child= */ true); }); 560349cc55cSDimitry Andric } 561349cc55cSDimitry Andric 562bdd1243dSDimitry Andric void InstallAtExitCheckLeaks() { 563bdd1243dSDimitry Andric if (CAN_SANITIZE_LEAKS) { 564bdd1243dSDimitry Andric if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { 565bdd1243dSDimitry Andric if (flags()->halt_on_error) 566bdd1243dSDimitry Andric Atexit(__lsan::DoLeakCheck); 567bdd1243dSDimitry Andric else 568bdd1243dSDimitry Andric Atexit(__lsan::DoRecoverableLeakCheckVoid); 569bdd1243dSDimitry Andric } 570bdd1243dSDimitry Andric } 571bdd1243dSDimitry Andric } 572bdd1243dSDimitry Andric 5730b57cec5SDimitry Andric } // namespace __hwasan 5740b57cec5SDimitry Andric 5755f757f3fSDimitry Andric using namespace __hwasan; 5765f757f3fSDimitry Andric 5775f757f3fSDimitry Andric extern "C" void __hwasan_thread_enter() { 5785f757f3fSDimitry Andric hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited(); 5795f757f3fSDimitry Andric } 5805f757f3fSDimitry Andric 5815f757f3fSDimitry Andric extern "C" void __hwasan_thread_exit() { 5825f757f3fSDimitry Andric Thread *t = GetCurrentThread(); 5835f757f3fSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer. 5845f757f3fSDimitry Andric atomic_signal_fence(memory_order_seq_cst); 5855f757f3fSDimitry Andric if (t) { 5865f757f3fSDimitry Andric // Block async signals on the thread as the handler can be instrumented. 5875f757f3fSDimitry Andric // After this point instrumented code can't access essential data from TLS 5885f757f3fSDimitry Andric // and will crash. 5895f757f3fSDimitry Andric // Bionic already calls __hwasan_thread_exit with blocked signals. 5905f757f3fSDimitry Andric if (SANITIZER_GLIBC) 5915f757f3fSDimitry Andric BlockSignals(); 5925f757f3fSDimitry Andric hwasanThreadList().ReleaseThread(t); 5935f757f3fSDimitry Andric } 5945f757f3fSDimitry Andric } 5955f757f3fSDimitry Andric 5960b57cec5SDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 597