xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_posix.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
168d75effSDimitry Andric //===-- asan_posix.cpp ----------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Posix-specific details.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
1568d75effSDimitry Andric #if SANITIZER_POSIX
1668d75effSDimitry Andric 
1768d75effSDimitry Andric #include "asan_internal.h"
1868d75effSDimitry Andric #include "asan_interceptors.h"
1968d75effSDimitry Andric #include "asan_mapping.h"
20*5ffd83dbSDimitry Andric #include "asan_poisoning.h"
2168d75effSDimitry Andric #include "asan_report.h"
2268d75effSDimitry Andric #include "asan_stack.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_posix.h"
2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h"
2668d75effSDimitry Andric 
2768d75effSDimitry Andric #include <pthread.h>
28*5ffd83dbSDimitry Andric #include <signal.h>
2968d75effSDimitry Andric #include <stdlib.h>
3068d75effSDimitry Andric #include <sys/time.h>
3168d75effSDimitry Andric #include <sys/resource.h>
3268d75effSDimitry Andric #include <unistd.h>
3368d75effSDimitry Andric 
3468d75effSDimitry Andric namespace __asan {
3568d75effSDimitry Andric 
3668d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
3768d75effSDimitry Andric   StartReportDeadlySignal();
3868d75effSDimitry Andric   SignalContext sig(siginfo, context);
3968d75effSDimitry Andric   ReportDeadlySignal(sig);
4068d75effSDimitry Andric }
4168d75effSDimitry Andric 
42*5ffd83dbSDimitry Andric bool PlatformUnpoisonStacks() {
43*5ffd83dbSDimitry Andric   stack_t signal_stack;
44*5ffd83dbSDimitry Andric   CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
45*5ffd83dbSDimitry Andric   uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
46*5ffd83dbSDimitry Andric   uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
47*5ffd83dbSDimitry Andric   // If we're executing on the signal alternate stack AND the Linux flag
48*5ffd83dbSDimitry Andric   // SS_AUTODISARM was used, then we cannot get the signal alternate stack
49*5ffd83dbSDimitry Andric   // bounds from sigaltstack -- sigaltstack's output looks just as if no
50*5ffd83dbSDimitry Andric   // alternate stack has ever been set up.
51*5ffd83dbSDimitry Andric   // We're always unpoisoning the signal alternate stack to support jumping
52*5ffd83dbSDimitry Andric   // between the default stack and signal alternate stack.
53*5ffd83dbSDimitry Andric   if (signal_stack.ss_flags != SS_DISABLE)
54*5ffd83dbSDimitry Andric     UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
55*5ffd83dbSDimitry Andric 
56*5ffd83dbSDimitry Andric   if (signal_stack.ss_flags != SS_ONSTACK)
57*5ffd83dbSDimitry Andric     return false;
58*5ffd83dbSDimitry Andric 
59*5ffd83dbSDimitry Andric   // Since we're on the signal altnerate stack, we cannot find the DEFAULT
60*5ffd83dbSDimitry Andric   // stack bottom using a local variable.
61*5ffd83dbSDimitry Andric   uptr default_bottom, tls_addr, tls_size, stack_size;
62*5ffd83dbSDimitry Andric   GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
63*5ffd83dbSDimitry Andric                        &tls_size);
64*5ffd83dbSDimitry Andric   UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
65*5ffd83dbSDimitry Andric   return true;
66*5ffd83dbSDimitry Andric }
67*5ffd83dbSDimitry Andric 
6868d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1
6968d75effSDimitry Andric 
7068d75effSDimitry Andric #if SANITIZER_NETBSD && !ASAN_DYNAMIC
7168d75effSDimitry Andric // Thread Static Data cannot be used in early static ASan init on NetBSD.
7268d75effSDimitry Andric // Reuse the Asan TSD API for compatibility with existing code
7368d75effSDimitry Andric // with an alternative implementation.
7468d75effSDimitry Andric 
7568d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr;
7668d75effSDimitry Andric 
7768d75effSDimitry Andric struct tsd_key {
7868d75effSDimitry Andric   tsd_key() : key(nullptr) {}
7968d75effSDimitry Andric   ~tsd_key() {
8068d75effSDimitry Andric     CHECK(tsd_destructor);
8168d75effSDimitry Andric     if (key)
8268d75effSDimitry Andric       (*tsd_destructor)(key);
8368d75effSDimitry Andric   }
8468d75effSDimitry Andric   void *key;
8568d75effSDimitry Andric };
8668d75effSDimitry Andric 
8768d75effSDimitry Andric static thread_local struct tsd_key key;
8868d75effSDimitry Andric 
8968d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
9068d75effSDimitry Andric   CHECK(!tsd_destructor);
9168d75effSDimitry Andric   tsd_destructor = destructor;
9268d75effSDimitry Andric }
9368d75effSDimitry Andric 
9468d75effSDimitry Andric void *AsanTSDGet() {
9568d75effSDimitry Andric   CHECK(tsd_destructor);
9668d75effSDimitry Andric   return key.key;
9768d75effSDimitry Andric }
9868d75effSDimitry Andric 
9968d75effSDimitry Andric void AsanTSDSet(void *tsd) {
10068d75effSDimitry Andric   CHECK(tsd_destructor);
10168d75effSDimitry Andric   CHECK(tsd);
10268d75effSDimitry Andric   CHECK(!key.key);
10368d75effSDimitry Andric   key.key = tsd;
10468d75effSDimitry Andric }
10568d75effSDimitry Andric 
10668d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
10768d75effSDimitry Andric   CHECK(tsd_destructor);
10868d75effSDimitry Andric   CHECK_EQ(key.key, tsd);
10968d75effSDimitry Andric   key.key = nullptr;
11068d75effSDimitry Andric   // Make sure that signal handler can not see a stale current thread pointer.
11168d75effSDimitry Andric   atomic_signal_fence(memory_order_seq_cst);
11268d75effSDimitry Andric   AsanThread::TSDDtor(tsd);
11368d75effSDimitry Andric }
11468d75effSDimitry Andric #else
11568d75effSDimitry Andric static pthread_key_t tsd_key;
11668d75effSDimitry Andric static bool tsd_key_inited = false;
11768d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
11868d75effSDimitry Andric   CHECK(!tsd_key_inited);
11968d75effSDimitry Andric   tsd_key_inited = true;
12068d75effSDimitry Andric   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
12168d75effSDimitry Andric }
12268d75effSDimitry Andric 
12368d75effSDimitry Andric void *AsanTSDGet() {
12468d75effSDimitry Andric   CHECK(tsd_key_inited);
12568d75effSDimitry Andric   return pthread_getspecific(tsd_key);
12668d75effSDimitry Andric }
12768d75effSDimitry Andric 
12868d75effSDimitry Andric void AsanTSDSet(void *tsd) {
12968d75effSDimitry Andric   CHECK(tsd_key_inited);
13068d75effSDimitry Andric   pthread_setspecific(tsd_key, tsd);
13168d75effSDimitry Andric }
13268d75effSDimitry Andric 
13368d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
13468d75effSDimitry Andric   AsanThreadContext *context = (AsanThreadContext*)tsd;
13568d75effSDimitry Andric   if (context->destructor_iterations > 1) {
13668d75effSDimitry Andric     context->destructor_iterations--;
13768d75effSDimitry Andric     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
13868d75effSDimitry Andric     return;
13968d75effSDimitry Andric   }
14068d75effSDimitry Andric   AsanThread::TSDDtor(tsd);
14168d75effSDimitry Andric }
14268d75effSDimitry Andric #endif
14368d75effSDimitry Andric }  // namespace __asan
14468d75effSDimitry Andric 
14568d75effSDimitry Andric #endif  // SANITIZER_POSIX
146