xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_posix.cpp (revision 43a5ec4eb41567cc92586503212743d89686d78f)
1 //===-- asan_posix.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of AddressSanitizer, an address sanity checker.
10 //
11 // Posix-specific details.
12 //===----------------------------------------------------------------------===//
13 
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_POSIX
16 
17 #include "asan_internal.h"
18 #include "asan_interceptors.h"
19 #include "asan_mapping.h"
20 #include "asan_poisoning.h"
21 #include "asan_report.h"
22 #include "asan_stack.h"
23 #include "sanitizer_common/sanitizer_libc.h"
24 #include "sanitizer_common/sanitizer_posix.h"
25 #include "sanitizer_common/sanitizer_procmaps.h"
26 
27 #include <pthread.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <sys/time.h>
31 #include <sys/resource.h>
32 #include <unistd.h>
33 
34 namespace __asan {
35 
36 void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
37   StartReportDeadlySignal();
38   SignalContext sig(siginfo, context);
39   ReportDeadlySignal(sig);
40 }
41 
42 bool PlatformUnpoisonStacks() {
43   stack_t signal_stack;
44   CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
45   uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
46   uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
47   // If we're executing on the signal alternate stack AND the Linux flag
48   // SS_AUTODISARM was used, then we cannot get the signal alternate stack
49   // bounds from sigaltstack -- sigaltstack's output looks just as if no
50   // alternate stack has ever been set up.
51   // We're always unpoisoning the signal alternate stack to support jumping
52   // between the default stack and signal alternate stack.
53   if (signal_stack.ss_flags != SS_DISABLE)
54     UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
55 
56   if (signal_stack.ss_flags != SS_ONSTACK)
57     return false;
58 
59   // Since we're on the signal alternate stack, we cannot find the DEFAULT
60   // stack bottom using a local variable.
61   uptr default_bottom, tls_addr, tls_size, stack_size;
62   GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
63                        &tls_size);
64   UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
65   return true;
66 }
67 
68 // ---------------------- TSD ---------------- {{{1
69 
70 #if SANITIZER_NETBSD && !ASAN_DYNAMIC
71 // Thread Static Data cannot be used in early static ASan init on NetBSD.
72 // Reuse the Asan TSD API for compatibility with existing code
73 // with an alternative implementation.
74 
75 static void (*tsd_destructor)(void *tsd) = nullptr;
76 
77 struct tsd_key {
78   tsd_key() : key(nullptr) {}
79   ~tsd_key() {
80     CHECK(tsd_destructor);
81     if (key)
82       (*tsd_destructor)(key);
83   }
84   void *key;
85 };
86 
87 static thread_local struct tsd_key key;
88 
89 void AsanTSDInit(void (*destructor)(void *tsd)) {
90   CHECK(!tsd_destructor);
91   tsd_destructor = destructor;
92 }
93 
94 void *AsanTSDGet() {
95   CHECK(tsd_destructor);
96   return key.key;
97 }
98 
99 void AsanTSDSet(void *tsd) {
100   CHECK(tsd_destructor);
101   CHECK(tsd);
102   CHECK(!key.key);
103   key.key = tsd;
104 }
105 
106 void PlatformTSDDtor(void *tsd) {
107   CHECK(tsd_destructor);
108   CHECK_EQ(key.key, tsd);
109   key.key = nullptr;
110   // Make sure that signal handler can not see a stale current thread pointer.
111   atomic_signal_fence(memory_order_seq_cst);
112   AsanThread::TSDDtor(tsd);
113 }
114 #else
115 static pthread_key_t tsd_key;
116 static bool tsd_key_inited = false;
117 void AsanTSDInit(void (*destructor)(void *tsd)) {
118   CHECK(!tsd_key_inited);
119   tsd_key_inited = true;
120   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
121 }
122 
123 void *AsanTSDGet() {
124   CHECK(tsd_key_inited);
125   return pthread_getspecific(tsd_key);
126 }
127 
128 void AsanTSDSet(void *tsd) {
129   CHECK(tsd_key_inited);
130   pthread_setspecific(tsd_key, tsd);
131 }
132 
133 void PlatformTSDDtor(void *tsd) {
134   AsanThreadContext *context = (AsanThreadContext*)tsd;
135   if (context->destructor_iterations > 1) {
136     context->destructor_iterations--;
137     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
138     return;
139   }
140   AsanThread::TSDDtor(tsd);
141 }
142 #endif
143 }  // namespace __asan
144 
145 #endif  // SANITIZER_POSIX
146