xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan_linux.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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