xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_posix.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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 
1781ad6265SDimitry Andric #  include <pthread.h>
1881ad6265SDimitry Andric #  include <signal.h>
1981ad6265SDimitry Andric #  include <stdlib.h>
2081ad6265SDimitry Andric #  include <sys/resource.h>
2181ad6265SDimitry Andric #  include <sys/time.h>
2281ad6265SDimitry Andric #  include <unistd.h>
2381ad6265SDimitry Andric 
2468d75effSDimitry Andric #  include "asan_interceptors.h"
2581ad6265SDimitry Andric #  include "asan_internal.h"
2668d75effSDimitry Andric #  include "asan_mapping.h"
275ffd83dbSDimitry Andric #  include "asan_poisoning.h"
2868d75effSDimitry Andric #  include "asan_report.h"
2968d75effSDimitry Andric #  include "asan_stack.h"
3081ad6265SDimitry Andric #  include "lsan/lsan_common.h"
3168d75effSDimitry Andric #  include "sanitizer_common/sanitizer_libc.h"
3268d75effSDimitry Andric #  include "sanitizer_common/sanitizer_posix.h"
3368d75effSDimitry Andric #  include "sanitizer_common/sanitizer_procmaps.h"
3468d75effSDimitry Andric 
3568d75effSDimitry Andric namespace __asan {
3668d75effSDimitry Andric 
3768d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
3868d75effSDimitry Andric   StartReportDeadlySignal();
3968d75effSDimitry Andric   SignalContext sig(siginfo, context);
4068d75effSDimitry Andric   ReportDeadlySignal(sig);
4168d75effSDimitry Andric }
4268d75effSDimitry Andric 
435ffd83dbSDimitry Andric bool PlatformUnpoisonStacks() {
445ffd83dbSDimitry Andric   stack_t signal_stack;
455ffd83dbSDimitry Andric   CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
465ffd83dbSDimitry Andric   uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
475ffd83dbSDimitry Andric   uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
485ffd83dbSDimitry Andric   // If we're executing on the signal alternate stack AND the Linux flag
495ffd83dbSDimitry Andric   // SS_AUTODISARM was used, then we cannot get the signal alternate stack
505ffd83dbSDimitry Andric   // bounds from sigaltstack -- sigaltstack's output looks just as if no
515ffd83dbSDimitry Andric   // alternate stack has ever been set up.
525ffd83dbSDimitry Andric   // We're always unpoisoning the signal alternate stack to support jumping
535ffd83dbSDimitry Andric   // between the default stack and signal alternate stack.
545ffd83dbSDimitry Andric   if (signal_stack.ss_flags != SS_DISABLE)
555ffd83dbSDimitry Andric     UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
565ffd83dbSDimitry Andric 
575ffd83dbSDimitry Andric   if (signal_stack.ss_flags != SS_ONSTACK)
585ffd83dbSDimitry Andric     return false;
595ffd83dbSDimitry Andric 
60fe6060f1SDimitry Andric   // Since we're on the signal alternate stack, we cannot find the DEFAULT
615ffd83dbSDimitry Andric   // stack bottom using a local variable.
625ffd83dbSDimitry Andric   uptr default_bottom, tls_addr, tls_size, stack_size;
635ffd83dbSDimitry Andric   GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
645ffd83dbSDimitry Andric                        &tls_size);
655ffd83dbSDimitry Andric   UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
665ffd83dbSDimitry Andric   return true;
675ffd83dbSDimitry Andric }
685ffd83dbSDimitry Andric 
6968d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1
7068d75effSDimitry Andric 
7168d75effSDimitry Andric #if SANITIZER_NETBSD && !ASAN_DYNAMIC
7268d75effSDimitry Andric // Thread Static Data cannot be used in early static ASan init on NetBSD.
7368d75effSDimitry Andric // Reuse the Asan TSD API for compatibility with existing code
7468d75effSDimitry Andric // with an alternative implementation.
7568d75effSDimitry Andric 
7668d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr;
7768d75effSDimitry Andric 
7868d75effSDimitry Andric struct tsd_key {
7968d75effSDimitry Andric   tsd_key() : key(nullptr) {}
8068d75effSDimitry Andric   ~tsd_key() {
8168d75effSDimitry Andric     CHECK(tsd_destructor);
8268d75effSDimitry Andric     if (key)
8368d75effSDimitry Andric       (*tsd_destructor)(key);
8468d75effSDimitry Andric   }
8568d75effSDimitry Andric   void *key;
8668d75effSDimitry Andric };
8768d75effSDimitry Andric 
8868d75effSDimitry Andric static thread_local struct tsd_key key;
8968d75effSDimitry Andric 
9068d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
9168d75effSDimitry Andric   CHECK(!tsd_destructor);
9268d75effSDimitry Andric   tsd_destructor = destructor;
9368d75effSDimitry Andric }
9468d75effSDimitry Andric 
9568d75effSDimitry Andric void *AsanTSDGet() {
9668d75effSDimitry Andric   CHECK(tsd_destructor);
9768d75effSDimitry Andric   return key.key;
9868d75effSDimitry Andric }
9968d75effSDimitry Andric 
10068d75effSDimitry Andric void AsanTSDSet(void *tsd) {
10168d75effSDimitry Andric   CHECK(tsd_destructor);
10268d75effSDimitry Andric   CHECK(tsd);
10368d75effSDimitry Andric   CHECK(!key.key);
10468d75effSDimitry Andric   key.key = tsd;
10568d75effSDimitry Andric }
10668d75effSDimitry Andric 
10768d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
10868d75effSDimitry Andric   CHECK(tsd_destructor);
10968d75effSDimitry Andric   CHECK_EQ(key.key, tsd);
11068d75effSDimitry Andric   key.key = nullptr;
11168d75effSDimitry Andric   // Make sure that signal handler can not see a stale current thread pointer.
11268d75effSDimitry Andric   atomic_signal_fence(memory_order_seq_cst);
11368d75effSDimitry Andric   AsanThread::TSDDtor(tsd);
11468d75effSDimitry Andric }
11568d75effSDimitry Andric #else
11668d75effSDimitry Andric static pthread_key_t tsd_key;
11768d75effSDimitry Andric static bool tsd_key_inited = false;
11868d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
11968d75effSDimitry Andric   CHECK(!tsd_key_inited);
12068d75effSDimitry Andric   tsd_key_inited = true;
12168d75effSDimitry Andric   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
12268d75effSDimitry Andric }
12368d75effSDimitry Andric 
12468d75effSDimitry Andric void *AsanTSDGet() {
12568d75effSDimitry Andric   CHECK(tsd_key_inited);
12668d75effSDimitry Andric   return pthread_getspecific(tsd_key);
12768d75effSDimitry Andric }
12868d75effSDimitry Andric 
12968d75effSDimitry Andric void AsanTSDSet(void *tsd) {
13068d75effSDimitry Andric   CHECK(tsd_key_inited);
13168d75effSDimitry Andric   pthread_setspecific(tsd_key, tsd);
13268d75effSDimitry Andric }
13368d75effSDimitry Andric 
13468d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
13568d75effSDimitry Andric   AsanThreadContext *context = (AsanThreadContext *)tsd;
13668d75effSDimitry Andric   if (context->destructor_iterations > 1) {
13768d75effSDimitry Andric     context->destructor_iterations--;
13868d75effSDimitry Andric     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
13968d75effSDimitry Andric     return;
14068d75effSDimitry Andric   }
1415f757f3fSDimitry Andric #    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
1425f757f3fSDimitry Andric         SANITIZER_SOLARIS
1435f757f3fSDimitry Andric   // After this point it's unsafe to execute signal handlers which may be
1445f757f3fSDimitry Andric   // instrumented. It's probably not just a Linux issue.
1455f757f3fSDimitry Andric   BlockSignals();
1465f757f3fSDimitry Andric #    endif
14768d75effSDimitry Andric   AsanThread::TSDDtor(tsd);
14868d75effSDimitry Andric }
14968d75effSDimitry Andric #  endif
15081ad6265SDimitry Andric 
151*cb14a3feSDimitry Andric static void BeforeFork() {
1525f757f3fSDimitry Andric   if (CAN_SANITIZE_LEAKS) {
1535f757f3fSDimitry Andric     __lsan::LockGlobal();
1545f757f3fSDimitry Andric   }
1555f757f3fSDimitry Andric   // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
1565f757f3fSDimitry Andric   // stuff we need.
1575f757f3fSDimitry Andric   __lsan::LockThreads();
1585f757f3fSDimitry Andric   __lsan::LockAllocator();
159*cb14a3feSDimitry Andric   StackDepotLockBeforeFork();
160*cb14a3feSDimitry Andric }
161*cb14a3feSDimitry Andric 
162*cb14a3feSDimitry Andric static void AfterFork(bool fork_child) {
163*cb14a3feSDimitry Andric   StackDepotUnlockAfterFork(fork_child);
1645f757f3fSDimitry Andric   // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
1655f757f3fSDimitry Andric   // the stuff we need.
1665f757f3fSDimitry Andric   __lsan::UnlockAllocator();
1675f757f3fSDimitry Andric   __lsan::UnlockThreads();
1685f757f3fSDimitry Andric   if (CAN_SANITIZE_LEAKS) {
1695f757f3fSDimitry Andric     __lsan::UnlockGlobal();
1705f757f3fSDimitry Andric   }
171*cb14a3feSDimitry Andric }
172*cb14a3feSDimitry Andric 
173*cb14a3feSDimitry Andric void InstallAtForkHandler() {
174*cb14a3feSDimitry Andric #  if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE
175*cb14a3feSDimitry Andric   return;  // FIXME: Implement FutexWait.
176*cb14a3feSDimitry Andric #  endif
177*cb14a3feSDimitry Andric   pthread_atfork(
178*cb14a3feSDimitry Andric       &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
179*cb14a3feSDimitry Andric       []() { AfterFork(/* fork_child= */ true); });
1805f757f3fSDimitry Andric }
1815f757f3fSDimitry Andric 
18281ad6265SDimitry Andric void InstallAtExitCheckLeaks() {
18381ad6265SDimitry Andric   if (CAN_SANITIZE_LEAKS) {
18481ad6265SDimitry Andric     if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
18581ad6265SDimitry Andric       if (flags()->halt_on_error)
18681ad6265SDimitry Andric         Atexit(__lsan::DoLeakCheck);
18781ad6265SDimitry Andric       else
18881ad6265SDimitry Andric         Atexit(__lsan::DoRecoverableLeakCheckVoid);
18981ad6265SDimitry Andric     }
19081ad6265SDimitry Andric   }
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric 
19368d75effSDimitry Andric }  // namespace __asan
19468d75effSDimitry Andric 
19568d75effSDimitry Andric #endif  // SANITIZER_POSIX
196