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
ProtectGap(uptr addr,uptr size)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
PrintRange(uptr start,uptr end,const char * name)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
PrintAddressSpaceLayout()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
GetHighMemEnd()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
InitializeShadowBaseAddress(uptr shadow_size_bytes)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
MaybeDieIfNoTaggingAbi(const char * message)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
CanUseTaggingAbi()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
EnableTaggingAbi()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
InitializeOsSupport()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
InitShadow()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
InitThreads()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
MemIsApp(uptr p)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
InstallAtExitHandler()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
HwasanTSDThreadInit()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
HwasanTSDDtor(void * tsd)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
HwasanTSDInit()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
HwasanTSDInit()3360b57cec5SDimitry Andric void HwasanTSDInit() {}
HwasanTSDThreadInit()3370b57cec5SDimitry Andric void HwasanTSDThreadInit() {}
3380b57cec5SDimitry Andric # endif
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andric # if SANITIZER_ANDROID
GetCurrentThreadLongPtr()341349cc55cSDimitry Andric uptr *GetCurrentThreadLongPtr() { return (uptr *)get_android_tls_ptr(); }
3420b57cec5SDimitry Andric # else
GetCurrentThreadLongPtr()343349cc55cSDimitry Andric uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }
3440b57cec5SDimitry Andric # endif
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric # if SANITIZER_ANDROID
AndroidTestTlsSlot()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
AndroidTestTlsSlot()3620b57cec5SDimitry Andric void AndroidTestTlsSlot() {}
3630b57cec5SDimitry Andric # endif
3640b57cec5SDimitry Andric
GetAccessInfo(siginfo_t * info,ucontext_t * uc)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
HwasanOnSIGTRAP(int signo,siginfo_t * info,ucontext_t * uc)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
OnStackUnwind(const SignalContext & sig,const void *,BufferedStackTrace * stack)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
HwasanOnDeadlySignal(int signo,void * info,void * context)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
InitStackAndTls(const InitState *)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
TagMemoryAligned(uptr p,uptr size,tag_t tag)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
BeforeFork()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
AfterFork(bool fork_child)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
HwasanInstallAtForkHandler()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
InstallAtExitCheckLeaks()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
__hwasan_thread_enter()5775f757f3fSDimitry Andric extern "C" void __hwasan_thread_enter() {
5785f757f3fSDimitry Andric hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited();
5795f757f3fSDimitry Andric }
5805f757f3fSDimitry Andric
__hwasan_thread_exit()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