diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -223,12 +223,28 @@ list(APPEND RUNTIME_BUILD_ID_LINK "${target}-unknown-fuchsia") endforeach() - set(LLVM_RUNTIME_MULTILIBS "asan;noexcept;asan+noexcept;relative-vtables;relative-vtables+noexcept" CACHE STRING "") + # HWAsan + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan_LLVM_BUILD_COMPILER_RT OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan_LLVM_USE_SANITIZER "HWAddress" CACHE STRING "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") + + # HWASan+noexcept + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LLVM_BUILD_COMPILER_RT OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LLVM_USE_SANITIZER "HWAddress" CACHE STRING "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "") + set(RUNTIMES_aarch64-unknown-fuchsia+hwasan+noexcept_LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "") + + set(LLVM_RUNTIME_MULTILIBS "asan;noexcept;asan+noexcept;relative-vtables;relative-vtables+noexcept;hwasan;hwasan+noexcept" CACHE STRING "") set(LLVM_RUNTIME_MULTILIB_asan_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "") set(LLVM_RUNTIME_MULTILIB_noexcept_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "") set(LLVM_RUNTIME_MULTILIB_asan+noexcept_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "") set(LLVM_RUNTIME_MULTILIB_relative-vtables_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "") set(LLVM_RUNTIME_MULTILIB_relative-vtables+noexcept_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "") + set(LLVM_RUNTIME_MULTILIB_hwasan_TARGETS "aarch64-unknown-fuchsia" CACHE STRING "") + set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia" CACHE STRING "") endif() set(LLVM_BUILTIN_TARGETS "${BUILTIN_TARGETS}" CACHE STRING "") diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -97,6 +97,8 @@ Dyld += "asan/"; if (SanArgs.needsTsanRt() && SanArgs.needsSharedRt()) Dyld += "tsan/"; + if (SanArgs.needsHwasanRt() && SanArgs.needsSharedRt()) + Dyld += "hwasan/"; Dyld += "ld.so.1"; CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Dyld)); @@ -217,6 +219,14 @@ .flag("+fexperimental-relative-c++-abi-vtables") .flag("-fexceptions") .flag("+fno-exceptions")); + // ASan has higher priority because we always want the instrumentated version. + Multilibs.push_back(Multilib("hwasan", {}, {}, 6) + .flag("+fsanitize=hwaddress")); + // Use the asan+noexcept variant with ASan and -fno-exceptions. + Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 7) + .flag("+fsanitize=hwaddress") + .flag("-fexceptions") + .flag("+fno-exceptions")); Multilibs.FilterOut([&](const Multilib &M) { std::vector RD = FilePaths(M); return std::all_of(RD.begin(), RD.end(), [&](std::string P) { @@ -229,6 +239,7 @@ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), "fexceptions", Flags); addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags); + addMultilibFlag(getSanitizerArgs().needsHwasanRt(), "fsanitize=hwaddress", Flags); addMultilibFlag( Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables, @@ -358,6 +369,7 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::HWAddress; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -701,7 +701,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND HWASAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|Android") + OS_NAME MATCHES "Linux|Android|Fuchsia") set(COMPILER_RT_HAS_HWASAN TRUE) else() set(COMPILER_RT_HAS_HWASAN FALSE) diff --git a/compiler-rt/lib/hwasan/CMakeLists.txt b/compiler-rt/lib/hwasan/CMakeLists.txt --- a/compiler-rt/lib/hwasan/CMakeLists.txt +++ b/compiler-rt/lib/hwasan/CMakeLists.txt @@ -6,6 +6,7 @@ hwasan_allocator.cpp hwasan_dynamic_shadow.cpp hwasan_exceptions.cpp + hwasan_fuchsia.cpp hwasan_globals.cpp hwasan_interceptors.cpp hwasan_interceptors_vfork.S @@ -41,7 +42,11 @@ ) set(HWASAN_DEFINITIONS) -append_list_if(COMPILER_RT_HWASAN_WITH_INTERCEPTORS HWASAN_WITH_INTERCEPTORS=1 HWASAN_DEFINITIONS) +if (NOT FUCHSIA) + append_list_if(COMPILER_RT_HWASAN_WITH_INTERCEPTORS HWASAN_WITH_INTERCEPTORS=1 HWASAN_DEFINITIONS) +else() + list(APPEND HWASAN_DEFINITIONS HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE=1) +endif() set(HWASAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(OFF HWASAN_RTL_CFLAGS) diff --git a/compiler-rt/lib/hwasan/hwasan_dynamic_shadow.cpp b/compiler-rt/lib/hwasan/hwasan_dynamic_shadow.cpp --- a/compiler-rt/lib/hwasan/hwasan_dynamic_shadow.cpp +++ b/compiler-rt/lib/hwasan/hwasan_dynamic_shadow.cpp @@ -16,7 +16,9 @@ #include "hwasan_dynamic_shadow.h" #include "hwasan_mapping.h" #include "sanitizer_common/sanitizer_common.h" +#if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" +#endif #include #include @@ -111,6 +113,14 @@ } } // namespace __hwasan +#elif SANITIZER_FUCHSIA + +namespace __hwasan { + +void InitShadowGOT() {} + +} // namespace __hwasan + #else namespace __hwasan { diff --git a/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp b/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp @@ -0,0 +1,176 @@ +//===-- hwasan_fuchsia.cpp --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer and contains Fuchsia-specific +/// code. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include "hwasan.h" +#include "hwasan_interface_internal.h" +#include "hwasan_thread.h" +#include "hwasan_report.h" +#include "hwasan_thread_list.h" + +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL uptr __hwasan_tls; + +namespace __hwasan { + +uptr kHighMemEnd; +uptr kHighMemBeg; + +bool InitShadow() { + __hwasan_shadow_memory_dynamic_address = 0; + + // This initializes __sanitizer::ShadowBounds. + kHighMemEnd = GetMaxUserVirtualAddress(); + kHighMemBeg = __sanitizer::ShadowBounds.shadow_limit; + + CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1); + CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit); + CHECK_NE(kHighMemBeg, 0); + + return true; +} + +void InitThreads() { + uptr alloc_size = UINT64_C(1) << kShadowBaseAlignment; + uptr thread_start = reinterpret_cast( + MmapAlignedOrDieOnFatalError(alloc_size, alloc_size, __func__)); + InitThreadList(thread_start, thread_start + alloc_size); +} + +void InitPrctl() {} + +bool MemIsApp(uptr p) { + CHECK(GetTagFromPointer(p) == 0); + return kHighMemBeg <= p && p <= kHighMemEnd; +} + +void InstallAtExitHandler() {} + +// ---------------------- TSD ---------------- {{{ + +extern "C" void __hwasan_thread_enter() { + hwasanThreadList().CreateCurrentThread()->InitRandomState(); +} + +extern "C" void __hwasan_thread_exit() { + Thread *t = GetCurrentThread(); + // Make sure that signal handler can not see a stale current thread pointer. + atomic_signal_fence(memory_order_seq_cst); + if (t) + hwasanThreadList().ReleaseThread(t); +} + +extern "C" +void __sanitizer_thread_start_hook(void *hook, thrd_t self) { + __hwasan_thread_enter(); +} + +extern "C" +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { + __hwasan_thread_exit(); +} + +void HwasanTSDInit() {} +void HwasanTSDThreadInit() {} + +static THREADLOCAL uptr __hwasan_tls; + +uptr *GetCurrentThreadLongPtr() { + return &__hwasan_tls; +} + +void AndroidTestTlsSlot() {} + +Thread *GetCurrentThread() { + uptr *ThreadLongPtr = GetCurrentThreadLongPtr(); + if (UNLIKELY(*ThreadLongPtr == 0)) + return nullptr; + auto *R = (StackAllocationsRingBuffer *)ThreadLongPtr; + return hwasanThreadList().GetThreadByBufferAddress((uptr)R->Next()); +} + +struct AccessInfo { + uptr addr; + uptr size; + bool is_store; + bool is_load; + bool recover; +}; + +static void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, + uptr *registers_frame = nullptr) { + InternalMmapVector stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + stack->Unwind(pc, frame, /*context=*/nullptr, common_flags()->fast_unwind_on_fatal); + + // The second stack frame contains the failure __hwasan_check function, as + // we have a stack frame for the registers saved in __hwasan_tag_mismatch that + // we wish to ignore. This (currently) only occurs on AArch64, as x64 + // implementations use SIGTRAP to implement the failure, and thus do not go + // through the stack saver. + if (registers_frame && stack->trace && stack->size > 0) { + stack->trace++; + stack->size--; + } + + bool fatal = flags()->halt_on_error || !ai.recover; + ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal, + registers_frame); +} + +// TODO: We check if this is set in __hwasan_tag_mismatch4 before diagnosing a +// tag mismatch to cover for cases where we have instrumented code that checks +// global pointers, but HWASan hasn't been setup yet. We should go back and see +// if this is the right way to handle checks against globals before HWASan +// initialization. +extern int hwasan_inited; + +// Entry point stub for interoperability between __hwasan_tag_mismatch (ASM) and +// the rest of the mismatch handling code (C++). +extern "C" void __hwasan_tag_mismatch4(uptr addr, uptr access_info, + uptr *registers_frame, size_t outsize) { + if (!hwasan_inited) + return; + + __hwasan::AccessInfo ai; + ai.is_store = access_info & 0x10; + ai.is_load = !ai.is_store; + ai.recover = access_info & 0x20; + ai.addr = addr; + if ((access_info & 0xf) == 0xf) + ai.size = outsize; + else + ai.size = 1 << (access_info & 0xf); + + HandleTagMismatch(ai, (uptr)__builtin_return_address(0), + (uptr)__builtin_frame_address(0), + registers_frame); + __builtin_unreachable(); +} + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); +} + +// TODO: Do we need this? +void HwasanOnDeadlySignal(int signo, void *info, void *context) {} + +} // namespace __hwasan + +#endif // SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -21,7 +21,12 @@ #include "hwasan_thread.h" #include "hwasan_poisoning.h" #include "hwasan_report.h" +#if SANITIZER_FUCHSIA +#include "sanitizer_common/sanitizer_platform_limits_fuchsia.h" +#endif +#if SANITIZER_POSIX #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#endif #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_allocator_internal.h" @@ -304,6 +309,7 @@ #endif // HWASAN_WITH_INTERCEPTORS && __aarch64__ +#if HWASAN_WITH_INTERCEPTORS static void BeforeFork() { StackDepotLockAll(); } @@ -319,6 +325,7 @@ AfterFork(); return pid; } +#endif // HWASAN_WITH_INTERCEPTORS namespace __hwasan { @@ -335,9 +342,9 @@ static int inited = 0; CHECK_EQ(inited, 0); +#if HWASAN_WITH_INTERCEPTORS INTERCEPT_FUNCTION(fork); -#if HWASAN_WITH_INTERCEPTORS #if defined(__linux__) INTERCEPT_FUNCTION(vfork); #endif // __linux__ diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h --- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -15,7 +15,12 @@ #define HWASAN_INTERFACE_INTERNAL_H #include "sanitizer_common/sanitizer_internal_defs.h" +#if SANITIZER_FUCHSIA +#include "sanitizer_common/sanitizer_platform_limits_fuchsia.h" +#endif +#if SANITIZER_POSIX #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#endif #include extern "C" { diff --git a/compiler-rt/lib/hwasan/hwasan_new_delete.cpp b/compiler-rt/lib/hwasan/hwasan_new_delete.cpp --- a/compiler-rt/lib/hwasan/hwasan_new_delete.cpp +++ b/compiler-rt/lib/hwasan/hwasan_new_delete.cpp @@ -50,6 +50,7 @@ // Fake std::nothrow_t to avoid including . namespace std { struct nothrow_t {}; + enum class align_val_t: size_t {}; } // namespace std @@ -66,6 +67,14 @@ void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } @@ -77,5 +86,9 @@ void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void operator delete[](void* ptr, std::align_val_t) NOEXCEPT { OPERATOR_DELETE_BODY; } #endif // OPERATOR_NEW_BODY diff --git a/compiler-rt/lib/hwasan/hwasan_poisoning.cpp b/compiler-rt/lib/hwasan/hwasan_poisoning.cpp --- a/compiler-rt/lib/hwasan/hwasan_poisoning.cpp +++ b/compiler-rt/lib/hwasan/hwasan_poisoning.cpp @@ -22,6 +22,10 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { CHECK(IsAligned(p, kShadowAlignment)); CHECK(IsAligned(size, kShadowAlignment)); +#if SANITIZER_FUCHSIA + __sanitizer_fill_shadow(p, size, tag, + common_flags()->clear_shadow_mmap_threshold); +#else uptr shadow_start = MemToShadow(p); uptr shadow_size = MemToShadowSize(size); @@ -40,6 +44,7 @@ } else { internal_memset((void *)shadow_start, tag, shadow_size); } +#endif return AddTagToPointer(p, tag); } diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -51,12 +51,18 @@ // ScopedTaggingDisable needs GetCurrentThread to be set up. ScopedTaggingDisabler disabler; +#if !SANITIZER_FUCHSIA uptr tls_size; uptr stack_size; GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_, &tls_size); stack_top_ = stack_bottom_ + stack_size; tls_end_ = tls_begin_ + tls_size; +#else + __sanitizer::GetThreadStackTopAndBottom(true, &stack_top_, + &stack_bottom_); + tls_end_ = tls_begin_ = 0; +#endif if (stack_bottom_) { int local; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_fuchsia.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_fuchsia.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_fuchsia.h @@ -0,0 +1,25 @@ +//===-- sanitizer_platform_limits_fuchsia.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific Fuchsia data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_FUCHSIA_H +#define SANITIZER_PLATFORM_LIMITS_FUCHSIA_H + +#if SANITIZER_FUCHSIA + +namespace __sanitizer { +struct __sanitizer_struct_mallinfo {}; +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA + +#endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -54,6 +54,11 @@ return false; } +// TODO: We should also have an offline implementation. This function was +// initially undefined when building hwasan. It's probably just because no one +// used this until now that we didn't see this before. +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; } + // This is used in some places for suppression checking, which we // don't really support for Fuchsia. It's also used in UBSan to // identify a PC location to a function name, so we always fill in diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -1510,7 +1510,11 @@ void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) { Scale = kDefaultShadowScale; - if (ClMappingOffset.getNumOccurrences() > 0) { + if (TargetTriple.isOSFuchsia()) { + InGlobal = false; + InTls = false; + Offset = 0; + } else if (ClMappingOffset.getNumOccurrences() > 0) { InGlobal = false; InTls = false; Offset = ClMappingOffset;