From 0a5450f8b2a2df38d0118319b3b0e274bf466d47 Mon Sep 17 00:00:00 2001 From: WANG Date: Sun, 3 Sep 2023 14:30:07 +0000 Subject: [PATCH 1/3] Code for maple asan runtime. --- src/mrt/libsan/.gitignore | 6 + src/mrt/libsan/CMakeLists.txt | 59 +++ src/mrt/libsan/asan/asan_alloctor.cpp | 300 ++++++++++++++ src/mrt/libsan/asan/asan_alloctor.h | 66 +++ src/mrt/libsan/asan/asan_avltree.cpp | 195 +++++++++ src/mrt/libsan/asan/asan_avltree.h | 65 +++ src/mrt/libsan/asan/asan_fake_stack.cpp | 38 ++ src/mrt/libsan/asan/asan_flags.cpp | 23 ++ src/mrt/libsan/asan/asan_flags.h | 28 ++ src/mrt/libsan/asan/asan_flags.inc | 169 ++++++++ src/mrt/libsan/asan/asan_interceptors.cpp | 63 +++ src/mrt/libsan/asan/asan_interceptors.h | 87 ++++ .../asan/asan_interceptors_memintrinsics.cpp | 68 ++++ .../asan/asan_interceptors_memintrinsics.h | 28 ++ src/mrt/libsan/asan/asan_interfaces.inc | 37 ++ .../libsan/asan/asan_interfaces_internal.h | 62 +++ src/mrt/libsan/asan/asan_internal.h | 33 ++ src/mrt/libsan/asan/asan_internal_defs.h | 158 +++++++ src/mrt/libsan/asan/asan_malloc_linux.cpp | 243 +++++++++++ src/mrt/libsan/asan/asan_mapping.cpp | 9 + src/mrt/libsan/asan/asan_mapping.h | 119 ++++++ src/mrt/libsan/asan/asan_poisoning.cpp | 33 ++ src/mrt/libsan/asan/asan_poisoning.h | 23 ++ src/mrt/libsan/asan/asan_report.cpp | 210 ++++++++++ src/mrt/libsan/asan/asan_report.h | 48 +++ src/mrt/libsan/asan/asan_rtl.cpp | 82 ++++ src/mrt/libsan/asan/asan_shadow_memory.cpp | 384 ++++++++++++++++++ src/mrt/libsan/asan/asan_shadow_memory.h | 48 +++ src/mrt/libsan/asan/asan_signal_handler.h | 49 +++ .../libsan/asan/asan_signal_handler_linux.cpp | 56 +++ src/mrt/libsan/asan/asan_stubs.cpp | 67 +++ src/mrt/libsan/asan/asan_stubs.h | 17 + src/mrt/libsan/asan/asan_thread.h | 38 ++ src/mrt/libsan/asan/asan_utils.h | 97 +++++ src/mrt/libsan/asan/common_flags.h | 38 ++ src/mrt/libsan/asan/sanitizer_flags.cpp | 20 + src/mrt/libsan/asan/sanitizer_flags.inc | 279 +++++++++++++ src/mrt/libsan/asan/sanitizer_libc.cpp | 374 +++++++++++++++++ src/mrt/libsan/asan/sanitizer_libc.h | 46 +++ .../libsan/asan/sanitizer_linux_syscall.cpp | 29 ++ src/mrt/libsan/asan/sanitizer_linux_syscall.h | 21 + .../asan/sanitizer_linux_syscall_NR_aarch64.h | 5 + src/mrt/libsan/asan/sanitizer_printf.cpp | 211 ++++++++++ src/mrt/libsan/asan/sanitizer_printf.h | 41 ++ src/mrt/libsan/asan/sanitizer_termination.cpp | 68 ++++ src/mrt/libsan/asan/sanitizer_termination.h | 18 + src/mrt/libsan/interception/interception.h | 90 ++++ .../interception/interception_linux.cpp | 38 ++ .../libsan/interception/interception_linux.h | 35 ++ 49 files changed, 4321 insertions(+) create mode 100644 src/mrt/libsan/.gitignore create mode 100644 src/mrt/libsan/CMakeLists.txt create mode 100644 src/mrt/libsan/asan/asan_alloctor.cpp create mode 100644 src/mrt/libsan/asan/asan_alloctor.h create mode 100644 src/mrt/libsan/asan/asan_avltree.cpp create mode 100644 src/mrt/libsan/asan/asan_avltree.h create mode 100644 src/mrt/libsan/asan/asan_fake_stack.cpp create mode 100644 src/mrt/libsan/asan/asan_flags.cpp create mode 100644 src/mrt/libsan/asan/asan_flags.h create mode 100644 src/mrt/libsan/asan/asan_flags.inc create mode 100644 src/mrt/libsan/asan/asan_interceptors.cpp create mode 100644 src/mrt/libsan/asan/asan_interceptors.h create mode 100644 src/mrt/libsan/asan/asan_interceptors_memintrinsics.cpp create mode 100644 src/mrt/libsan/asan/asan_interceptors_memintrinsics.h create mode 100644 src/mrt/libsan/asan/asan_interfaces.inc create mode 100644 src/mrt/libsan/asan/asan_interfaces_internal.h create mode 100644 src/mrt/libsan/asan/asan_internal.h create mode 100644 src/mrt/libsan/asan/asan_internal_defs.h create mode 100644 src/mrt/libsan/asan/asan_malloc_linux.cpp create mode 100644 src/mrt/libsan/asan/asan_mapping.cpp create mode 100644 src/mrt/libsan/asan/asan_mapping.h create mode 100644 src/mrt/libsan/asan/asan_poisoning.cpp create mode 100644 src/mrt/libsan/asan/asan_poisoning.h create mode 100644 src/mrt/libsan/asan/asan_report.cpp create mode 100644 src/mrt/libsan/asan/asan_report.h create mode 100644 src/mrt/libsan/asan/asan_rtl.cpp create mode 100644 src/mrt/libsan/asan/asan_shadow_memory.cpp create mode 100644 src/mrt/libsan/asan/asan_shadow_memory.h create mode 100644 src/mrt/libsan/asan/asan_signal_handler.h create mode 100644 src/mrt/libsan/asan/asan_signal_handler_linux.cpp create mode 100644 src/mrt/libsan/asan/asan_stubs.cpp create mode 100644 src/mrt/libsan/asan/asan_stubs.h create mode 100644 src/mrt/libsan/asan/asan_thread.h create mode 100644 src/mrt/libsan/asan/asan_utils.h create mode 100644 src/mrt/libsan/asan/common_flags.h create mode 100644 src/mrt/libsan/asan/sanitizer_flags.cpp create mode 100644 src/mrt/libsan/asan/sanitizer_flags.inc create mode 100644 src/mrt/libsan/asan/sanitizer_libc.cpp create mode 100644 src/mrt/libsan/asan/sanitizer_libc.h create mode 100644 src/mrt/libsan/asan/sanitizer_linux_syscall.cpp create mode 100644 src/mrt/libsan/asan/sanitizer_linux_syscall.h create mode 100644 src/mrt/libsan/asan/sanitizer_linux_syscall_NR_aarch64.h create mode 100644 src/mrt/libsan/asan/sanitizer_printf.cpp create mode 100644 src/mrt/libsan/asan/sanitizer_printf.h create mode 100644 src/mrt/libsan/asan/sanitizer_termination.cpp create mode 100644 src/mrt/libsan/asan/sanitizer_termination.h create mode 100644 src/mrt/libsan/interception/interception.h create mode 100644 src/mrt/libsan/interception/interception_linux.cpp create mode 100644 src/mrt/libsan/interception/interception_linux.h diff --git a/src/mrt/libsan/.gitignore b/src/mrt/libsan/.gitignore new file mode 100644 index 0000000000..5b0863bd43 --- /dev/null +++ b/src/mrt/libsan/.gitignore @@ -0,0 +1,6 @@ +*.o +*.so +*.dump +build +test + diff --git a/src/mrt/libsan/CMakeLists.txt b/src/mrt/libsan/CMakeLists.txt new file mode 100644 index 0000000000..ce683408f9 --- /dev/null +++ b/src/mrt/libsan/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.23.0) + +set(MAPLE_ROOT $ENV{MAPLE_ROOT}) +set(MAPLE_MRT_ROOT ${MAPLE_ROOT}/src/mrt) + +set(LINARO_CXX "${MAPLE_ROOT}/tools/gcc-linaro-7.5.0") +set(CMAKE_CXX_COMPILER "${LINARO_CXX}/bin/aarch64-linux-gnu-g++") + +set(inc_dirs +${MAPLE_MRT_ROOT}/libsan/asan +${MAPLE_MRT_ROOT}/libsan/interception +${LINARO_CXX}/aarch64-linux-gnu/include/c++/7.5.0 +${LINARO_CXX}/aarch64-linux-gnu/include/c++/7.5.0/aarch64-linux-gnu +${LINARO_CXX}/aarch64-linux-gnu/libc/usr/include +${LINARO_CXX}/lib/gcc/aarch64-linux-gnu/7.5.0/include +${LINARO_CXX}/aarch64-linux-gnu/libc/usr/include/linux +) + +set(src_libsan +${MAPLE_MRT_ROOT}/libsan/asan/asan_interceptors.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_report.cpp +${MAPLE_MRT_ROOT}/libsan/asan/sanitizer_libc.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_stubs.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_malloc_linux.cpp +${MAPLE_MRT_ROOT}/libsan/asan/sanitizer_termination.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_flags.cpp +${MAPLE_MRT_ROOT}/libsan/asan/sanitizer_flags.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_rtl.cpp +${MAPLE_MRT_ROOT}/libsan/asan/sanitizer_printf.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_shadow_memory.cpp +${MAPLE_MRT_ROOT}/libsan/asan/sanitizer_linux_syscall.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_alloctor.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_mapping.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_fake_stack.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_interceptors_memintrinsics.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_signal_handler_linux.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_poisoning.cpp +${MAPLE_MRT_ROOT}/libsan/asan/asan_avltree.cpp +${MAPLE_MRT_ROOT}/libsan/interception/interception_linux.cpp +) + +set(CMAKE_CXX_FLAGS "-U __SIZEOF_INT128__ -pthread -ldl -nostdinc -fno-exceptions") + +add_library(asan-dynamic-rt SHARED ${src_libsan}) +add_library(asan-static-rt STATIC ${src_libsan}) + +set_target_properties(asan-dynamic-rt PROPERTIES + COMPILE_FLAGS "" + INCLUDE_DIRECTORIES "${inc_dirs}" + LINK_LIBRARIES "" + OUTPUT_NAME "asan" +) + +set_target_properties(asan-static-rt PROPERTIES + COMPILE_FLAGS "" + INCLUDE_DIRECTORIES "${inc_dirs}" + LINK_LIBRARIES "" + OUTPUT_NAME "asan" +) diff --git a/src/mrt/libsan/asan/asan_alloctor.cpp b/src/mrt/libsan/asan/asan_alloctor.cpp new file mode 100644 index 0000000000..9469fa477c --- /dev/null +++ b/src/mrt/libsan/asan/asan_alloctor.cpp @@ -0,0 +1,300 @@ +#include "asan_alloctor.h" +#include "asan_interceptors.h" +#include "asan_internal.h" +#include "asan_utils.h" +#include "asan_mapping.h" +#include "asan_report.h" +#include "asan_avltree.h" + +namespace __sanitizer { + +Allocator* allocatorPtr; + +AsanChunkTree::AsanChunkTree(){ + OnInit(); +} + +void FreeSubTree(AsanChunk* chunk) { + if (chunk->left != nullptr) + FreeSubTree(chunk->left); + if (chunk->right != nullptr) + FreeSubTree(chunk->right); + REAL(free(chunk)); +} + +void AsanChunkTree::ClearAllChunks() { + VReport(ASAN_LOG_DEBUG, "Free all AsanChunks\n"); + if (root != nullptr) + FreeSubTree(root); +} + +AsanChunkTree::~AsanChunkTree() { + // To not link with libstdc++, the destructor must be empty + // if (root != nullptr) + // ClearAllChunks(); +} + +AsanChunk* AsanChunkTree::FindChunkWithBeg(AsanChunk* node, uptr beg) const { + if (node == nullptr) + return node; + if (beg > node->end_addr) { + return FindChunkWithBeg(node->right, beg); + } + else if (beg < node->beg_addr) { + return FindChunkWithBeg(node->left, beg); + } + else { + if (beg == node->beg_addr) { + return node; + } + else { + // beg is at the middle of a chunk + return nullptr; + } + } +} + +AsanChunk* AsanChunkTree::FindChunkContainsAddr(AsanChunk* node, uptr addr) const { + if (node == nullptr) + return node; + if (addr > node->end_addr) { + return FindChunkContainsAddr(node->right, addr); + } + else if (addr < node->beg_addr) { + return FindChunkContainsAddr(node->left, addr); + } + else { + return node; + } +} + +AsanChunk* AsanChunkTree::FindChunkAtLeft(uptr addr) const { + AsanChunk* pre = nullptr; + AsanChunk* cur = root; + while (cur != nullptr) { + if (cur->end_addr < addr) { + // cur is at the left + pre = cur; + cur = cur->right; + } + else if (cur->beg_addr > addr) { + // cur is at the right + pre = cur; + cur = cur->left; + } + else { + // addr in cur + return cur; + } + } + // Make sure [pre] is just at the left of addr + if (pre == nullptr) pre = cur; + if (pre->beg_addr > addr) return nullptr; + while (pre->right != nullptr && pre->right->beg_addr <= addr) { + pre = pre->right; + } + return pre; +} + +AsanChunk* AsanChunkTree::GetListLeftAsanChunk(const AsanChunk* chunk) const { + if (chunk == nullptr) return nullptr; + if (chunk->left != nullptr) { + return MaxValueChunk(chunk->left); + } + if (chunk->father == nullptr) return nullptr; + if (chunk->father->right == chunk) return chunk->father; + return nullptr; +} + +AsanChunk* AsanChunkTree::GetListRightAsanChunk(const AsanChunk* chunk) const { + if (chunk == nullptr) return nullptr; + if (chunk->right != nullptr) { + return MinValueChunk(chunk->right); + } + if (chunk->father == nullptr) return nullptr; + if (chunk->father->left == chunk) return chunk->father; + return nullptr; +} + +int AsanChunkTree::PrepareToInsertChunk(const AsanChunk* chunk) { + AsanChunk* right_cur = FindChunkAtLeft(chunk->end_addr); + + // no overlap + if (right_cur == nullptr) return 0; + if (right_cur->end_addr < chunk->beg_addr) return 0; + + // remove overlaped chunks + AsanChunk* cur = right_cur; + AsanChunk* next_cur = nullptr; + while (cur != nullptr && cur->end_addr >= chunk->beg_addr) { + CHECK(cur->IsPoisonedChunk()); // Make sure it is a poisoned chunk + next_cur = GetListLeftAsanChunk(cur); + DeleteChunk(cur); + cur = next_cur; + } +} + +void AsanChunkTree::InsertChunk(AsanChunk* chunk) { + root = __sanitizer::InsertChunk(root, chunk); + root->father = nullptr; +} + +void AsanChunkTree::DeleteChunk(AsanChunk* chunk) { + root = __sanitizer::DeleteChunk(root, chunk->beg_addr); + if (root != nullptr) + root->father = nullptr; +} + +AsanChunk* AsanChunkTree::CreateLeftRedzoneChunk(const AsanChunk* chunk) { + AsanChunk* list_left = GetListLeftAsanChunk(chunk); + if (list_left == nullptr) { + // As large redzone as we want + // uptr min_start_addr = RoundDownTo(chunk->beg_addr, ASAN_PAGE_SIZE); + // if (chunk->beg_addr - min_start_addr < redzone_weak_min_size) { + // min_start_addr -= redzone_weak_min_size; + // } + uptr min_start_addr = chunk->beg_addr - redzone_weak_min_size; + AsanChunk* new_chunk = NewAsanChunk(min_start_addr, chunk->beg_addr - 1, kAsanHeapLeftRedzoneMagic); + // We do not insert redzone chunks + // this->InsertChunk(this->root, new_chunk); + return new_chunk; + } + else { + uptr min_start_addr = list_left->end_addr + 1; + if (chunk->beg_addr - min_start_addr > redzone_weak_min_size) { + min_start_addr = chunk->beg_addr - redzone_weak_min_size; + } + else if (chunk->beg_addr == min_start_addr) { + return nullptr; + } + AsanChunk* new_chunk = NewAsanChunk(min_start_addr, chunk->beg_addr - 1, kAsanHeapLeftRedzoneMagic); + // We do not insert redzone chunks + // this->InsertChunk(this->root, new_chunk); + return new_chunk; + } +} + +AsanChunk* AsanChunkTree::CreateRightRedzoneChunk(const AsanChunk* chunk) { + AsanChunk* list_right = GetListRightAsanChunk(chunk); + if (list_right == nullptr) { + // as large redzone as we want + uptr min_end_addr = RoundUpTo(chunk->end_addr, ASAN_PAGE_SIZE) - 1; + if (min_end_addr - chunk->end_addr + 1 < redzone_weak_min_size) { + min_end_addr = chunk->end_addr + redzone_weak_min_size - 1; + } + else { + min_end_addr = Min(min_end_addr, chunk->end_addr + redzone_weak_max_size - 1); + } + AsanChunk* new_chunk = NewAsanChunk(chunk->end_addr + 1, min_end_addr, kAsanInternalHeapMagic); + // this->InsertChunk(this->root, new_chunk); + return new_chunk; + } + else { + uptr min_end_addr = list_right->beg_addr - 1; + if (min_end_addr - chunk->end_addr + 1 > redzone_weak_min_size) { + min_end_addr = chunk->end_addr + redzone_weak_min_size; + } + else if (chunk->end_addr == min_end_addr) { + return nullptr; + } + AsanChunk* new_chunk = NewAsanChunk(chunk->end_addr + 1, min_end_addr, kAsanInternalHeapMagic); + // this->InsertChunk(this->root, new_chunk); + return new_chunk; + } +} + +void PrintSubTree(const AsanChunk* chunk, int indent) { + for (int i = 0; i < indent; ++i) { + Printf(" "); + } + if (chunk != nullptr) { + Printf("%p %p %x\n", chunk, chunk->Beg(), chunk->mode & 0x0ff); + PrintSubTree(chunk->left, indent + 1); + PrintSubTree(chunk->right, indent + 1); + } + else { + Printf("NONE\n"); + } +} + +void AsanChunkTree::PrintTree() const { + PrintSubTree(root, 0); +} + +void AsanChunkTree::PrintList() const { + +} + +int Allocator::OnInit(AsanShadowMem *ptr) { + shadow = ptr; + tree.OnInit(); + tree.redzone_weak_min_size = asan_flags()->redzone; + tree.redzone_weak_max_size = asan_flags()->max_redzone; +} + +int Allocator::OnDelete(){ + VReport(ASAN_LOG_DEBUG, "Free shadow\n"); + if (shadow != nullptr) { + REAL(free(shadow)); + } + tree.ClearAllChunks(); +} + +int Allocator::DoMalloc(void* addr, uptr size) { + VReport(ASAN_LOG_DEBUG, "%s:%d %s(addr=%p, size=%lld)\n", __FILE__, __LINE__, __func__, addr, size); + shadow->UnpoisonMem(addr, size); + AsanChunk * new_chunk = NewAsanChunk((uptr)addr, (uptr)addr + size - 1, 0); +// tree.PrepareToInsertChunk(new_chunk); + tree.InsertChunk(new_chunk); +// REAL(free(new_chunk)); + AsanChunk* left_redzone = tree.CreateLeftRedzoneChunk(new_chunk); + if (left_redzone != nullptr) { + shadow->PoisonMem(left_redzone->Beg(), left_redzone->ChunkSize(), left_redzone->mode); + REAL(free(left_redzone)); + } + AsanChunk* right_redzone = tree.CreateRightRedzoneChunk(new_chunk); + if (right_redzone != nullptr) { + shadow->PoisonMem(right_redzone->Beg(), right_redzone->ChunkSize(), right_redzone->mode); + REAL(free(right_redzone)); + } + return 0; +} + +int Allocator::DoAlloca(void* addr, uptr size) { + // We do not insert a chunk with alloca + // but insert some redzone at right + shadow->UnpoisonMem(addr, size); + void* redzone_beg = (void*)((uptr)addr + size); + shadow->PoisonMem(redzone_beg, redzone_weak_min_size, kAsanStackRightRedzoneMagic); +} + +int Allocator::DoFree(void* addr) { + if (addr == nullptr) return 0; + VReport(ASAN_LOG_DEBUG, "%s:%d %s(addr=%p)\n", __FILE__, __LINE__, __func__, addr); + AsanChunk* free_chunk = tree.FindChunkWithBeg(tree.root, (uptr)addr); + if (free_chunk == nullptr) { + GET_CALLER_PC_BP_SP; + if (shadow->IsFreeAfterUse(addr)) + ReportDoubleFree(pc, bp, sp, (uptr)addr); + else + ReportFreeNotMalloced(pc, bp, sp, (uptr)addr); + } + else if (free_chunk->IsPoisonedChunk()) { + // We delete the chunk while free + ASSERT(false, "We should have delete the chunk."); + GET_CALLER_PC_BP_SP; + ReportDoubleFree(pc, bp, sp, (uptr)addr); + } + DoQuickFree(free_chunk); + return 0; +} + +int Allocator::DoQuickFree(AsanChunk* chunk) { + // The delete may change the content of the chunk + // shadow must read from the chunk before delete it + shadow->PoisonMem((void*)(chunk->beg_addr), chunk->ChunkSize(), kAsanHeapFreeMagic); + DeleteChunk(chunk); +// chunk->mode = kAsanHeapFreeMagic; +} + +} // namespace __sanitizer diff --git a/src/mrt/libsan/asan/asan_alloctor.h b/src/mrt/libsan/asan/asan_alloctor.h new file mode 100644 index 0000000000..aeeb755304 --- /dev/null +++ b/src/mrt/libsan/asan/asan_alloctor.h @@ -0,0 +1,66 @@ +#ifndef ASAN_ALLOCTOR_H +#define ASAN_ALLOCTOR_H +#include "asan_internal_defs.h" +#include "asan_shadow_memory.h" +#include "asan_interceptors.h" +#include "asan_internal.h" +#include "asan_mapping.h" +#include "asan_avltree.h" + + +namespace __sanitizer { + + +class AsanChunkTree { +public: + AsanChunk* root; + uptr redzone_weak_min_size; + uptr redzone_weak_max_size; + inline void OnInit() {root = nullptr;} + AsanChunkTree(); + void ClearAllChunks(); + ~AsanChunkTree(); + AsanChunk* FindChunkWithBeg(AsanChunk* N, uptr beg) const; + AsanChunk* FindChunkContainsAddr(AsanChunk* N, uptr addr) const; + AsanChunk* GetListLeftAsanChunk(const AsanChunk* chunk) const; + AsanChunk* GetListRightAsanChunk(const AsanChunk* chunk) const; + + AsanChunk* FindChunkAtLeft(uptr addr) const; + int PrepareToInsertChunk(const AsanChunk* chunk); + void InsertChunk(AsanChunk* chunk); + void DeleteChunk(AsanChunk* chunk); + AsanChunk* CreateLeftRedzoneChunk(const AsanChunk* chunk); + AsanChunk* CreateRightRedzoneChunk(const AsanChunk* chunk); + void UpdateChunkListInfo(AsanChunk* chunk); + + void PrintTree() const; + void PrintList() const; +}; + +struct Allocator { + int OnInit(AsanShadowMem *ptr); + int OnDelete(); + int DoMalloc(void* addr, uptr size); + int DoAlloca(void* addr, uptr size); + int DoFree(void* addr); + int DoQuickFree(AsanChunk* addr); + + inline AsanChunk* FindChunkWithBeg(void* beg) { + return tree.FindChunkWithBeg(tree.root, (uptr)beg); + } + + inline void DeleteChunk(AsanChunk* chunk) { + tree.DeleteChunk(chunk); + } + + AsanChunkTree tree; + AsanShadowMem *shadow; + uptr redzone_weak_min_size; +}; + +extern Allocator* allocatorPtr; + +} // namespace __sanitizer + + +#endif // ASAN_ALLOCTOR_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_avltree.cpp b/src/mrt/libsan/asan/asan_avltree.cpp new file mode 100644 index 0000000000..167461dca2 --- /dev/null +++ b/src/mrt/libsan/asan/asan_avltree.cpp @@ -0,0 +1,195 @@ +#include "asan_avltree.h" + +#include "asan_interceptors.h" +#include "asan_internal_defs.h" + + +static __sanitizer::uptr max(__sanitizer::uptr a, __sanitizer::uptr b) { + return (a > b) ? a : b; +} + +static int height(__sanitizer::AsanChunk *node) { + if (node == nullptr) return 0; + return node->height; +} + +int __sanitizer::Balance(__sanitizer::AsanChunk *node) { + if (node == nullptr) return 0; + return height(node->left) - height(node->right); +} + +__sanitizer::AsanChunk *__sanitizer::NewAsanChunk(__sanitizer::uptr beg_addr, __sanitizer::uptr end_addr, int mode) { + __sanitizer::AsanChunk *node = (__sanitizer::AsanChunk *)REAL(malloc(sizeof(__sanitizer::AsanChunk))); + node->beg_addr = beg_addr; + node->end_addr = end_addr; + node->mode = mode; + node->height = 1; + node->left = nullptr; + node->right = nullptr; + node->father = nullptr; + return node; +} + +void __sanitizer::UpdateHeight(__sanitizer::AsanChunk *node) { + node->height = 1 + max(height(node->left), height(node->right)); +} + +__sanitizer::AsanChunk *__sanitizer::RightRotate(__sanitizer::AsanChunk *node) { + __sanitizer::AsanChunk *leftChild = node->left; + __sanitizer::AsanChunk *rightGrandChild = leftChild->right; + + leftChild->right = node; + node->father = leftChild; + node->left = rightGrandChild; + + if (rightGrandChild != nullptr) rightGrandChild->father = node; + + __sanitizer::UpdateHeight(node); + __sanitizer::UpdateHeight(leftChild); + + return leftChild; +} + +__sanitizer::AsanChunk *__sanitizer::LeftRotate(__sanitizer::AsanChunk *node) { + __sanitizer::AsanChunk *rightChild = node->right; + __sanitizer::AsanChunk *leftGrandChild = rightChild->left; + + rightChild->left = node; + node->father = rightChild; + node->right = leftGrandChild; + + if (leftGrandChild != nullptr) leftGrandChild->father = node; + + __sanitizer::UpdateHeight(node); + __sanitizer::UpdateHeight(rightChild); + + return rightChild; +} + +__sanitizer::AsanChunk *__sanitizer::InsertChunk(__sanitizer::AsanChunk *node, __sanitizer::AsanChunk *new_node) { + if (node == nullptr) return new_node; + + if (__sanitizer::ChunkAtLeft(node, new_node)) { + node->left = __sanitizer::InsertChunk(node->left, new_node); + node->left->father = node; + } + else if (__sanitizer::ChunkAtRight(node, new_node)) { + node->right = __sanitizer::InsertChunk(node->right, new_node); + node->right->father = node; + } + else { + Printf("Insert an existing node (beg_addr=%p).\n", (void*)(new_node->beg_addr)); + Die(); + } + + __sanitizer::UpdateHeight(node); + + int BalanceFactor = __sanitizer::Balance(node); + + if (BalanceFactor > 1 && __sanitizer::ChunkAtLeft(node->left, new_node)) { + return __sanitizer::RightRotate(node); + } + + if (BalanceFactor < -1 && __sanitizer::ChunkAtRight(node->right, new_node)) { + return __sanitizer::LeftRotate(node); + } + + if (BalanceFactor > 1 && __sanitizer::ChunkAtRight(node->left, new_node)) { + node->left = __sanitizer::LeftRotate(node->left); + node->left->father = node; + return __sanitizer::RightRotate(node); + } + + if (BalanceFactor < -1 && __sanitizer::ChunkAtLeft(node->right, new_node)) { + node->right = __sanitizer::RightRotate(node->right); + node->right->father = node; + return __sanitizer::LeftRotate(node); + } + + return node; +} + +__sanitizer::AsanChunk *__sanitizer::MinValueChunk(__sanitizer::AsanChunk *node) { + __sanitizer::AsanChunk *current = node; + while (current->left != nullptr) current = current->left; + return current; +} + +__sanitizer::AsanChunk *__sanitizer::MaxValueChunk(__sanitizer::AsanChunk *node) { + __sanitizer::AsanChunk *current = node; + while (current->right != nullptr) current = current->right; + return current; +} + +__sanitizer::AsanChunk *__sanitizer::DeleteChunk(__sanitizer::AsanChunk *node, __sanitizer::uptr beg_addr) { + if (node == nullptr) return node; + + if (beg_addr < node->beg_addr) { + node->left = __sanitizer::DeleteChunk(node->left, beg_addr); + if (node->left != nullptr) node->left->father = node; + } + + else if (beg_addr > node->beg_addr) { + node->right = __sanitizer::DeleteChunk(node->right, beg_addr); + if (node->right != nullptr) node->right->father = node; + } + else { + if ((node->left == nullptr) || (node->right == nullptr)) { + __sanitizer::AsanChunk *temp = (node->left != nullptr) ? node->left : node->right; + + if (temp == nullptr) { + temp = node; + if (node->father != nullptr) { + if (node->father->left == node) node->father->left = nullptr; + else node->father->right = nullptr; + } + node = nullptr; + } + else { + __sanitizer::AsanChunk* node_father = node->father; + *node = *temp; + if (node->left != nullptr) node->left->father = node; + if (node->right != nullptr) node->right->father = node; + node->father = node_father; + } + REAL(free(temp)); + } + else { + __sanitizer::AsanChunk *temp = __sanitizer::MinValueChunk(node->right); + node->beg_addr = temp->beg_addr; + node->end_addr = temp->end_addr; + node->mode = temp->mode; + node->right = __sanitizer::DeleteChunk(node->right, temp->beg_addr); + if (node->right != nullptr) + node->right->father = node; + } + } + + if (node == nullptr) return node; + + __sanitizer::UpdateHeight(node); + + int BalanceFactor = __sanitizer::Balance(node); + + if (BalanceFactor > 1 && __sanitizer::Balance(node->left) >= 0) { + return __sanitizer::RightRotate(node); + } + + if (BalanceFactor > 1 && __sanitizer::Balance(node->left) < 0) { + node->left = __sanitizer::LeftRotate(node->left); + node->left->father = node; + return __sanitizer::RightRotate(node); + } + + if (BalanceFactor < -1 && __sanitizer::Balance(node->right) <= 0) { + return __sanitizer::LeftRotate(node); + } + + if (BalanceFactor < -1 && __sanitizer::Balance(node->right) > 0) { + node->right = __sanitizer::RightRotate(node->right); + node->right->father = node; + return __sanitizer::LeftRotate(node); + } + + return node; +} diff --git a/src/mrt/libsan/asan/asan_avltree.h b/src/mrt/libsan/asan/asan_avltree.h new file mode 100644 index 0000000000..a8cc575448 --- /dev/null +++ b/src/mrt/libsan/asan/asan_avltree.h @@ -0,0 +1,65 @@ +#ifndef ASAN_AVLTREE_H +#define ASAN_AVLTREE_H + +#include "asan_internal_defs.h" +#include "asan_internal.h" + +namespace __sanitizer { + +typedef int height_t; + +class AsanChunk { +public: + uptr beg_addr; + uptr end_addr; + height_t height; + int mode; + struct AsanChunk *left; + struct AsanChunk *right; + struct AsanChunk *father; + + inline bool IsRedZoneChunk() {return mode == kAsanHeapLeftRedzoneMagic || mode == kAsanGlobalRedzoneMagic;} + inline bool IsPoisonedChunk() {return mode < 0 || mode >= (1 << ASAN_SHADOW_SCALE);} + inline uptr ChunkSize() {return end_addr - beg_addr + 1;} + inline void* Beg() const {return (void*)beg_addr;} + inline void* End() const {return (void*)end_addr;} +}; + +int Balance(AsanChunk *node); +AsanChunk *NewAsanChunk(uptr beg_addr, uptr end_addr, int mode); +void UpdateHeight(AsanChunk *node); +AsanChunk *RightRotate(AsanChunk *node); +AsanChunk *LeftRotate(AsanChunk *node); +AsanChunk *InsertChunk(AsanChunk *node, AsanChunk *new_node); +AsanChunk *MinValueChunk(AsanChunk *node); +AsanChunk *MaxValueChunk(AsanChunk* node); +AsanChunk *DeleteChunk(AsanChunk *node, uptr beg_addr); + +inline height_t ChunkHeight(const AsanChunk* chunk) { + return chunk == nullptr ? 0 : chunk->height; +} + +inline bool ChunkAtLeft(const AsanChunk* anchor, const AsanChunk* chunk) { + return chunk->end_addr < anchor->beg_addr; +} + +inline bool ChunkAtRight(const AsanChunk* anchor, const AsanChunk* chunk) { + return chunk->beg_addr > anchor->end_addr; +} + +inline bool ChunkHasOverlap(const AsanChunk* node, const AsanChunk* chunk) { + if ((chunk->beg_addr > node->beg_addr && chunk->beg_addr < node->end_addr) \ + || (chunk->end_addr > node->beg_addr && chunk->end_addr < node->end_addr)) + return true; + return false; +} + +inline bool EqualChunk(AsanChunk* node, AsanChunk* chunk) { + if (node == nullptr && chunk == nullptr) return true; + else if (node == nullptr || chunk == nullptr) return false; + return (node->beg_addr == chunk->beg_addr && node->end_addr == chunk->end_addr); +} + +} // namespace __sanitizer + +#endif // ASAN_AVLTREE_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_fake_stack.cpp b/src/mrt/libsan/asan/asan_fake_stack.cpp new file mode 100644 index 0000000000..682816f620 --- /dev/null +++ b/src/mrt/libsan/asan/asan_fake_stack.cpp @@ -0,0 +1,38 @@ +#include "asan_interfaces_internal.h" +#include "asan_internal_defs.h" +#include "asan_internal.h" +#include "asan_alloctor.h" +#include "sanitizer_libc.h" + + +namespace __sanitizer { + +static const u64 kMagic1 = kAsanStackAfterReturnMagic; +static const u64 kMagic2 = (kMagic1 << 8) | kMagic1; +static const u64 kMagic4 = (kMagic2 << 16) | kMagic2; +static const u64 kMagic8 = (kMagic4 << 32) | kMagic4; + +static const u64 kAllocaRedzoneSize = 32UL; +static const u64 kAllocaRedzoneMask = 31UL; + +extern "C" { + +SANITIZER_INTERFACE_ATTRIBUTE void __asan_alloca_poison(uptr addr, uptr size) { + uptr LeftRedzoneAddr = addr - kAllocaRedzoneSize; + allocatorPtr->shadow->PoisonMem((void*)LeftRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaLeftMagic); + allocatorPtr->shadow->UnpoisonMem((void*)addr, size); + // add some right redzone + uptr RightRedzoneAddr = addr + size; + allocatorPtr->shadow->PoisonMem((void*)RightRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaRightMagic); +} + + +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_allocas_unpoison(uptr top, uptr bottom) { + if ((!top) || (top > bottom)) return; + internal_memset((void*)top, 0, (bottom - top) / ASAN_SHADOW_GRANULARITY); +} + +} + +} // namespace __sanitizer \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_flags.cpp b/src/mrt/libsan/asan/asan_flags.cpp new file mode 100644 index 0000000000..9e50f5ee6d --- /dev/null +++ b/src/mrt/libsan/asan/asan_flags.cpp @@ -0,0 +1,23 @@ +#include "common_flags.h" +#include "asan_flags.h" + + +namespace __sanitizer +{ + +AsanFlags asan_flags_dont_use_directly; + +void AsanFlags::SetDefaults() { +#define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "asan_flags.inc" +#undef ASAN_FLAG +} + +void InitializeAsanFlags() { + // Google use a register mechanism, not sure if it is necessary. + // Currently, we read from those flags directly anyway + asan_flags_dont_use_directly.SetDefaults(); +} + +} // namespace __sanitizer + diff --git a/src/mrt/libsan/asan/asan_flags.h b/src/mrt/libsan/asan/asan_flags.h new file mode 100644 index 0000000000..1549db31c7 --- /dev/null +++ b/src/mrt/libsan/asan/asan_flags.h @@ -0,0 +1,28 @@ +#ifndef SANITIZER_FLAGS_H +#define SANITIZER_FLAGS_H +#include "common_flags.h" + + +namespace __sanitizer +{ + +struct AsanFlags { +#define ASAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "asan_flags.inc" +#undef ASAN_FLAG + + void SetDefaults(); +}; + + +extern AsanFlags asan_flags_dont_use_directly; +inline AsanFlags *asan_flags() { + return &asan_flags_dont_use_directly; +} + +void InitializeAsanFlags(); + +} // namespace __sanitizer + + +#endif // SANITIZER_FLAGS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_flags.inc b/src/mrt/libsan/asan/asan_flags.inc new file mode 100644 index 0000000000..66c71af07d --- /dev/null +++ b/src/mrt/libsan/asan/asan_flags.inc @@ -0,0 +1,169 @@ +//===-- asan_flags.inc ------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// ASan runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef ASAN_FLAG +# error "Define ASAN_FLAG prior to including this file!" +#endif + +#define SANITIZER_LINUX 1 + +// ASAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. + +ASAN_FLAG(int, quarantine_size, -1, + "Deprecated, please use quarantine_size_mb.") +ASAN_FLAG(int, quarantine_size_mb, -1, + "Size (in Mb) of quarantine used to detect use-after-free " + "errors. Lower value may reduce memory usage but increase the " + "chance of false negatives.") +ASAN_FLAG(int, thread_local_quarantine_size_kb, -1, + "Size (in Kb) of thread local quarantine used to detect " + "use-after-free errors. Lower value may reduce memory usage but " + "increase the chance of false negatives. It is not advised to go " + "lower than 64Kb, otherwise frequent transfers to global quarantine " + "might affect performance.") +ASAN_FLAG(int, redzone, 16, + "Minimal size (in bytes) of redzones around heap objects. " + "Requirement: redzone >= 16, is a power of two.") +ASAN_FLAG(int, max_redzone, 2048, + "Maximal size (in bytes) of redzones around heap objects.") +ASAN_FLAG( + bool, debug, false, + "If set, prints some debugging information and does additional checks.") +ASAN_FLAG( + int, report_globals, 1, + "Controls the way to handle globals (0 - don't detect buffer overflow on " + "globals, 1 - detect buffer overflow, 2 - print data about registered " + "globals).") +ASAN_FLAG(bool, check_initialization_order, false, + "If set, attempts to catch initialization order issues.") +ASAN_FLAG( + bool, replace_str, true, + "If set, uses custom wrappers and replacements for libc string functions " + "to find more errors.") +ASAN_FLAG(bool, replace_intrin, true, + "If set, uses custom wrappers for memset/memcpy/memmove intrinsics.") +ASAN_FLAG(bool, detect_stack_use_after_return, + SANITIZER_LINUX && !SANITIZER_ANDROID, + "Enables stack-use-after-return checking at run-time.") +ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway. + "Minimum fake stack size log.") +ASAN_FLAG(int, max_uar_stack_size_log, + 20, // 1Mb per size class, i.e. ~11Mb per thread + "Maximum fake stack size log.") +ASAN_FLAG(bool, uar_noreserve, false, + "Use mmap with 'noreserve' flag to allocate fake stack.") +ASAN_FLAG( + int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K. + "ASan allocator flag. max_malloc_fill_size is the maximal amount of " + "bytes that will be filled with malloc_fill_byte on malloc.") +ASAN_FLAG( + int, max_free_fill_size, 0, + "ASan allocator flag. max_free_fill_size is the maximal amount of " + "bytes that will be filled with free_fill_byte during free.") +ASAN_FLAG(int, malloc_fill_byte, 0xbe, + "Value used to fill the newly allocated memory.") +ASAN_FLAG(int, free_fill_byte, 0x55, + "Value used to fill deallocated memory.") +ASAN_FLAG(bool, allow_user_poisoning, true, + "If set, user may manually mark memory regions as poisoned or " + "unpoisoned.") +ASAN_FLAG( + int, sleep_before_dying, 0, + "Number of seconds to sleep between printing an error report and " + "terminating the program. Useful for debugging purposes (e.g. when one " + "needs to attach gdb).") +ASAN_FLAG( + int, sleep_after_init, 0, + "Number of seconds to sleep after AddressSanitizer is initialized. " + "Useful for debugging purposes (e.g. when one needs to attach gdb).") +ASAN_FLAG( + int, sleep_before_init, 0, + "Number of seconds to sleep before AddressSanitizer starts initializing. " + "Useful for debugging purposes (e.g. when one needs to attach gdb).") +ASAN_FLAG(bool, check_malloc_usable_size, true, + "Allows the users to work around the bug in Nvidia drivers prior to " + "295.*.") +ASAN_FLAG(bool, unmap_shadow_on_exit, false, + "If set, explicitly unmaps the (huge) shadow at exit.") +ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap") +ASAN_FLAG(bool, print_stats, false, + "Print various statistics after printing an error message or if " + "atexit=1.") +ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.") +ASAN_FLAG(bool, print_scariness, false, + "Print the scariness score. Experimental.") +ASAN_FLAG(bool, atexit, false, + "If set, prints ASan exit stats even after program terminates " + "successfully.") +ASAN_FLAG( + bool, print_full_thread_history, true, + "If set, prints thread creation stacks for the threads involved in the " + "report and their ancestors up to the main thread.") +ASAN_FLAG( + bool, poison_heap, true, + "Poison (or not) the heap memory on [de]allocation. Zero value is useful " + "for benchmarking the allocator or instrumentator.") +ASAN_FLAG(bool, poison_partial, true, + "If true, poison partially addressable 8-byte aligned words " + "(default=true). This flag affects heap and global buffers, but not " + "stack buffers.") +ASAN_FLAG(bool, poison_array_cookie, true, + "Poison (or not) the array cookie after operator new[].") + +// Turn off alloc/dealloc mismatch checker on Mac and Windows for now. +// https://github.com/google/sanitizers/issues/131 +// https://github.com/google/sanitizers/issues/309 +// TODO(glider,timurrrr): Fix known issues and enable this back. +ASAN_FLAG(bool, alloc_dealloc_mismatch, + !SANITIZER_APPLE && !SANITIZER_WINDOWS && !SANITIZER_ANDROID, + "Report errors on malloc/delete, new/free, new/delete[], etc.") + +ASAN_FLAG(bool, new_delete_type_mismatch, true, + "Report errors on mismatch between size of new and delete.") +ASAN_FLAG( + bool, strict_init_order, false, + "If true, assume that dynamic initializers can never access globals from " + "other modules, even if the latter are already initialized.") +ASAN_FLAG( + bool, start_deactivated, false, + "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap " + "poisoning) to reduce memory consumption as much as possible, and " + "restores them to original values when the first instrumented module is " + "loaded into the process. This is mainly intended to be used on " + "Android. ") +ASAN_FLAG( + int, detect_invalid_pointer_pairs, 0, + "If >= 2, detect operations like <, <=, >, >= and - on invalid pointer " + "pairs (e.g. when pointers belong to different objects); " + "If == 1, detect invalid operations only when both pointers are non-null.") +ASAN_FLAG(bool, detect_container_overflow, true, + "If true, honor the container overflow annotations. See " + "https://github.com/google/sanitizers/wiki/" + "AddressSanitizerContainerOverflow") +ASAN_FLAG(int, detect_odr_violation, 2, + "If >=2, detect violation of One-Definition-Rule (ODR); " + "If ==1, detect ODR-violation only if the two variables " + "have different sizes") +ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") +ASAN_FLAG(bool, halt_on_error, true, + "Crash the program after printing the first error report " + "(WARNING: USE AT YOUR OWN RISK!)") +ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, + "realloc(p, 0) is equivalent to free(p) by default (Same as the " + "POSIX standard). If set to false, realloc(p, 0) will return a " + "pointer to an allocated space which can not be used.") +ASAN_FLAG(bool, verify_asan_link_order, true, + "Check position of ASan runtime in library list (needs to be disabled" + " when other library has to be preloaded system-wide)") +ASAN_FLAG( + bool, windows_hook_rtl_allocators, false, + "(Windows only) enable hooking of Rtl(Allocate|Free|Size|ReAllocate)Heap.") diff --git a/src/mrt/libsan/asan/asan_interceptors.cpp b/src/mrt/libsan/asan/asan_interceptors.cpp new file mode 100644 index 0000000000..844ac4b2b4 --- /dev/null +++ b/src/mrt/libsan/asan/asan_interceptors.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include "asan_internal_defs.h" +#include "asan_interceptors.h" +#include "interception.h" + +#define ASAN_INTERFACES_MACRO DECLARE_REAL_AND_INTERCEPTOR +#include "asan_interfaces.inc" +#undef ASAN_INTERFACES_MACRO + +using namespace __sanitizer; + + +extern "C" { +void InitializeAsanInterceptors() { + static bool was_called_once; + ASSERT(!was_called_once, "__sanitizer::InitializeAsanInterceptors was called again"); + was_called_once = true; + + ASAN_INTERCEPT_FUNC(malloc); + ASAN_INTERCEPT_FUNC(calloc); + ASAN_INTERCEPT_FUNC(realloc); + ASAN_INTERCEPT_FUNC(free); + // ASAN_INTERCEPT_FUNC(alloca); + + ASAN_INTERCEPT_FUNC(memcpy); + ASAN_INTERCEPT_FUNC(memset); + ASAN_INTERCEPT_FUNC(memmove); + + // Intercept str* functions. + ASAN_INTERCEPT_FUNC(memcmp); + ASAN_INTERCEPT_FUNC(strlen); + ASAN_INTERCEPT_FUNC(strnlen); + ASAN_INTERCEPT_FUNC(strcat); + ASAN_INTERCEPT_FUNC(strncat); + ASAN_INTERCEPT_FUNC(strcpy); + ASAN_INTERCEPT_FUNC(strncpy); + ASAN_INTERCEPT_FUNC(strdup); + + ASAN_INTERCEPT_FUNC(wcscpy); + ASAN_INTERCEPT_FUNC(wcsncpy); + + ASAN_INTERCEPT_FUNC(printf); + ASAN_INTERCEPT_FUNC(snprintf); + + // To handle several overloaded functions + const char* (*__asan_strchr_1)(const char *, int) = &strchr; + ASAN_INTERCEPT_FUNC_WITH_ADDR(strchr, __asan_strchr_1); + char* (*__asan_strchr_2)(char *, int) = &strchr; + ASAN_INTERCEPT_FUNC_WITH_ADDR(strchr, __asan_strchr_2); + + const char* (*__asan_strstr_1)(const char *, const char *) = &strstr; + ASAN_INTERCEPT_FUNC_WITH_ADDR(strstr, __asan_strstr_1); + char* (*__asan_strstr_2)(char *, const char *) = &strstr; + ASAN_INTERCEPT_FUNC_WITH_ADDR(strstr, __asan_strstr_2); + + // VReport(1, "AddressSanitizer: libc interceptors initialized\n"); +} + +} \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_interceptors.h b/src/mrt/libsan/asan/asan_interceptors.h new file mode 100644 index 0000000000..77649839cb --- /dev/null +++ b/src/mrt/libsan/asan/asan_interceptors.h @@ -0,0 +1,87 @@ +#ifndef SANITIZER_INTERCEPTORS_H +#define SANITIZER_INTERCEPTORS_H + +#include "asan_internal_defs.h" +#include "string.h" + + +# define PTR_TO_REAL(x) real_##x +# define REAL(x) __sanitizer::PTR_TO_REAL(x) +# define FUNC_TYPE(x) x##_type + +#define DEFINE_REAL(ret_type, func, ...) \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __sanitizer { \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ +} + +# define DECLARE_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__) \ + __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); + +# define DECLARE_CXX_WRAPPER(ret_type, func, ...) \ + ret_type func(__VA_ARGS__) \ + __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); + +# define WRAP(x) __interceptor_ ## x +# define WRAPPER_NAME(x) "__interceptor_" #x +# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) + +#define INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__) \ + DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ + extern "C" \ + INTERCEPTOR_ATTRIBUTE \ + ret_type WRAP(func)(__VA_ARGS__) + +#define CXX_INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__) \ + DECLARE_CXX_WRAPPER(ret_type, func, __VA_ARGS__) \ + extern "C" \ + INTERCEPTOR_ATTRIBUTE \ + ret_type WRAP(func)(__VA_ARGS__) + +# define DECLARE_REAL(ret_type, func, ...) \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __sanitizer { \ + extern FUNC_TYPE(func) PTR_TO_REAL(func); \ + } +# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) + +#define ASAN_INTERFACES_MACRO DECLARE_REAL +#include "asan_interfaces.inc" +#undef ASAN_INTERFACES_MACRO + +# define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if (!INTERCEPT_FUNCTION(name)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \ + } while (0) +# define ASAN_INTERCEPT_FUNC_VER(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s@@%s'\n", \ + #name, ver); \ + } while (0) +# define ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \ + VReport(1, \ + "AddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \ + #name, ver, #name); \ + } while (0) + +# define ASAN_INTERCEPT_FUNC_WITH_ADDR(name, addr) \ + do { \ + if (!INTERCEPT_FUNCTION_WITH_ADDR(name, addr)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \ + } while (0) + +extern "C" { + +void InitializeAsanInterceptors(); + +} + + +#endif // SANITIZER_INTERCEPTORS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_interceptors_memintrinsics.cpp b/src/mrt/libsan/asan/asan_interceptors_memintrinsics.cpp new file mode 100644 index 0000000000..9498a23a2d --- /dev/null +++ b/src/mrt/libsan/asan/asan_interceptors_memintrinsics.cpp @@ -0,0 +1,68 @@ +#include "asan_interceptors_memintrinsics.h" +#include "asan_interceptors.h" +#include "sanitizer_libc.h" +#include "asan_internal_defs.h" +#include "asan_alloctor.h" +#include "asan_report.h" + +using namespace __sanitizer; + +INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { + // We need to check the asan_inited here so that qemu can also work + if (!asan_inited) return internal_memcpy(to, from, size); + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + // TODO: check overlap + CheckAndReport(from, size, false); + CheckAndReport(to, size, true); + // return internal_memcpy(to, from, size); + return REAL(memcpy(to, from, size)); +} + +INTERCEPTOR(void*, memset, void *block, int c, uptr size) { + if (!asan_inited) return internal_memset(block, c, size); + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + CheckAndReport(block, size, true); + // return internal_memset(block, c, size); + return REAL(memset(block, c, size)); +} + +INTERCEPTOR(void*, memmove, void* to, const void* from, uptr size) { + if (!asan_inited) return internal_memmove(to, from, size); + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + CheckAndReport(from, size, false); + CheckAndReport(to, size, true); + // return internal_memmove(to, from, size); + return REAL(memmove(to, from, size)); +} + +extern "C" { + +void* __asan_memcpy(void* to, const void* from, uptr size) { + if (!asan_inited) return internal_memcpy(to, from, size); + // TODO: check overlap + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + CheckAndReport(from, size, false); + CheckAndReport(to, size, true); + // return internal_memcpy(to, from, size); + return REAL(memcpy(to, from, size)); +} + +void* __asan_memset(void* block, int c, uptr size) { + if (!asan_inited) return internal_memset(block, c, size); + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + CheckAndReport(block, size, true); + // return internal_memset(block, c, size); + return REAL(memset(block, c, size)); +} + +void* __asan_memmove(void* to, const void* from, uptr size) { + if (!asan_inited) return internal_memmove(to, from, size); + // TODO: check overlap + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + CheckAndReport(from, size, false); + CheckAndReport(to, size, true); + // return internal_memmove(to, from, size); + return REAL(memmove(to, from, size)); +} + +} \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_interceptors_memintrinsics.h b/src/mrt/libsan/asan/asan_interceptors_memintrinsics.h new file mode 100644 index 0000000000..30bcd58a96 --- /dev/null +++ b/src/mrt/libsan/asan/asan_interceptors_memintrinsics.h @@ -0,0 +1,28 @@ +#ifndef ASAN_INTERCEPTORS_MEMINTRINSICS_h +#define ASAN_INTERCEPTORS_MEMINTRINSICS_h + +#include "asan_interceptors.h" +#include "asan_internal_defs.h" +#include "asan_internal.h" +#include "asan_mapping.h" +#include "asan_alloctor.h" + +using namespace __sanitizer; + +// DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size) +// DECLARE_REAL(void*, memset, void *block, int c, uptr size) +// DECLARE_REAL(void*, memmove, void* to, const void* from, uptr size) + +extern "C" { + +// Those functions could be also invoked during __asan_init +// Before or during __asan_init, we invoke REAL(XXX) only +// After the __asan_init, we also check the shadow +void* __asan_memcpy(void* to, const void* from, uptr size); +void* __asan_memset(void* block, int c, uptr size); +void* __asan_memmove(void* to, const void* from, uptr size); + +} + + +# endif // ASAN_INTERCEPTORS_MEMINTRINSICS_h \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_interfaces.inc b/src/mrt/libsan/asan/asan_interfaces.inc new file mode 100644 index 0000000000..b841f4d473 --- /dev/null +++ b/src/mrt/libsan/asan/asan_interfaces.inc @@ -0,0 +1,37 @@ +// do not use namespace __sanitizer; +#ifndef ASAN_INTERFACES_MACRO +#error "Define ASAN_INTERFACES_MACRO before include this file" +#else +// malloc and free +ASAN_INTERFACES_MACRO(void *, malloc, __sanitizer::uptr); +ASAN_INTERFACES_MACRO(void*, calloc, __sanitizer::uptr, __sanitizer::uptr); +ASAN_INTERFACES_MACRO(void*, realloc, void* ptr, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(void*, alloca, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(void, free, void *); + +// intrinsic functions +ASAN_INTERFACES_MACRO(void*, memcpy, void *to, const void *from, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(void*, memset, void *block, int c, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(void*, memmove, void* to, const void* from, __sanitizer::uptr size); + +// str* functions +ASAN_INTERFACES_MACRO(int, memcmp, const void *a1, const void *a2, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(__sanitizer::uptr, strlen, const char *s); +ASAN_INTERFACES_MACRO(__sanitizer::uptr, strnlen, const char *s, __sanitizer::uptr maxlen); +ASAN_INTERFACES_MACRO(char *, strcat, char *to, const char *from); +ASAN_INTERFACES_MACRO(char *, strncat, char *to, const char *from, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(char *, strcpy, char *to, const char *from); +ASAN_INTERFACES_MACRO(char *, strncpy, char *to, const char *from, __sanitizer::uptr size); +ASAN_INTERFACES_MACRO(char *, strdup, const char *s); + +ASAN_INTERFACES_MACRO(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src); +ASAN_INTERFACES_MACRO(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, __sanitizer::uptr n); + +// printf functions +ASAN_INTERFACES_MACRO(int, printf, const char *format, ...); +ASAN_INTERFACES_MACRO(int, snprintf, char * s, size_t n, const char * format, ...) + +ASAN_INTERFACES_MACRO(const char*, strstr, const char *s1, const char *s2); +ASAN_INTERFACES_MACRO(const char*, strchr, const char *str, int c); + +#endif // ASAN_INTERFACES_MACRO \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_interfaces_internal.h b/src/mrt/libsan/asan/asan_interfaces_internal.h new file mode 100644 index 0000000000..6e9a080732 --- /dev/null +++ b/src/mrt/libsan/asan/asan_interfaces_internal.h @@ -0,0 +1,62 @@ +#ifndef SANITIZER_INTERFACE_INTERNAL_H +#define SANITIZER_INTERFACE_INTERNAL_H + +#include "asan_internal_defs.h" + +namespace __sanitizer { + +SANITIZER_INTERFACE_ATTRIBUTE +extern uptr __asan_shadow_memory_dynamic_address; + +// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return +SANITIZER_INTERFACE_ATTRIBUTE +extern int __asan_option_detect_stack_use_after_return; + +SANITIZER_INTERFACE_ATTRIBUTE +extern uptr *__asan_test_only_reported_buggy_pointer; + +extern "C" { +// This function should be called at the very beginning of the process, +// before any instrumented code is executed and before any call to malloc. +SANITIZER_INTERFACE_ATTRIBUTE void __asan_init(); + +// This function exists purely to get a linker/loader error when using +// incompatible versions of instrumentation and runtime library. Please note +// that __asan_version_mismatch_check is a macro that is replaced with +// __asan_version_mismatch_check_vXXX at compile-time. +SANITIZER_INTERFACE_ATTRIBUTE void __asan_version_mismatch_check(); + +SANITIZER_INTERFACE_ATTRIBUTE void __asan_alloca_poison(uptr addr, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE void __asan_allocas_unpoison(uptr top, uptr bottom); + +// Performs cleanup before a NoReturn function. Must be called before things +// like _exit and execl to avoid false positives on stack. +SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return(); + +} + +// This structure is used to describe the source location of a place where +// global was defined. +struct __asan_global_source_location { + const char *filename; + int line_no; + int column_no; +}; + +struct __asan_global { + uptr beg; // The address of the global. + uptr size; // The original size of the global. + uptr size_with_redzone; // The size with the redzone. + const char *name; // Name as a C string. + const char *module_name; // Module name as a C string. This pointer is a + // unique identifier of a module. + uptr has_dynamic_init; // Non-zero if the global has dynamic initializer. + uptr windows_padding; // TODO: Figure out how to remove this padding + // that's simply here to make the MSVC incremental + // linker happy... + uptr odr_indicator; // The address of the ODR indicator symbol. +}; + +} // namespace __sanitizer + +#endif // SANITIZER_INTERFACE_INTERNAL_H diff --git a/src/mrt/libsan/asan/asan_internal.h b/src/mrt/libsan/asan/asan_internal.h new file mode 100644 index 0000000000..d65a959617 --- /dev/null +++ b/src/mrt/libsan/asan/asan_internal.h @@ -0,0 +1,33 @@ +#ifndef ASAN_INTERNAL_H +#define ASAN_INTERNAL_H + +#include "asan_internal_defs.h" +#include "asan_shadow_memory.h" + + +namespace __sanitizer { + +// Magic values for reporting, the same as LLVM-ASAN +const su_t kAsanHeapLeftRedzoneMagic = 0xfa; +const su_t kAsanHeapFreeMagic = 0xfd; +const su_t kAsanStackLeftRedzoneMagic = 0xf1; +const su_t kAsanStackMidRedzoneMagic = 0xf2; +const su_t kAsanStackRightRedzoneMagic = 0xf3; +const su_t kAsanStackAfterReturnMagic = 0xf5; +const su_t kAsanInitializationOrderMagic = 0xf6; +const su_t kAsanUserPoisonedMemoryMagic = 0xf7; +const su_t kAsanContiguousContainerOOBMagic = 0xfc; +const su_t kAsanStackUseAfterScopeMagic = 0xf8; +const su_t kAsanGlobalRedzoneMagic = 0xf9; +const su_t kAsanInternalHeapMagic = 0xfe; +const su_t kAsanArrayCookieMagic = 0xac; +const su_t kAsanIntraObjectRedzone = 0xbb; +const su_t kAsanAllocaLeftMagic = 0xca; +const su_t kAsanAllocaRightMagic = 0xcb; + +static const uptr kCurrentStackFrameMagic = 0x41B58AB3; +static const uptr kRetiredStackFrameMagic = 0x45E0360E; +} // namespace __sanitizer + + +#endif // ASAN_INTERNAL_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_internal_defs.h b/src/mrt/libsan/asan/asan_internal_defs.h new file mode 100644 index 0000000000..131211bff1 --- /dev/null +++ b/src/mrt/libsan/asan/asan_internal_defs.h @@ -0,0 +1,158 @@ + +#ifndef SANITIZER_INTERNAL_DEFS_H +#define SANITIZER_INTERNAL_DEFS_H + +#define SanitizerToolName "ASAN" +#define UINT64_MAX 0xffffffffffffffff +#define INT64_MAX 0x7fffffffffffffff +#define INT64_MIN 0x8000000000000000 + +#define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) +#define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) +#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE + +#define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE ReturnType Name(__VA_ARGS__) + +#define SANITIZER_WORDSIZE 64 + +namespace __sanitizer { + +typedef unsigned long uptr; +typedef signed long sptr; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef int fd_t; +typedef int error_t; + +typedef int pid_t; + +typedef uptr OFF_T; +typedef u64 OFF64_T; + +typedef u32 operator_new_size_type; + +typedef u64 tid_t; + +#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +#define SANITIZER_WEAK_DEFAULT_IMPL extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE +#define SANITIZER_WEAK_CXX_DEFAULT_IMPL extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define ALIAS(x) __attribute__((alias(x))) +// Please only use the ALIGNED macro before the type. +// Using ALIGNED after the variable declaration is not portable! +#define ALIGNED(x) __attribute__((aligned(x))) +#define FORMAT(f, a) __attribute__((format(printf, f, a))) +#define NOINLINE __attribute__((noinline)) +#define NORETURN __attribute__((noreturn)) +#define THREADLOCAL __thread +#define LIKELY(x) __builtin_expect(!!(x), 1) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) + +// Unaligned versions of basic types. +typedef ALIGNED(1) u16 uu16; +typedef ALIGNED(1) u32 uu32; +typedef ALIGNED(1) u64 uu64; +typedef ALIGNED(1) s16 us16; +typedef ALIGNED(1) s32 us32; +typedef ALIGNED(1) s64 us64; + +#define GET_CALLER_PC() (__sanitizer::uptr) __builtin_return_address(0) +#define GET_CURRENT_FRAME() (__sanitizer::uptr) __builtin_frame_address(0) + +// Forces the compiler to generate a frame pointer in the function. +#define ENABLE_FRAME_POINTER \ + do { \ + volatile __sanitizer::uptr enable_fp; \ + enable_fp = GET_CURRENT_FRAME(); \ + (void)enable_fp; \ + } while (0) + +// NOTE: Functions below must be defined in each run-time. +void NORETURN Die(); +void NORETURN CheckFailed(const char *file, int line, const char *cond, + u64 v1, u64 v2); + +void Printf(const char *format, ...); +void RawWrite(const char* msg); + +#define ASAN_LOG_DEBUG 4 +#define ASAN_LOG_INFO 3 +#define ASAN_LOG_WARN 2 +#define ASAN_LOG_ERR 1 +#define ASAN_LOG_NONE 0 + +inline int Verbosity() {return ASAN_LOG_ERR;} + +// Check macro +#define RAW_CHECK_MSG(expr, msg, ...) \ + do { \ + if (UNLIKELY(!(expr))) { \ + const char* msgs[] = {msg, __VA_ARGS__}; \ + for (const char* m : msgs) RawWrite(m); \ + Die(); \ + } \ + } while (0) + +#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr "\n", ) +#define RAW_CHECK_VA(expr, ...) RAW_CHECK_MSG(expr, #expr "\n", __VA_ARGS__) + +#define CHECK_IMPL(c1, op, c2) \ + do { \ + __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \ + __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \ + if (UNLIKELY(!(v1 op v2))) \ + __sanitizer::CheckFailed(__FILE__, __LINE__, \ + "(" #c1 ") " #op " (" #c2 ")", v1, v2); \ + } while (false) \ +/**/ + +#define CHECK(a) CHECK_IMPL((a), !=, 0) +#define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b)) +#define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b)) +#define CHECK_LT(a, b) CHECK_IMPL((a), <, (b)) +#define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b)) +#define CHECK_GT(a, b) CHECK_IMPL((a), >, (b)) +#define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b)) + +#define VReport(level, ...) \ + do { \ + if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \ + } while (false) + +#define ASSERT(c, msg) \ + do { \ + if (!c) {Printf((msg)); Die();} \ + } while (false) + +#define UNREACHABLE(msg) do { \ + ASSERT(0, msg); \ + Die(); \ +} while (0) + +// Internal thread identifier allocated by ThreadRegistry. +typedef u32 Tid; +constexpr Tid kInvalidTid = -1; +constexpr Tid kMainTid = 0; +typedef u32 Pid; + +// Stack depot stack identifier. +typedef u32 StackID; +const StackID kInvalidStackID = 0; + +extern bool asan_inited; +extern bool asan_init_is_running; +extern bool asan_interceptor_inited; + +} // namespace __sanitizer + +#endif // SANITIZER_INTERNAL_DEFS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_malloc_linux.cpp b/src/mrt/libsan/asan/asan_malloc_linux.cpp new file mode 100644 index 0000000000..1885839ad1 --- /dev/null +++ b/src/mrt/libsan/asan/asan_malloc_linux.cpp @@ -0,0 +1,243 @@ +#include "asan_internal_defs.h" +#include "asan_interceptors.h" +#include "asan_alloctor.h" +#include "asan_report.h" +#include "sanitizer_libc.h" +#include "interception.h" +#include "asan_utils.h" +#include "sanitizer_printf.h" +#include +#include +#include + +using namespace __sanitizer; + +#define INTERCEPTOR_VREPORT \ + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + +INTERCEPTOR(void, free, void *ptr) { + INTERCEPTOR_VREPORT + if (asan_inited) { + VReport(ASAN_LOG_DEBUG, "free %p\n", ptr); + allocatorPtr->DoFree(ptr); + } + REAL(free(ptr)); +} + +INTERCEPTOR(void*, malloc, uptr size) { + INTERCEPTOR_VREPORT + if (!asan_inited) { + return internal_malloc(size); + } + void* addr = REAL(malloc(size)); + VReport(ASAN_LOG_DEBUG, "malloc %p %llu\n", addr, size); + allocatorPtr->DoMalloc(addr, size); + return addr; +} + +INTERCEPTOR(void*, calloc, uptr num, uptr size) { + if (!asan_inited) { + return internal_calloc(num, size); + } + INTERCEPTOR_VREPORT + void* addr = REAL(calloc(num, size)); + VReport(ASAN_LOG_DEBUG, "calloc %p %llu %llu\n", addr, num, size); + allocatorPtr->DoMalloc(addr, num * size); + return addr; +} + +INTERCEPTOR(void*, realloc, void* ptr, uptr size) { + INTERCEPTOR_VREPORT + // we first ensure the ptr is malloc-ed + if (ptr != nullptr) { + // we perform checks when the ptr is not NULL + AsanChunk* old_chunk = allocatorPtr->FindChunkWithBeg(ptr); + if (old_chunk == nullptr) { + Printf("realloc with an address not malloc-ed yet.\n"); + Die(); + } + allocatorPtr->DoQuickFree(old_chunk); + // we cannot resize the chunk directly + // as the realloc can return a new address + void* addr = REAL(realloc(ptr, size)); + if (size > 0) { + allocatorPtr->DoMalloc(addr, size); + } + VReport(ASAN_LOG_DEBUG, "realloc %p %llu\n", addr, size); + return addr; + } + else { + // behaves like a malloc + void* addr = REAL(realloc(ptr, size)); + if (size > 0) { + VReport(ASAN_LOG_DEBUG, "realloc %p %llu\n", addr, size); + allocatorPtr->DoMalloc(addr, size); + } + return addr; + } +} + +INTERCEPTOR(void*, alloca, uptr size) { + INTERCEPTOR_VREPORT + void* addr = REAL(alloca(size)); + VReport(ASAN_LOG_DEBUG, "alloca %p %llu\n", addr, size); + allocatorPtr->DoAlloca(addr, size); + return addr; +} + +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { + INTERCEPTOR_VREPORT + CheckAndReport(a1, size, false); + CheckAndReport(a2, size, false); + return REAL(memcmp(a1, a2, size)); +} + +//============================================================ +INTERCEPTOR(uptr, strlen, const char *s) { + INTERCEPTOR_VREPORT + uptr result = internal_strlen(s); + CheckAndReport(s, result + 1, false); + return result; +} + +INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) { + INTERCEPTOR_VREPORT + // if (!asan_inited) return internal_strlen(s); + uptr result = internal_strnlen(s, maxlen); + if (result < maxlen) + CheckAndReport(s, result + 1, false); + else + CheckAndReport(s, result, false); + return result; +} + +INTERCEPTOR(char *, strcat, char *to, const char *from) { + INTERCEPTOR_VREPORT + uptr from_length = internal_strlen(from); + CheckAndReport(from, from_length + 1, false); + uptr to_length = internal_strlen(to); + CheckAndReport(to, to_length + from_length + 1, true); + return REAL(strcat)(to, from); +} + +INTERCEPTOR(char *, strncat, char *to, const char *from, uptr size) { + INTERCEPTOR_VREPORT + uptr copy_length = internal_strnlen(from, size); + if (copy_length < size) + CheckAndReport(from, copy_length + 1, false); + else + CheckAndReport(from, copy_length, false); + uptr to_length = internal_strlen(to); + CheckAndReport(to, to_length + copy_length + 1, true); + return REAL(strncat(to, from, size)); +} + +INTERCEPTOR(char *, strcpy, char *to, const char *from) { + INTERCEPTOR_VREPORT + uptr from_length = internal_strlen(from); + CheckAndReport(from, from_length + 1, false); + CheckAndReport(to, from_length + 1, true); + REAL(memcpy(to, from, from_length + 1)); + return to; + // return REAL(strcpy(to, from)); +} + +INTERCEPTOR(char *, strncpy, char *to, const char *from, uptr size) { + INTERCEPTOR_VREPORT + uptr from_length = internal_strnlen(from, size); + if (from_length == size) + CheckAndReport(from, from_length, false); + else + CheckAndReport(from, from_length + 1, false); + CheckAndReport(to, from_length + 1, true); + return REAL(strncpy(to, from, size)); +} + +INTERCEPTOR(char *, strdup, const char *s) { + INTERCEPTOR_VREPORT + uptr length = internal_strlen(s); + CheckAndReport(s, length + 1, false); + return REAL(strdup(s)); +} + +// wchar_t functions +INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { + INTERCEPTOR_VREPORT + uptr src_len = internal_wcslen(src); + uptr byte_len = (src_len + 1) * sizeof(wchar_t); + CheckAndReport((void*)src, byte_len, false); + CheckAndReport((void*)dest, byte_len, true); + return REAL(wcscpy(dest, src)); +} + +INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, uptr n) { + INTERCEPTOR_VREPORT + uptr src_len = internal_wcsnlen(src, n); + uptr read_len = src_len * sizeof(wchar_t); + if (src_len < n) { + read_len += sizeof(wchar_t); + } + CheckAndReport((void*)src, read_len, false); + CheckAndReport((void*)dest, (src_len + 1) * sizeof(wchar_t), true); + return REAL(wcsncpy(dest, src, n)); +} + +INTERCEPTOR(int, printf, const char *format, ...) { + INTERCEPTOR_VREPORT + // We merely check if the format is a valid string pointer with valid length + // check the pointer at initial + CheckAndReport((void*)format, 1, false); + uptr read_len = REAL(strlen(format)); + CheckAndReport((void*)format, (read_len + 1) * sizeof(char), false); + va_list args; + va_start(args, format); + va_list copy_args; + va_copy(copy_args, args); + CheckPrintfVars(format, copy_args); + int ret = vprintf(format, args); + va_end(copy_args); + va_end(args); + return ret; +} + +INTERCEPTOR(int, snprintf, char * s, size_t n, const char * format, ...) { + INTERCEPTOR_VREPORT + // An aggressive implement + CheckAndReport((void*)s, n, true); + CheckAndReport((void*)format, 1, false); + uptr read_len = REAL(strlen(format)); + CheckAndReport((void*)format, (read_len + 1) * sizeof(char), false); + va_list args; + va_start(args, format); + va_list copy_args; + va_copy(copy_args, args); + CheckPrintfVars(format, copy_args); + int ret = vsnprintf(s, n, format, args); + va_end(copy_args); + va_end(args); + return ret; +} + +// CXX function +CXX_INTERCEPTOR(const char*, strstr, const char *haystack, const char *needle) { + INTERCEPTOR_VREPORT + uptr len1 = internal_strlen(haystack); + CheckAndReport(haystack, len1, false); + uptr len2 = internal_strlen(needle); + CheckAndReport(needle, len2, false); + if (len1 < len2) return nullptr; + for (uptr pos = 0; pos <= len1 - len2; pos++) { + if (internal_memcmp(haystack + pos, needle, len2) == 0) + return const_cast(haystack) + pos; + } + return nullptr; +} + +CXX_INTERCEPTOR(const char*, strchr, const char *str, int c) { + INTERCEPTOR_VREPORT + // const char* result = REAL(strchr(str, c)); + const char* result = internal_strchr(str, c); + if (result != nullptr) + CheckAndReport(str, (uptr)result - (uptr)str + 1, false); + return result; +} \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_mapping.cpp b/src/mrt/libsan/asan/asan_mapping.cpp new file mode 100644 index 0000000000..d570a9b1ee --- /dev/null +++ b/src/mrt/libsan/asan/asan_mapping.cpp @@ -0,0 +1,9 @@ +#include "asan_mapping.h" + +namespace __sanitizer { + +uptr ASAN_SHADOW_BEG = -1; +uptr ASAN_SHADOW_END = 0; // to be initialized +uptr ASAN_TOTAL_PHYS_PAGES, ASAN_PAGE_SIZE; + +} // namespace __sanitizer diff --git a/src/mrt/libsan/asan/asan_mapping.h b/src/mrt/libsan/asan/asan_mapping.h new file mode 100644 index 0000000000..4a8dba1149 --- /dev/null +++ b/src/mrt/libsan/asan/asan_mapping.h @@ -0,0 +1,119 @@ +#ifndef ASAN_MAPPING_H +#define ASAN_MAPPING_H + +#include "asan_internal_defs.h" + +namespace __sanitizer { + +#define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000 +#define ASAN_SHADOW_OFFSET ASAN_SHADOW_OFFSET_CONST +#define ASAN_SHADOW_SCALE 3 +#define ASAN_PREMAP_SHADOW 0 +#define ASAN_SHADOW_GRANULARITY (1ULL << ASAN_SHADOW_SCALE) +// #define ASAN_PAGE_SIZE 4096 +extern uptr ASAN_PAGE_SIZE; // initialize while building shadow memory +extern uptr ASAN_TOTAL_PHYS_PAGES; + +// We add an extra page before and after the +// kLowShadowBeg and KHighShadowEnd +extern uptr ASAN_SHADOW_BEG; // to be initialized +extern uptr ASAN_SHADOW_END; // to be initialized + +#define MEM_TO_SHADOW(mem) (((mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET)) +#define SHADOW_TO_MEM(shadow) (((shadow) - (ASAN_SHADOW_OFFSET)) << ASAN_SHADOW_SCALE) + +static const u64 kDefaultShadowSentinel = ~(uptr)0; +static const u64 kConstShadowOffset = ASAN_SHADOW_OFFSET_CONST; + +// Initialized in __asan_init +extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; + +// The offsets of Beg and End are reversed +#define kLowMemBeg 0 +#define kLowMemEnd (ASAN_SHADOW_OFFSET ? ASAN_SHADOW_OFFSET - 1 : 0) + +#define kLowShadowBeg ASAN_SHADOW_OFFSET +#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd) + +#define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1) + +#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg) +#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd) + +#define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg) +#define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd) + +// With the zero shadow base we can not actually map pages starting from 0. +// This constant is somewhat arbitrary. +#define kZeroBaseShadowStart 0 +#define kZeroBaseMaxShadowStart (1 << 18) + +// When kLowShadowEnd = 0, we have no low shadow, the gap starts from 0 +#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 : kZeroBaseShadowStart) +#define kShadowGapEnd ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1) + +#define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0) +#define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0) + +#define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0) +#define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0) + +#define DO_ASAN_MAPPING_PROFILE 0 +extern uptr AsanMappingProfile[]; +# if DO_ASAN_MAPPING_PROFILE +# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; +# else +# define PROFILE_ASAN_MAPPING() +# endif + +static inline bool AddrIsInLowMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return a <= kLowMemEnd; +} + +static inline bool AddrIsInLowShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return a >= kLowShadowBeg && a <= kLowShadowEnd; +} + +static inline bool AddrIsInMidMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; +} + +static inline bool AddrIsInMidShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return kMidMemBeg && a >= kMidShadowBeg && a <= kMidShadowEnd; +} + +static inline bool AddrIsInHighMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return kHighMemBeg && a >= kHighMemBeg && a <= kHighMemEnd; +} + +static inline bool AddrIsInHighShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return kHighMemBeg && a >= kHighShadowBeg && a <= kHighShadowEnd; +} + +static inline bool AddrIsInShadowGap(uptr a) { + PROFILE_ASAN_MAPPING(); + if (kMidMemBeg) { + if (a <= kShadowGapEnd) + return ASAN_SHADOW_OFFSET == 0 || a >= kShadowGapBeg; + return (a >= kShadowGap2Beg && a <= kShadowGap2End) || + (a >= kShadowGap3Beg && a <= kShadowGap3End); + } + // In zero-based shadow mode we treat addresses near zero as addresses + // in shadow gap as well. + if (ASAN_SHADOW_OFFSET == 0) + return a <= kShadowGapEnd; + return a >= kShadowGapBeg && a <= kShadowGapEnd; +} + +// Must be after all calls to PROFILE_ASAN_MAPPING(). +static const uptr kAsanMappingProfileSize = __LINE__; + +} // namespace __sanitizer + +#endif // ASAN_MAPPING_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_poisoning.cpp b/src/mrt/libsan/asan/asan_poisoning.cpp new file mode 100644 index 0000000000..fe9f5f9260 --- /dev/null +++ b/src/mrt/libsan/asan/asan_poisoning.cpp @@ -0,0 +1,33 @@ +#include "asan_poisoning.h" +#include "asan_interceptors.h" +#include "asan_internal_defs.h" + +using namespace __sanitizer; + +extern "C" { + +void __asan_set_shadow_00(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0, size); +} + +void __asan_set_shadow_f1(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf1, size); +} + +void __asan_set_shadow_f2(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf2, size); +} + +void __asan_set_shadow_f3(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf3, size); +} + +void __asan_set_shadow_f5(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf5, size); +} + +void __asan_set_shadow_f8(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf8, size); +} + +} \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_poisoning.h b/src/mrt/libsan/asan/asan_poisoning.h new file mode 100644 index 0000000000..b4fda7b5d0 --- /dev/null +++ b/src/mrt/libsan/asan/asan_poisoning.h @@ -0,0 +1,23 @@ +#ifndef ASAN_POISONING_H +#define ASAN_POISONING_H +#include "asan_internal_defs.h" + +namespace __sanitizer { +extern "C" { + +void __asan_set_shadow_00(uptr addr, uptr size); + +void __asan_set_shadow_f1(uptr addr, uptr size); + +void __asan_set_shadow_f2(uptr addr, uptr size); + +void __asan_set_shadow_f3(uptr addr, uptr size); + +void __asan_set_shadow_f5(uptr addr, uptr size); + +void __asan_set_shadow_f8(uptr addr, uptr size); +} + +} // namespace __sanitizer + +#endif // ASAN_POISONING_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_report.cpp b/src/mrt/libsan/asan/asan_report.cpp new file mode 100644 index 0000000000..a6209da972 --- /dev/null +++ b/src/mrt/libsan/asan/asan_report.cpp @@ -0,0 +1,210 @@ +#include "asan_report.h" + +#include +#include + +#include "asan_alloctor.h" +#include "asan_interfaces_internal.h" +#include "asan_internal.h" +#include "asan_internal_defs.h" +#include "asan_mapping.h" +#include "asan_shadow_memory.h" +#include "asan_signal_handler.h" +#include "asan_thread.h" +#include "asan_utils.h" +#include "common_flags.h" +#include "sanitizer_printf.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +static const int PRINT_BUFF_SIZE = 4096 * 4; +static const char *line_spliter = "=================================================================\n"; + +ASAN_REPORT_ERROR(load, false, 1) +ASAN_REPORT_ERROR(load, false, 2) +ASAN_REPORT_ERROR(load, false, 4) +ASAN_REPORT_ERROR(load, false, 8) +ASAN_REPORT_ERROR(load, false, 16) +ASAN_REPORT_ERROR_N(load, true) + +ASAN_REPORT_ERROR(store, true, 1) +ASAN_REPORT_ERROR(store, true, 2) +ASAN_REPORT_ERROR(store, true, 4) +ASAN_REPORT_ERROR(store, true, 8) +ASAN_REPORT_ERROR(store, true, 16) +ASAN_REPORT_ERROR_N(store, true) + +static bool SuppressErrorReport(uptr pc) { + if (!common_flags()->suppress_equal_pcs) return false; + return false; +} + +void PrintShadowErrorTable(uptr addr) { + PrintfDecorator d; + uptr saddr = MEM_TO_SHADOW(addr); + int row_bytes = 16; + uptr print_beg_saddr = RoundDownTo(saddr, row_bytes) - row_bytes * 4; + uptr print_end_saddr = RoundUpTo(saddr, row_bytes) + row_bytes * 4 - 1; + print_beg_saddr = Max(kLowShadowBeg, print_beg_saddr); + print_end_saddr = Min(kHighShadowEnd, print_end_saddr); + + char table_buff[PRINT_BUFF_SIZE]; + internal_memset(table_buff, 0, PRINT_BUFF_SIZE); + int buff_idx = 0; + for (uptr beg = print_beg_saddr; beg <= print_end_saddr; beg += row_bytes) { + const char *row_prefix = (saddr >= beg && saddr < beg + row_bytes) ? "=>" : " "; + buff_idx += REAL(snprintf(table_buff + buff_idx, PRINT_BUFF_SIZE - buff_idx, "%s%p: ", row_prefix, (void *)beg)); + for (uptr offset = 0; offset < row_bytes; ++offset) { + su_t *to_print_saddr = (su_t *)(beg + offset); + if (beg + offset == saddr) { + buff_idx += + REAL(snprintf(table_buff + buff_idx, PRINT_BUFF_SIZE - buff_idx, "[%s]", d.GetShadowByteStr(*to_print_saddr))); + } else if (beg + offset <= print_end_saddr) { + buff_idx += + REAL(snprintf(table_buff + buff_idx, PRINT_BUFF_SIZE - buff_idx, " %s ", d.GetShadowByteStr(*to_print_saddr))); + } + } + table_buff[buff_idx] = '\n'; + buff_idx += 1; + } + table_buff[buff_idx] = '\0'; + table_buff[PRINT_BUFF_SIZE - 1] = '\0'; + Printf(table_buff); +} + +void PrintMagicValueRoutine() { + PrintfDecorator d; + char buff[PRINT_BUFF_SIZE]; + internal_memset(buff, 0, PRINT_BUFF_SIZE); + int buff_idx = 0; + buff_idx += REAL(snprintf(buff + buff_idx, PRINT_BUFF_SIZE - 1, + "Shadow byte legend (one shadow byte represents 8 application bytes):\n Addressable: " + "00\n Partially addressable: 01 02 03 04 05 06 07\n")); + #define __ASAN_SNP(format, magic) \ + buff_idx += REAL(snprintf(buff+buff_idx, PRINT_BUFF_SIZE-buff_idx-1,\ + (format), d.GetShadowByteStr((magic)))); + __ASAN_SNP(" Heap left redzone: %s\n", kAsanHeapLeftRedzoneMagic); + __ASAN_SNP(" Freed heap region: %s\n", kAsanHeapFreeMagic); + __ASAN_SNP(" Stack left redzone: %s\n", kAsanStackLeftRedzoneMagic); + __ASAN_SNP(" Stack mid redzone: %s\n", kAsanStackMidRedzoneMagic); + __ASAN_SNP(" Stack right redzone: %s\n", kAsanStackRightRedzoneMagic); + __ASAN_SNP(" Stack after return: %s\n", kAsanStackAfterReturnMagic); + __ASAN_SNP(" Stack use after scope: %s\n", kAsanStackUseAfterScopeMagic); + __ASAN_SNP(" Global redzone: %s\n", kAsanGlobalRedzoneMagic); + __ASAN_SNP(" Global init order: %s\n", kAsanInitializationOrderMagic); + __ASAN_SNP(" Poisoned by user: %s\n", kAsanUserPoisonedMemoryMagic); + __ASAN_SNP(" Container overflow: %s\n", kAsanContiguousContainerOOBMagic); + __ASAN_SNP(" Array cookie: %s\n", kAsanArrayCookieMagic); + __ASAN_SNP(" Intra object redzone: %s\n", kAsanIntraObjectRedzone); + #undef __ASAN_SNP + buff[buff_idx] = '\0'; + Printf(buff); +} + +void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal) { + if (__asan_test_only_reported_buggy_pointer) { + *__asan_test_only_reported_buggy_pointer = addr; + return; + } + if (!fatal && SuppressErrorReport(pc)) return; + ENABLE_FRAME_POINTER; + + // Optimization experiments. + // The experiments can be used to evaluate potential optimizations that remove + // instrumentation (assess false negatives). Instead of completely removing + // some instrumentation, compiler can emit special calls into runtime + // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass + // mask of experiments (exp). + // The reaction to a non-zero value of exp is to be defined. + (void)exp; + const char *behavior = is_write ? "WRITE" : "READ"; + ReportStackTrace(); + ReportErrorInfo(pc, bp, sp, addr, behavior, access_size); + PrintShadowErrorTable(addr); + PrintMagicValueRoutine(); + Die(); +} + +void ReportDoubleFree(uptr pc, uptr bp, uptr sp, uptr addr) { + const char *behavior = "double-free"; + ReportStackTrace(); + ReportErrorInfo(pc, bp, sp, addr, behavior, 0); + PrintShadowErrorTable(addr); + PrintMagicValueRoutine(); + Die(); +} + +void ReportFreeNotMalloced(uptr pc, uptr bp, uptr sp, uptr addr) { + const char *behavior = "free-not-malloced"; + ReportStackTrace(); + ReportErrorInfo(pc, bp, sp, addr, behavior, 0); + PrintShadowErrorTable(addr); + PrintMagicValueRoutine(); + Die(); +} + +void CheckAndReport(const void *membeg, uptr size, bool is_write) { + if (allocatorPtr->shadow->IsPoisonedMem(membeg, size)) { + uptr err_addr = allocatorPtr->shadow->GetPoisonedAddr(membeg, size); + GET_CALLER_PC_BP_SP; + ReportGenericError(pc, bp, sp, err_addr, is_write, size, 0, is_write); + } +} + +void ReportErrorInfo(uptr pc, uptr bp, uptr sp, uptr addr, const char *behavior, uptr access_size) { + PrintfDecorator d; + Pid pid = GetCurrentPid(); + Tid tid = GetCurrentTidOrInvalid(); + char buff[PRINT_BUFF_SIZE]; + // do not initialize with = {0}, this will call __interceptor_memset + internal_memset(buff, 0, PRINT_BUFF_SIZE); + int buff_idx = 0; + buff_idx += REAL(snprintf(buff + buff_idx, PRINT_BUFF_SIZE - 1, + "%s%s==%u==ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p%s\n", line_spliter, + d.Error(), pid, behavior, (void *)addr, (void *)pc, (void *)bp, (void *)sp, d.Default())); + buff_idx += REAL(snprintf(buff + buff_idx, PRINT_BUFF_SIZE - buff_idx - 1, "%s%s of size %lu at %p thread T%u%s\n", + d.Blue(), behavior, access_size, (void *)addr, tid, d.Default())); + buff[buff_idx] = '\0'; + Printf(buff); +} + +void ReportStackTrace() { + static uptr stack_depth = 128; + void *callstack[stack_depth]; + size_t frames = backtrace(callstack, stack_depth); + char **symbols = backtrace_symbols(callstack, frames); + for (size_t i = 0; i < frames; i++) { + if (!symbols) + Printf(" #%d %p\n", i, callstack[i]); + else + Printf(" #%d %s\n", i, symbols[i]); + } + Printf("\n"); + REAL(free(symbols)); +} + +void ReportCapturedDeadlySignal(int signal, uptr pc, uptr bp, uptr sp, SignalContext sc) { + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + PrintfDecorator d; + Pid pid = GetCurrentPid(); + Tid tid = GetCurrentTidOrInvalid(); + char *buff = (char *)REAL(malloc(PRINT_BUFF_SIZE * sizeof(char))); + int buff_idx = 0; + buff_idx += + REAL(snprintf(buff + buff_idx, PRINT_BUFF_SIZE - buff_idx - 1, + "%s%s==%u==ERROR: AddressSanitizer: %s(%d) on unknown address (pc %p bp %p sp %p T%u)\n%s", line_spliter, + d.Error(), pid, GetSignalStr(signal), signal, (void *)pc, (void *)bp, (void *)sp, tid, d.Default())); + if (sc.is_memory_access) { + const char *behavior = (sc.write_flag == SignalContext::WriteFlag::Write) ? "WRITE" : "INVALID"; + buff_idx += REAL(snprintf(buff + buff_idx, PRINT_BUFF_SIZE - buff_idx - 1, + "==%u==The signal is caused by a %s memory access.\n", pid, behavior)); + } + buff[buff_idx] = '\0'; + Printf(buff); + REAL(free(buff)); + ReportStackTrace(); + Die(); +} + +} // namespace __sanitizer diff --git a/src/mrt/libsan/asan/asan_report.h b/src/mrt/libsan/asan/asan_report.h new file mode 100644 index 0000000000..bfb7c2a8c1 --- /dev/null +++ b/src/mrt/libsan/asan/asan_report.h @@ -0,0 +1,48 @@ +#ifndef SANITIZER_REPORT_H +#define SANITIZER_REPORT_H + +#include "asan_internal_defs.h" +#include "asan_signal_handler.h" + +namespace __sanitizer { + +#define GET_CALLER_PC_BP \ + uptr bp = GET_CURRENT_FRAME(); \ + uptr pc = GET_CALLER_PC(); + +#define GET_CALLER_PC_BP_SP \ + GET_CALLER_PC_BP; \ + uptr local_stack; \ + uptr sp = (uptr)&local_stack + +#define ASAN_REPORT_ERROR(type, is_write, size) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_report_##type##size(uptr addr) { \ + GET_CALLER_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ + } + +#define ASAN_REPORT_ERROR_N(type, is_write) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_report_##type##_n(uptr addr, uptr size) { \ + GET_CALLER_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ + } + +void PrintShadowErrorTable(uptr addr); + +void ReportStackTrace(); + +void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, + uptr access_size, u32 exp, bool fatal); +void ReportDoubleFree(uptr pc, uptr bp, uptr sp, uptr addr); +void ReportFreeNotMalloced(uptr pc, uptr bp, uptr sp, uptr addr); + +void CheckAndReport(const void* membeg, uptr size, bool is_write); + +void ReportErrorInfo(uptr pc, uptr bp, uptr sp, uptr addr, const char* behavior, + uptr access_size); + +void ReportCapturedDeadlySignal(int signal, uptr pc, uptr bp, uptr sp, SignalContext sc); + +} // namespace __sanitizer + +#endif // SANITIZER_REPORT_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_rtl.cpp b/src/mrt/libsan/asan/asan_rtl.cpp new file mode 100644 index 0000000000..a88e4fa9b0 --- /dev/null +++ b/src/mrt/libsan/asan/asan_rtl.cpp @@ -0,0 +1,82 @@ +#include "asan_interceptors.h" +#include "asan_internal_defs.h" +#include "asan_report.h" +#include "asan_alloctor.h" +#include "asan_shadow_memory.h" +#include "asan_utils.h" +#include "common_flags.h" +#include "asan_signal_handler.h" + + +namespace __sanitizer { + +uptr __asan_shadow_memory_dynamic_address; // Global interface symbol. +int __asan_option_detect_stack_use_after_return; // Global interface symbol. +uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. + +uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; + +bool asan_inited = false; +bool asan_init_is_running = false; +bool asan_interceptor_inited = false; + +int InitializeAlloctor() { + AsanShadowMem *shadow = (AsanShadowMem*)REAL(malloc(sizeof(AsanShadowMem))); + shadow->InitShadow(); + allocatorPtr = (Allocator*)REAL(malloc(sizeof(Allocator))); + allocatorPtr->OnInit(shadow); +} + +void InitializePageSize() { + ASAN_TOTAL_PHYS_PAGES = sysconf(_SC_PHYS_PAGES); + ASAN_PAGE_SIZE = sysconf(_SC_PAGE_SIZE); + // ASAN_TOTAL_PHYS_PAGES = 0x100000; + // ASAN_PAGE_SIZE = 4096; +} + +void InitializeHighMemEnd() { + kHighMemEnd = (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; + kHighMemEnd |= (ASAN_PAGE_SIZE << ASAN_SHADOW_SCALE) - 1; +} + +void InitializeFlags() { + SetCommonFlagsDefaults(); + InitializeAsanFlags(); +} + +} // namespace __sanitizer + +extern "C" { + +using namespace __sanitizer; + +void NOINLINE __asan_handle_no_return() { + if (asan_init_is_running) + return; + // read the proc/pid/maps to get the mapped stack segment + // the clear the whole stack + // TODO: we need a AsanThread for each thread +} + +void __asan_init() { + if (asan_inited) return; + asan_inited = false; + asan_init_is_running = true; + asan_interceptor_inited = false; + InitializeFlags(); + InitializePageSize(); + InitializeHighMemEnd(); + InitializeAsanInterceptors(); + asan_interceptor_inited = true; + // Cannot print anything before this line!!! + VReport(ASAN_LOG_DEBUG, "InitializeAsanInterceptors\n"); + VReport(ASAN_LOG_DEBUG, "kHighMemEnd = %llx\n", kHighMemEnd); + VReport(ASAN_LOG_DEBUG, "ASAN_PAGE_SIZE = %d\n", ASAN_PAGE_SIZE); + InitializeAlloctor(); + InstallDeadlySignalHandler(DeadlySignalHandler); + VReport(ASAN_LOG_DEBUG, "Finish __asan_init\n"); + asan_inited = true; + asan_init_is_running = false; +} + +} diff --git a/src/mrt/libsan/asan/asan_shadow_memory.cpp b/src/mrt/libsan/asan/asan_shadow_memory.cpp new file mode 100644 index 0000000000..2dd3cc8892 --- /dev/null +++ b/src/mrt/libsan/asan/asan_shadow_memory.cpp @@ -0,0 +1,384 @@ +#include "asan_shadow_memory.h" +#include "asan_mapping.h" +#include "asan_thread.h" +#include "asan_utils.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux_syscall.h" +#include "asan_interceptors.h" +#include "stdio.h" +#include "asan_internal.h" +#include + +namespace __sanitizer { + +static su_t UNINITIALIZED_SHADOW = -1; + +u64 MmapFixed(uptr fixed_addr, uptr size, int additional_flags, const char* name) { + // Rounding must be down before calling this function + size = RoundUpTo(size, ASAN_PAGE_SIZE); + fixed_addr = RoundDownTo(fixed_addr, ASAN_PAGE_SIZE); + + // Using mmap to map the virtual memory address + static const int buff_size = 256; + char filepath[buff_size] = "/dev/shm/"; + Tid tid = GetCurrentTid(); + Tid pid = GetCurrentPid(); + long long ret = 0; + // ret = REAL(snprintf(filepath, buff_size, "/dev/shm/%s-%u-%u.asan.sd", name, pid, tid)); + // ASSERT((ret > 0 && ret < buff_size), "Failed to create the shadow memory file. 1\n"); + internal_strncat(filepath, name, buff_size - 70); + char pidbuff[30] = "-"; + internal_lltoa(pid, pidbuff + 1, 16); + internal_strncat(filepath, pidbuff, 30); + internal_lltoa(tid, pidbuff + 1, 16); + internal_strncat(filepath, pidbuff, 30); + if (asan_interceptor_inited) + VReport(ASAN_LOG_DEBUG, "Mmap %s %llx %llx\n", filepath, fixed_addr, size); + u64 fd = internal_openat(0, filepath, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU); + ASSERT((fd >= 0), "Failed to create the shadow memory file. 2\n"); + ret = internal_ftruncate(fd, size); + ASSERT((ret == 0), "Failed to create the shadow memory file. 3\n"); + ret = internal_unlink(filepath); + ASSERT((ret == 0), "Failed to create the shadow memory file. 4\n"); + ret = internal_mmap((void *)fixed_addr, size, PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_FIXED | MAP_ANON | additional_flags, fd, 0); + if (ret == -1) { + VReport(ASAN_LOG_ERR, "Failed to map shadow memory file to virtual memory. errno=%i\n", errno); + ASSERT(false, ""); + } + return fd; +} + +int AsanShadowMem::InitShadow() { + scale = ASAN_SHADOW_SCALE; + scale_factor = 1 << scale; + half_scale_factor = 1 << (scale - 1); + + uptr mmap_size = kLowShadowEnd - kLowShadowBeg + 1; + uptr start_addr = kLowShadowBeg; + char buff[30] = {0}; + while (start_addr < kHighShadowEnd) { + internal_lltoa(start_addr, buff, 16); + MmapFixed(start_addr, mmap_size, 0, buff); + start_addr += mmap_size; + } + size = kHighShadowEnd - kLowShadowBeg; + ASAN_SHADOW_BEG = kLowShadowBeg - ASAN_PAGE_SIZE; + ASAN_SHADOW_END = kHighShadowEnd + ASAN_PAGE_SIZE; + beg = ASAN_SHADOW_BEG; + end = ASAN_SHADOW_END; + // Too large size, we do not initialize it at the beginning + // internal_memset((void *)kLowShadowBeg, UNINITIALIZED_SHADOW, size); + return 0; +} + +int AsanShadowMem::DeleteShadow() {} + +su_t AsanShadowMem::PoisonUnitHeadBytes(su_t old_value, su_t new_value, int affected_bytes) { + CHECK((affected_bytes <= scale_factor && affected_bytes > 0)); + su_t ret_value = old_value; + if (affected_bytes == scale_factor) { + ret_value = new_value; + } else { + // the first several bytes are poisoned + // but the last several bytes maybe still usable + // To supress FPs, all 8 bytes are treated as not poisoned + if (old_value == 0) { /*do nothing*/ + } else if (old_value > 0) { + if (old_value > affected_bytes) { /*do nothing since several bytes are still accessible*/ + } else { + ret_value = new_value; + } + } else { + if (affected_bytes > half_scale_factor) { + ret_value = new_value; + } else { + if (old_value == UNINITIALIZED_SHADOW) { + ret_value = new_value; + } else { /*do nothing*/ + } + } + } + } + return ret_value; +} + +su_t AsanShadowMem::PoisonUnitTailBytes(su_t old_value, su_t new_value, int affected_bytes) { + CHECK((affected_bytes <= scale_factor && affected_bytes > 0)); + su_t ret_value = old_value; + if (affected_bytes == scale_factor) { + // the beg is aligned + ret_value = new_value; + } else { + // the last several bytes are poisoned + // but several first bytes are still usable + if (old_value == 0) { + ret_value = scale_factor - affected_bytes; + } else if (old_value > 0) { + if (old_value + affected_bytes > scale_factor) { + // there is overlap between usable and poisoned + ret_value = scale_factor - affected_bytes; + } else { /*do nothing since no overlap*/ + } + } else { + // the 8 bytes are not readable anyway + if (affected_bytes > half_scale_factor) { + ret_value = new_value; + } else { + if (old_value == UNINITIALIZED_SHADOW) { + // uninitialized yet, to be poisoned + ret_value = new_value; + } else { /*do nothing*/ + } + } + } + } + return ret_value; +} + +su_t AsanShadowMem::PoisonUnit(su_t old_value, su_t new_value, int beg_byte, int end_byte) { + CHECK(beg_byte >= 0); + CHECK(end_byte < scale_factor); + CHECK(beg_byte <= end_byte); + su_t ret_value = old_value; + if (old_value == 0) { + if (end_byte < scale_factor - 1) { + // some bytes at tail are valid + ret_value = 0; + } else { + // util beg_byte, all bytes are valid + // when beg_byte == 0, all utils are poisoned + if (beg_byte == 0) ret_value = new_value; + else ret_value = scale_factor - beg_byte; + } + } else { + if (old_value > 0) { + // consider the overlap [0, old_value-1] [beg_byte, end_byte] + if (beg_byte > old_value - 1) { + // no overlap and do nothing + } else if (end_byte >= old_value - 1) { + // overlap [beg_byte, old_value-1] + if (beg_byte > 0) + ret_value = beg_byte; + else + ret_value = new_value; + } else { + // some bytes in [end_byte, old_value - 1] are valid + // do nothing + } + } + } + return ret_value; +} + +int AsanShadowMem::PoisonMem(const void *membeg, uptr size, su_t v) { + uptr tmpbeg = (uptr)membeg; + uptr tmpend = tmpbeg + size - 1; + uptr shadowbeg = MEM_TO_SHADOW(tmpbeg); + // the affected memory may not be aligned to the scale_factor + uptr alignedbeg = RoundDownTo(tmpbeg, scale_factor); + // uptr begAffectedBytes = scale_factor - (tmpbeg - alignedbeg); // [1, scale_factor] + uptr beg_byte = tmpbeg - alignedbeg; + + uptr alignedend = RoundUpTo(tmpend, scale_factor) - 1; + if (alignedend < tmpend) alignedend += scale_factor; + uptr end_byte = tmpend - (alignedend + 1 - scale_factor); + + uptr shadowSize = (alignedend - alignedbeg) / scale_factor + 1; + uptr shadowend = shadowbeg + shadowSize - 1; + + // TODO: the following code should be thread safe + if (shadowSize > 1) { + su_t firstByteValue = *(su_t *)(shadowbeg); + firstByteValue = PoisonUnitTailBytes(firstByteValue, v, scale_factor - beg_byte); + + su_t lastByteValue = *(su_t *)(shadowend); + lastByteValue = PoisonUnitHeadBytes(lastByteValue, v, end_byte + 1); + internal_memset((void *)shadowbeg, v, shadowSize); + // end TODO + if (firstByteValue != v) { + *((su_t *)shadowbeg) = firstByteValue; + } + if (lastByteValue != v) { + *((su_t *)shadowend) = lastByteValue; + } + } else { + su_t firstByteValue = *(su_t *)(shadowbeg); + *((su_t *)shadowbeg) = PoisonUnit(firstByteValue, v, beg_byte, end_byte); + } + return 0; +} + +su_t AsanShadowMem::UnpoisonUnitHeadBytes(su_t old_value, int affected_bytes) { + CHECK((affected_bytes <= scale_factor && affected_bytes > 0)); + if (old_value == 0) + return 0; + else if (affected_bytes == scale_factor) + return 0; + else if (old_value < 0 || old_value >= scale_factor) + return affected_bytes; // affected_bytes < scale_factor + else + return Max(affected_bytes, old_value); +} + +su_t AsanShadowMem::UnpoisonUnitTailBytes(su_t old_value, int affected_bytes) { + CHECK((affected_bytes < scale_factor && affected_bytes > 0)); + return 0; +} + +su_t AsanShadowMem::UnpoisonUnit(su_t old_value, int beg_byte, int end_byte) { + CHECK(beg_byte >= 0); + CHECK(end_byte < scale_factor); + CHECK(beg_byte <= end_byte); + su_t ret_value = old_value; + if (old_value == 0) { + // unpoison the same memory again? + // do nothing + } else { + if (old_value < 0 || old_value >= scale_factor) { + // all bytes are invalid + ret_value = (end_byte + 1) & 0x07; + } else { + // consider the overlap between [0, old_value - 1] and [beg_byte, end_byte] + if (end_byte <= old_value - 1) { + // do nothing + } else { + // no matter if there is a overlap, we set [0, end_byte] unpoisoned + ret_value = end_byte + 1; + } + } + } + return ret_value; +} + +int AsanShadowMem::UnpoisonMem(const void *membeg, uptr size) { + uptr tmpbeg = (uptr)membeg; + uptr tmpend = tmpbeg + size - 1; + uptr shadowbeg = MEM_TO_SHADOW(tmpbeg); + // the affected memory may not be aligned to the scale_factor + uptr alignedbeg = RoundDownTo(tmpbeg, scale_factor); + // uptr begAffectedBytes = scale_factor - (tmpbeg - alignedbeg); // [1, scale_factor] + uptr beg_byte = tmpbeg - alignedbeg; + + uptr alignedend = RoundUpTo(tmpend, scale_factor) - 1; + if (alignedend < tmpend) alignedend += scale_factor; + uptr end_byte = tmpend - (alignedend + 1 - scale_factor); + + uptr shadowSize = (alignedend - alignedbeg) / scale_factor + 1; + uptr shadowend = shadowbeg + shadowSize - 1; + + if (shadowSize > 1) { + su_t firstByteValue = 0; // must be set to 0 + + su_t lastByteValue = 0; + if (end_byte != scale_factor - 1) { + lastByteValue = *(su_t *)(shadowend); + lastByteValue = UnpoisonUnitHeadBytes(lastByteValue, end_byte + 1); + } + internal_memset((void *)shadowbeg, 0, shadowSize); + if (lastByteValue != 0) { + *((su_t *)shadowend) = lastByteValue; + } + } else { + su_t firstByteValue = *(su_t *)(shadowbeg); + *((su_t *)shadowbeg) = UnpoisonUnit(firstByteValue, beg_byte, end_byte); + } + return 0; +} + +bool AsanShadowMem::IsPoisonedUnit(su_t old_value, int beg_byte, int end_byte) { + CHECK(beg_byte >= 0); + CHECK(end_byte < scale_factor); + CHECK(beg_byte <= end_byte); + if (old_value == 0) + return false; + else if (old_value < 0 || old_value > scale_factor - 1) + return true; + else { + // [0, old_value-1] are valid + if (end_byte > old_value - 1) + return true; + else + return false; + } +} + +bool AsanShadowMem::IsPoisonedMem(const void *membeg, uptr size) { + if (size == 0) return false; + uptr tmpbeg = (uptr)membeg; + uptr tmpend = tmpbeg + size - 1; + uptr shadowbeg = MEM_TO_SHADOW(tmpbeg); + // the affected memory may not be aligned to the scale_factor + uptr alignedbeg = RoundDownTo(tmpbeg, scale_factor); + // uptr begAffectedBytes = scale_factor - (tmpbeg - alignedbeg); // [1, scale_factor] + uptr beg_byte = tmpbeg - alignedbeg; + + uptr alignedend = RoundUpTo(tmpend, scale_factor) - 1; + if (alignedend < tmpend) alignedend += scale_factor; + uptr end_byte = tmpend - (alignedend + 1 - scale_factor); + + uptr shadowSize = (alignedend - alignedbeg) / scale_factor + 1; + uptr shadowend = shadowbeg + shadowSize - 1; + + if (shadowSize > 1) { + su_t firstByteValue = *(su_t *)(shadowbeg); + if (IsPoisonedUnit(firstByteValue, beg_byte, scale_factor - 1)) return true; + su_t lastByteValue = *(su_t *)(shadowend); + if (IsPoisonedUnit(lastByteValue, 0, end_byte)) return true; + // all bytes in [shadowbeg + 1, shadowend - 1] should be 0 + for (uptr i = shadowbeg + 1; i < shadowend - 1; ++i) { + if (*((su_t *)i) != 0) return true; + } + return false; + } else { + su_t firstByteValue = *(su_t *)(shadowbeg); + return IsPoisonedUnit(firstByteValue, beg_byte, end_byte); + } +} + +bool AsanShadowMem::IsFreeAfterUse(const void* membeg) { + uptr shadowbeg = MEM_TO_SHADOW((uptr)membeg); + return kAsanHeapFreeMagic == *((su_t*)shadowbeg); +} + +uptr AsanShadowMem::GetPoisonedAddr(const void *membeg, uptr size) { + if (size == 0) return false; + uptr tmpbeg = (uptr)membeg; + uptr tmpend = tmpbeg + size - 1; + uptr shadowbeg = MEM_TO_SHADOW(tmpbeg); + // the affected memory may not be aligned to the scale_factor + uptr alignedbeg = RoundDownTo(tmpbeg, scale_factor); + // uptr begAffectedBytes = scale_factor - (tmpbeg - alignedbeg); // [1, scale_factor] + uptr beg_byte = tmpbeg - alignedbeg; + + uptr alignedend = RoundUpTo(tmpend, scale_factor) - 1; + if (alignedend < tmpend) alignedend += scale_factor; + uptr end_byte = tmpend - (alignedend + 1 - scale_factor); + + uptr shadowSize = (alignedend - alignedbeg) / scale_factor + 1; + uptr shadowend = shadowbeg + shadowSize - 1; + + if (shadowSize > 1) { + su_t firstByteValue = *(su_t *)(shadowbeg); + if (IsPoisonedUnit(firstByteValue, beg_byte, scale_factor - 1)) return tmpbeg; + + su_t lastByteValue = *(su_t *)(shadowend); + if (IsPoisonedUnit(lastByteValue, 0, end_byte)) return tmpend; + // all bytes in [shadowbeg + 1, shadowend - 1] should be 0 + // TODO: read 8 bytes per iteration + for (uptr i = shadowbeg + 1; i < shadowend - 1; ++i) { + if (*((su_t *)i) != 0) return SHADOW_TO_MEM(i); + } + return 0; + } else { + su_t firstByteValue = *(su_t *)(shadowbeg); + if (IsPoisonedUnit(firstByteValue, beg_byte, end_byte)) { + return tmpbeg; + } + else { + return 0; + } + } +} + +} // namespace __sanitizer \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_shadow_memory.h b/src/mrt/libsan/asan/asan_shadow_memory.h new file mode 100644 index 0000000000..5c5a7f9a3a --- /dev/null +++ b/src/mrt/libsan/asan/asan_shadow_memory.h @@ -0,0 +1,48 @@ +#ifndef ASAN_SHADOW_MEMORY +#define ASAN_SHADOW_MEMORY +#include "asan_internal_defs.h" +#include "asan_mapping.h" + + +#define SHADOW_UNIT_TYPE char + +namespace __sanitizer { + +typedef SHADOW_UNIT_TYPE su_t; + +u64 MmapFixed(uptr fixed_addr, uptr size, int additional_flags, const char* name); + +struct AsanShadowMem { + fd_t high_mmap_fd; + fd_t mid_mmap_fd; + fd_t low_mmap_fd; + int scale; + int scale_factor; + int half_scale_factor; + uptr beg; + uptr end; + u64 size; + + int InitShadow(); + int DeleteShadow(); + int PoisonMem(const void* membeg, uptr size, su_t v); + int UnpoisonMem(const void* membeg, uptr size); + bool IsPoisonedMem(const void* membeg, uptr size); + bool IsFreeAfterUse(const void* membeg); + uptr GetPoisonedAddr(const void* membeg, uptr size); + + su_t PoisonUnitHeadBytes(su_t old_value, su_t new_value, int affected_bytes); + su_t PoisonUnitTailBytes(su_t old_value, su_t new_value, int affected_bytes); + su_t PoisonUnit(su_t old_value, su_t new_value, int beg_byte, int end_byte); + + su_t UnpoisonUnitHeadBytes(su_t old_value, int affected_bytes); + su_t UnpoisonUnitTailBytes(su_t old_value, int affected_bytes); + su_t UnpoisonUnit(su_t old_value, int beg_byte, int end_byte); + + bool IsPoisonedUnit(su_t old_value, int beg_byte, int end_byte); +}; + +} // namespace __sanitizer + + +#endif // ASAN_SHADOW_MEMORY \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_signal_handler.h b/src/mrt/libsan/asan/asan_signal_handler.h new file mode 100644 index 0000000000..08af722409 --- /dev/null +++ b/src/mrt/libsan/asan/asan_signal_handler.h @@ -0,0 +1,49 @@ +#ifndef ASAN_SIGNAL_HANDLER_H +#define ASAN_SIGNAL_HANDLER_H +#include "asan_internal_defs.h" +#include "asan_internal.h" +#include "asan_flags.h" +#include + +namespace __sanitizer { + +inline const char* GetSignalStr(int signal) { + switch (signal) + { + case SIGFPE: + return "FPE"; + case SIGILL: + return "ILL"; + case SIGABRT: + return "ABRT"; + case SIGSEGV: + return "SEGV"; + case SIGBUS: + return "BUS"; + case SIGTRAP: + return "TRAP"; + default: + return "UNKNOWN SIGNAL"; + } +} + +struct SignalContext { + siginfo_t *siginfo; + ucontext_t *context; + uptr addr; + bool is_memory_access; + enum WriteFlag { Unknown, Read, Write } write_flag; + bool is_true_faulting_addr; + + SignalContext(siginfo_t* siginfo, ucontext_t* context); +}; + +typedef void (*SignalHandlerFunc)(int, siginfo_t *, void *); + +void DeadlySignalHandler(int signal, siginfo_t* info, void* context); + +void InstallDeadlySignalHandler(SignalHandlerFunc); + +} // namespace __sanitizer + +#endif // ASAN_SIGNAL_HANDLER_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_signal_handler_linux.cpp b/src/mrt/libsan/asan/asan_signal_handler_linux.cpp new file mode 100644 index 0000000000..7a6429d2e4 --- /dev/null +++ b/src/mrt/libsan/asan/asan_signal_handler_linux.cpp @@ -0,0 +1,56 @@ +#include "asan_signal_handler.h" +#include "asan_internal_defs.h" +#include "asan_internal.h" +#include "asan_interceptors.h" +#include +#include +#include "asan_report.h" + +namespace __sanitizer { + +SignalContext::SignalContext(siginfo_t* siginfo, ucontext_t* context) + : siginfo(siginfo), context(context) { + const siginfo_t* si = static_cast(siginfo); + addr = (uptr)(si->si_addr); + is_memory_access = si->si_signo == SIGSEGV || si->si_signo == SIGBUS; + + // uptr err = context->uc_mcontext.gregs[REG_ERR]; + // write_flag = err & PF_WRITE ? Write : Read; + if (si->si_code == SEGV_ACCERR) { + write_flag = Write; + } + else if (si->si_code == SEGV_MAPERR) { + write_flag = Unknown; + } + is_true_faulting_addr = si->si_signo == SIGSEGV && si->si_code != 128; +} + +void DeadlySignalHandler(int signal, siginfo_t* info, void* context) { + VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__); + SignalContext sc((siginfo_t*)info, (ucontext_t*)context); + GET_CALLER_PC_BP_SP; + ReportCapturedDeadlySignal(signal, pc, bp, sp, sc); + Die(); +} + +void InstallDeadlySignalHandler(SignalHandlerFunc handler) { + + stack_t ss; + ss.ss_sp = REAL(malloc(SIGSTKSZ)); + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + sigaltstack(&ss, NULL); + + struct sigaction action; + action.sa_sigaction = handler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGABRT, &action, NULL); + sigaction(SIGBUS, &action, NULL); + sigaction(SIGTRAP, &action, NULL); + sigaction(SIGFPE, &action, NULL); + sigaction(SIGILL, &action, NULL); +} + +} // namespace __sanitizer diff --git a/src/mrt/libsan/asan/asan_stubs.cpp b/src/mrt/libsan/asan/asan_stubs.cpp new file mode 100644 index 0000000000..2dc694499e --- /dev/null +++ b/src/mrt/libsan/asan/asan_stubs.cpp @@ -0,0 +1,67 @@ +#ifdef ASAN_REPORT_STUB + +#include "asan_stubs.h" +#include "asan_internal_defs.h" +#include "asan_shadow_memory.h" +#include "asan_mapping.h" +#include "asan_utils.h" +#include "stdio.h" + +using namespace __sanitizer; + +extern "C" { + +void printf_shadow_bytes(uptr addr) { + Printf("Shadow range [%llx, %llx]\n\n", ASAN_SHADOW_OFFSET, ASAN_SHADOW_END); + uptr saddr = MEM_TO_SHADOW(addr); + int row_bytes = 8; + uptr print_beg_saddr = RoundDownTo(saddr, row_bytes) - row_bytes; + uptr print_end_saddr = RoundUpTo(saddr, row_bytes) + row_bytes - 1; + print_beg_saddr = Max(ASAN_SHADOW_OFFSET, print_beg_saddr); + print_end_saddr = Min(ASAN_SHADOW_END, print_end_saddr); + for (uptr beg = print_beg_saddr; beg <= print_end_saddr; beg += row_bytes) { + Printf("0x%llx: ", beg); + for (uptr offset = 0; offset < row_bytes; ++offset) { + su_t * to_print_saddr = (su_t*)(beg + offset); + if (beg + offset == saddr) + Printf(" [%x] ", (*to_print_saddr) & 0x0ff); + else + Printf(" %x ", (*to_print_saddr) & 0x0ff); + } + Printf("\n"); + } +} + +INTERFACE_ATTRIBUTE void __asan_report_load1(uptr addr) { + Printf("__asan_report_load1\n"); + printf_shadow_bytes(addr); + Die(); +} + +INTERFACE_ATTRIBUTE void __asan_report_load2(uptr addr) { + Printf("__asan_report_load2\n"); + printf_shadow_bytes(addr); + Die(); +} + +INTERFACE_ATTRIBUTE void __asan_report_load4(uptr addr) { + Printf("__asan_report_load4\n"); + printf_shadow_bytes(addr); + Die(); +} + +INTERFACE_ATTRIBUTE void __asan_report_load8(uptr addr) { + Printf("__asan_report_load8\n"); + printf_shadow_bytes(addr); + Die(); +} + +INTERFACE_ATTRIBUTE void __asan_report_load16(uptr addr) { + Printf("__asan_report_load16\n"); + printf_shadow_bytes(addr); + Die(); +} + +} + +#endif // ASAN_REPORT_STUB \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_stubs.h b/src/mrt/libsan/asan/asan_stubs.h new file mode 100644 index 0000000000..8997de3894 --- /dev/null +++ b/src/mrt/libsan/asan/asan_stubs.h @@ -0,0 +1,17 @@ +#ifndef ASAN_STUBS_H +#define ASAN_STUBS_H + +#include "asan_internal_defs.h" + +namespace __sanitizer { + +extern "C" { + +INTERFACE_ATTRIBUTE void __asan_report_load4(__sanitizer::uptr x); + +} +} // namespace __sanitizer + + + +#endif // ASAN_STUBS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_thread.h b/src/mrt/libsan/asan/asan_thread.h new file mode 100644 index 0000000000..120dee52fd --- /dev/null +++ b/src/mrt/libsan/asan/asan_thread.h @@ -0,0 +1,38 @@ +#ifndef SANITIZER_THREAD_H +#define SANITIZER_THREAD_H +#include "asan_internal_defs.h" +#include "pthread.h" +#include "sys/types.h" +#include "sys/syscall.h" +#include "sys/signal.h" +#include "unistd.h" + +namespace __sanitizer { + +inline Tid GetCurrentTid() { + Tid tid; + tid = syscall(SYS_gettid); + return tid; +} + + +inline Pid GetCurrentPid() { + Pid pid; + pid = getpid(); + return pid; +} + +// This merely works for Linux OS +inline bool IsMainThread() { + return GetCurrentTid() == GetCurrentPid(); +} + + +inline Tid GetCurrentTidOrInvalid() { + return IsMainThread() ? kMainTid : kInvalidTid; +} + + +} // namespace __sanitizer + +#endif // SANITIZER_THREAD_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/asan_utils.h b/src/mrt/libsan/asan/asan_utils.h new file mode 100644 index 0000000000..fcfe262411 --- /dev/null +++ b/src/mrt/libsan/asan/asan_utils.h @@ -0,0 +1,97 @@ +#ifndef SANITIZER_UTILS_H +#define SANITIZER_UTILS_H +#include "asan_internal_defs.h" +#include "pthread.h" +#include "unistd.h" + + +namespace __sanitizer { + +extern "C" { +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +} + +inline uptr MostSignificantSetBitIndex(uptr x) { + unsigned long up; + // On Arm, it is __buildin_clz + up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); + // up = SANITIZER_WORDSIZE - 1 - __builtin_clz(x); + // _BitScanReverse(&up, x); + return up; +} + +inline uptr LeastSignificantSetBitIndex(uptr x) { + unsigned long up; + up = __builtin_ctzl(x); + // _BitScanForward(&up, x); + return up; +} + +inline constexpr bool IsPowerOfTwo(uptr x) { + return (x & (x - 1)) == 0; +} + + +inline uptr RoundUpToPowerOfTwo(uptr size) { + if (IsPowerOfTwo(size)) return size; + + uptr up = MostSignificantSetBitIndex(size); + return 1ULL << (up + 1); +} + +inline constexpr uptr RoundUpTo(uptr size, uptr boundary) { + return (size + boundary - 1) & ~(boundary - 1); +} + +inline constexpr uptr RoundDownTo(uptr x, uptr boundary) { + return x & ~(boundary - 1); +} + +inline constexpr bool IsAligned(uptr a, uptr alignment) { + return (a & (alignment - 1)) == 0; +} + +inline uptr Log2(uptr x) { + return LeastSignificantSetBitIndex(x); +} + +// Don't use std::min, std::max or std::swap, to minimize dependency +// on libstdc++. +template +constexpr T Min(T a, T b) { + return a < b ? a : b; +} +template +constexpr T Max(T a, T b) { + return a > b ? a : b; +} +template +constexpr T Abs(T a) { + return a < 0 ? -a : a; +} +template void Swap(T& a, T& b) { + T tmp = a; + a = b; + b = tmp; +} + +// Char handling +inline bool IsSpace(int c) { + return (c == ' ') || (c == '\n') || (c == '\t') || + (c == '\f') || (c == '\r') || (c == '\v'); +} +inline bool IsDigit(int c) { + return (c >= '0') && (c <= '9'); +} +inline int ToLower(int c) { + return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; +} + + + +} // namespace __sanitizer + + + +#endif // SANITIZER_UTILS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/common_flags.h b/src/mrt/libsan/asan/common_flags.h new file mode 100644 index 0000000000..f6b9db32c1 --- /dev/null +++ b/src/mrt/libsan/asan/common_flags.h @@ -0,0 +1,38 @@ +#ifndef SANITIZER_COMMON_FLAGS_H +#define SANITIZER_COMMON_FLAGS_H + +#include "asan_internal_defs.h" + + +namespace __sanitizer { + +enum HandleSignalMode { + kHandleSignalNo, + kHandleSignalYes, + kHandleSignalExclusive, +}; + + +class CommonFlags { +public: +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "sanitizer_flags.inc" +#undef COMMON_FLAGS + void SetDefaults(); + void CopyFrom(const CommonFlags &other); +}; + + +// Functions to get/set global CommonFlags shared by all sanitizer runtimes: +extern CommonFlags common_flags_dont_use; +inline const CommonFlags *common_flags() { + return &common_flags_dont_use; +} + +inline void SetCommonFlagsDefaults() { + common_flags_dont_use.SetDefaults(); +} + +} + +#endif // SANITIZER_COMMON_FLAGS_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/sanitizer_flags.cpp b/src/mrt/libsan/asan/sanitizer_flags.cpp new file mode 100644 index 0000000000..634de335ee --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_flags.cpp @@ -0,0 +1,20 @@ +#include "asan_internal_defs.h" +#include "common_flags.h" +#include "string.h" + + +namespace __sanitizer { + +CommonFlags common_flags_dont_use; + +void CommonFlags::SetDefaults() { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sanitizer_flags.inc" +#undef COMMON_FLAG +} + +void CommonFlags::CopyFrom(const CommonFlags &other) { + memcpy(this, &other, sizeof(*this)); +} + +} diff --git a/src/mrt/libsan/asan/sanitizer_flags.inc b/src/mrt/libsan/asan/sanitizer_flags.inc new file mode 100644 index 0000000000..4a0ec7ea0e --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_flags.inc @@ -0,0 +1,279 @@ +//===-- sanitizer_flags.h ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file describes common flags available in all sanitizers. +// +//===----------------------------------------------------------------------===// + +#ifndef COMMON_FLAG +#error "Define COMMON_FLAG prior to including this file!" +#endif + +// COMMON_FLAG(Type, Name, DefaultValue, Description) +// Supported types: bool, const char *, int, uptr. +// Default value must be a compile-time constant. +// Description must be a string literal. + +#define SANITIZER_LINUX 1 +#define SANITIZER_ANDROID 0 +#define SANITIZER_APPLE 0 +#define SANITIZER_WINDOWS 0 +#define SANITIZER_GO 0 +#define SANITIZER_ARM 1 +#define SANITIZER_FUCHSIA 0 + +COMMON_FLAG( + bool, symbolize, true, + "If set, use the online symbolizer from common sanitizer runtime to turn " + "virtual addresses to file/line locations.") +COMMON_FLAG( + const char *, external_symbolizer_path, nullptr, + "Path to external symbolizer. If empty, the tool will search $PATH for " + "the symbolizer.") +COMMON_FLAG( + bool, allow_addr2line, false, + "If set, allows online symbolizer to run addr2line binary to symbolize " + "stack traces (addr2line will only be used if llvm-symbolizer binary is " + "unavailable.") +COMMON_FLAG(const char *, strip_path_prefix, "", + "Strips this prefix from file paths in error reports.") +COMMON_FLAG(bool, fast_unwind_on_check, false, + "If available, use the fast frame-pointer-based unwinder on " + "internal CHECK failures.") +COMMON_FLAG(bool, fast_unwind_on_fatal, false, + "If available, use the fast frame-pointer-based unwinder on fatal " + "errors.") +// ARM thumb/thumb2 frame pointer is inconsistent on GCC and Clang [1] +// and fast-unwider is also unreliable with mixing arm and thumb code [2]. +// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172 +// [2] https://bugs.llvm.org/show_bug.cgi?id=44158 +COMMON_FLAG(bool, fast_unwind_on_malloc, + !(SANITIZER_LINUX && !SANITIZER_ANDROID && SANITIZER_ARM), + "If available, use the fast frame-pointer-based unwinder on " + "malloc/free.") +COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") +COMMON_FLAG(int, malloc_context_size, 1, + "Max number of stack frames kept for each allocation/deallocation.") +COMMON_FLAG( + const char *, log_path, nullptr, + "Write logs to \"log_path.pid\". The special values are \"stdout\" and " + "\"stderr\". If unspecified, defaults to \"stderr\".") +COMMON_FLAG( + bool, log_exe_name, false, + "Mention name of executable when reporting error and " + "append executable name to logs (as in \"log_path.exe_name.pid\").") +COMMON_FLAG(const char *, log_suffix, nullptr, + "String to append to log file name, e.g. \".txt\".") +COMMON_FLAG( + bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE, + "Write all sanitizer output to syslog in addition to other means of " + "logging.") +COMMON_FLAG( + int, verbosity, 0, + "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") +COMMON_FLAG(bool, strip_env, true, + "Whether to remove the sanitizer from DYLD_INSERT_LIBRARIES to " + "avoid passing it to children on Apple platforms. Default is true.") +COMMON_FLAG(bool, verify_interceptors, true, + "Verify that interceptors are working on Apple platforms. Default " + "is true.") +COMMON_FLAG(bool, detect_leaks, !SANITIZER_APPLE, "Enable memory leak detection.") +COMMON_FLAG( + bool, leak_check_at_exit, true, + "Invoke leak checking in an atexit handler. Has no effect if " + "detect_leaks=false, or if __lsan_do_leak_check() is called before the " + "handler has a chance to run.") +COMMON_FLAG(bool, allocator_may_return_null, false, + "If false, the allocator will crash instead of returning 0 on " + "out-of-memory.") +COMMON_FLAG(bool, print_summary, true, + "If false, disable printing error summaries in addition to error " + "reports.") +COMMON_FLAG(int, print_module_map, 0, + "Print the process module map where supported (0 - don't print, " + "1 - print only once before process exits, 2 - print after each " + "report).") +COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") +#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ + "Controls custom tool's " #signal " handler (0 - do not registers the " \ + "handler, 1 - register the handler and allow user to set own, " \ + "2 - registers the handler and block user from changing it). " +COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV)) +COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGBUS)) +COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT)) +COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL)) +COMMON_FLAG(HandleSignalMode, handle_sigtrap, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGTRAP)) +COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE)) +#undef COMMON_FLAG_HANDLE_SIGNAL_HELP +COMMON_FLAG(bool, allow_user_segv_handler, true, + "Deprecated. True has no effect, use handle_sigbus=1. If false, " + "handle_*=1 will be upgraded to handle_*=2.") +COMMON_FLAG(bool, use_sigaltstack, true, + "If set, uses alternate stack for signal handling.") +COMMON_FLAG(bool, detect_deadlocks, true, + "If set, deadlock detection is enabled.") +COMMON_FLAG( + uptr, clear_shadow_mmap_threshold, 64 * 1024, + "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " + "memset(). This is the threshold size in bytes.") +COMMON_FLAG(const char *, color, "auto", + "Colorize reports: (always|never|auto).") +COMMON_FLAG( + bool, legacy_pthread_cond, false, + "Enables support for dynamic libraries linked with libpthread 2.2.5.") +COMMON_FLAG(bool, intercept_tls_get_addr, false, "Intercept __tls_get_addr.") +COMMON_FLAG(bool, help, false, "Print the flag descriptions.") +COMMON_FLAG(uptr, mmap_limit_mb, 0, + "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " + "not a user-facing flag, used mosly for testing the tools") +COMMON_FLAG(uptr, hard_rss_limit_mb, 0, + "Hard RSS limit in Mb." + " If non-zero, a background thread is spawned at startup" + " which periodically reads RSS and aborts the process if the" + " limit is reached") +COMMON_FLAG(uptr, soft_rss_limit_mb, 0, + "Soft RSS limit in Mb." + " If non-zero, a background thread is spawned at startup" + " which periodically reads RSS. If the limit is reached" + " all subsequent malloc/new calls will fail or return NULL" + " (depending on the value of allocator_may_return_null)" + " until the RSS goes below the soft limit." + " This limit does not affect memory allocations other than" + " malloc/new.") +COMMON_FLAG(uptr, max_allocation_size_mb, 0, + "If non-zero, malloc/new calls larger than this size will return " + "nullptr (or crash if allocator_may_return_null=false).") +COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") +COMMON_FLAG(s32, allocator_release_to_os_interval_ms, + ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000, + "Only affects a 64-bit allocator. If set, tries to release unused " + "memory to the OS, but not more often than this interval (in " + "milliseconds). Negative values mean do not attempt to release " + "memory to the OS.\n") +COMMON_FLAG(bool, can_use_proc_maps_statm, true, + "If false, do not attempt to read /proc/maps/statm." + " Mostly useful for testing sanitizers.") +COMMON_FLAG( + bool, coverage, false, + "If set, coverage information will be dumped at program shutdown (if the " + "coverage instrumentation was enabled at compile time).") +COMMON_FLAG(const char *, coverage_dir, ".", + "Target directory for coverage dumps. Defaults to the current " + "directory.") +COMMON_FLAG(const char *, cov_8bit_counters_out, "", + "If non-empty, write 8bit counters to this file. ") +COMMON_FLAG(const char *, cov_pcs_out, "", + "If non-empty, write the coverage pc table to this file. ") +COMMON_FLAG(bool, full_address_space, false, + "Sanitize complete address space; " + "by default kernel area on 32-bit platforms will not be sanitized") +COMMON_FLAG(bool, print_suppressions, true, + "Print matched suppressions at exit.") +COMMON_FLAG( + bool, disable_coredump, (SANITIZER_WORDSIZE == 64) && !SANITIZER_GO, + "Disable core dumping. By default, disable_coredump=1 on 64-bit to avoid" + " dumping a 16T+ core file. Ignored on OSes that don't dump core by" + " default and for sanitizers that don't reserve lots of virtual memory.") +COMMON_FLAG(bool, use_madv_dontdump, true, + "If set, instructs kernel to not store the (huge) shadow " + "in core file.") +COMMON_FLAG(bool, symbolize_inline_frames, true, + "Print inlined frames in stacktraces. Defaults to true.") +COMMON_FLAG(bool, demangle, true, "Print demangled symbols.") +COMMON_FLAG(bool, symbolize_vs_style, false, + "Print file locations in Visual Studio style (e.g: " + " file(10,42): ...") +COMMON_FLAG(int, dedup_token_length, 0, + "If positive, after printing a stack trace also print a short " + "string token based on this number of frames that will simplify " + "deduplication of the reports. " + "Example: 'DEDUP_TOKEN: foo-bar-main'. Default is 0.") +COMMON_FLAG(const char *, stack_trace_format, "DEFAULT", + "Format string used to render stack frames. " + "See sanitizer_stacktrace_printer.h for the format description. " + "Use DEFAULT to get default format.") +COMMON_FLAG(int, compress_stack_depot, 0, + "Compress stack depot to save memory.") +COMMON_FLAG(bool, no_huge_pages_for_shadow, true, + "If true, the shadow is not allowed to use huge pages. ") +COMMON_FLAG(bool, strict_string_checks, false, + "If set check that string arguments are properly null-terminated") +COMMON_FLAG(bool, intercept_strstr, true, + "If set, uses custom wrappers for strstr and strcasestr functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strspn, true, + "If set, uses custom wrappers for strspn and strcspn function " + "to find more errors.") +COMMON_FLAG(bool, intercept_strtok, true, + "If set, uses a custom wrapper for the strtok function " + "to find more errors.") +COMMON_FLAG(bool, intercept_strpbrk, true, + "If set, uses custom wrappers for strpbrk function " + "to find more errors.") +COMMON_FLAG( + bool, intercept_strcmp, true, + "If set, uses custom wrappers for strcmp functions to find more errors.") +COMMON_FLAG(bool, intercept_strlen, true, + "If set, uses custom wrappers for strlen and strnlen functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strchr, true, + "If set, uses custom wrappers for strchr, strchrnul, and strrchr " + "functions to find more errors.") +COMMON_FLAG(bool, intercept_memcmp, true, + "If set, uses custom wrappers for memcmp function " + "to find more errors.") +COMMON_FLAG(bool, strict_memcmp, true, + "If true, assume that memcmp(p1, p2, n) always reads n bytes before " + "comparing p1 and p2.") +COMMON_FLAG(bool, intercept_memmem, true, + "If set, uses a wrapper for memmem() to find more errors.") +COMMON_FLAG(bool, intercept_intrin, true, + "If set, uses custom wrappers for memset/memcpy/memmove " + "intrinsics to find more errors.") +COMMON_FLAG(bool, intercept_stat, true, + "If set, uses custom wrappers for *stat functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_send, true, + "If set, uses custom wrappers for send* functions " + "to find more errors.") +COMMON_FLAG(bool, decorate_proc_maps, (bool)SANITIZER_ANDROID, + "If set, decorate sanitizer mappings in /proc/self/maps with " + "user-readable names") +COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool " + "found an error") +COMMON_FLAG( + bool, abort_on_error, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE, + "If set, the tool calls abort() instead of _exit() after printing the " + "error report.") +COMMON_FLAG(bool, suppress_equal_pcs, true, + "Deduplicate multiple reports for single source location in " + "halt_on_error=false mode (asan only).") +COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash " + "(asan only).") +COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.") +COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.") +COMMON_FLAG(bool, dump_instruction_bytes, false, + "If true, dump 16 bytes starting at the instruction that caused SEGV") +COMMON_FLAG(bool, dump_registers, true, + "If true, dump values of CPU registers when SEGV happens. Only " + "available on OS X for now.") +COMMON_FLAG(bool, detect_write_exec, false, + "If true, triggers warning when writable-executable pages requests " + "are being made") +COMMON_FLAG(bool, test_only_emulate_no_memorymap, false, + "TEST ONLY fail to read memory mappings to emulate sanitized " + "\"init\"") diff --git a/src/mrt/libsan/asan/sanitizer_libc.cpp b/src/mrt/libsan/asan/sanitizer_libc.cpp new file mode 100644 index 0000000000..904eaf5f3b --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_libc.cpp @@ -0,0 +1,374 @@ +#include "asan_internal_defs.h" +#include "asan_utils.h" +#include "sanitizer_libc.h" +#include "asan_interceptors.h" +#include "asan_mapping.h" +#include "asan_shadow_memory.h" + +using namespace __sanitizer; + +extern "C" { + +void* internal_malloc(uptr size) { + // This is only used during __asan_init + // we use mmap to provide a page before the ASAN_SHADOW_OFFSET + static uptr offset = ASAN_SHADOW_OFFSET - 4096; + static bool have_mmaped = false; + if (!have_mmaped) { + MmapFixed(offset, 4096, 0, "internal_malloc"); + } + if (offset + size >= ASAN_SHADOW_OFFSET) { + Printf("Insufficient space for internal_malloc. Die."); + Die(); + } + void* result = (void*)offset; + offset += size; + return result; +} + +void* internal_calloc(uptr num, uptr size) { + uptr n = num * size; + void* result = internal_malloc(n); + internal_memset(result, 0, n); + return result; +} + +void* internal_realloc(void* addr, uptr size) { + // Never call it while __asan_init + Die(); +} + +/** + * The following functions are part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * **/ + +s64 internal_atoll(const char *nptr) { + return internal_simple_strtoll(nptr, nullptr, 10); +} + +char* internal_itoa(int value, char* str, int base) { + return internal_lltoa(value, str, base); +} + +char* internal_lltoa(long long value, char* str, int base) { + CHECK_GT(base, 1); + int idx = 0; + if (base == 10 && value < 0) { + str[idx] = '-'; + ++idx; + value = -value; + } + else if (value < 0) { + value = -value; + } + long long factor = 1; + while (value / factor > 0) factor *= base; + bool valid = false; + while (factor > 0) { + factor /= base; + int tmp = value / factor; + if (tmp > 0 && tmp < 10) { + str[idx] = tmp + 48; + value -= tmp * factor; + valid = true; + } + else if (tmp >= 10 && tmp < base) { + str[idx] = tmp + 87; + value -= tmp * factor; + valid = true; + } + else if (tmp < base && valid) { + str[idx] = '0'; + } + else { + Die(); + } + ++idx; + } + str[idx] = 0; + return str; +} + +void *internal_memchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + for (uptr i = 0; i < n; ++i, ++t) + if (*t == c) + return reinterpret_cast(const_cast(t)); + return nullptr; +} + +void *internal_memrchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + void *res = nullptr; + for (uptr i = 0; i < n; ++i, ++t) { + if (*t == c) { + res = reinterpret_cast(const_cast(t)); + } + } + return res; +} + +int internal_memcmp(const void* s1, const void* s2, uptr n) { + const char *t1 = (const char *)s1; + const char *t2 = (const char *)s2; + for (uptr i = 0; i < n; ++i, ++t1, ++t2) { + if (*t1 != *t2) { + return *t1 < *t2 ? -1 : 1; + } + } + return 0; +} + +void *internal_memcpy(void *dest, const void *src, uptr n) { + char *d = (char*)dest; + const char *s = (const char *)src; + for (uptr i = 0; i < n; ++i) { + d[i] = s[i]; + } + return dest; +} + +void *internal_memmove(void *dest, const void *src, uptr n) { + char *d = (char*)dest; + const char *s = (const char *)src; + sptr i, signed_n = (sptr)n; + CHECK_GE(signed_n, 0); + if (d < s) { + for (i = 0; i < signed_n; ++i) { + d[i] = s[i]; + } + } else { + if (d > s && signed_n > 0) { + for (i = signed_n - 1; i >= 0; --i) { + d[i] = s[i]; + } + } + } + return dest; +} + +void *internal_memset(void* s, int c, uptr n) { + // Optimize for the most performance-critical case: + if ((reinterpret_cast(s) % 16) == 0 && (n % 16) == 0) { + u64 *p = reinterpret_cast(s); + u64 *e = p + n / 8; + u64 v = c; + v |= v << 8; + v |= v << 16; + v |= v << 32; + for (; p < e; p += 2) + p[0] = p[1] = v; + return s; + } + // The next line prevents Clang from making a call to memset() instead of the + // loop below. + // FIXME: building the runtime with -ffreestanding is a better idea. However + // there currently are linktime problems due to PR12396. + char volatile *t = (char*)s; + for (uptr i = 0; i < n; ++i, ++t) { + *t = c; + } + return s; +} + +uptr internal_strcspn(const char *s, const char *reject) { + uptr i; + for (i = 0; s[i]; i++) { + if (internal_strchr(reject, s[i])) { + return i; + } + } + return i; +} + +char* internal_strdup(const char *s) { + uptr len = internal_strlen(s); + char *s2 = (char*)REAL(malloc(len + 1)); + internal_memcpy(s2, s, len); + s2[len] = 0; + return s2; +} + +int internal_strcmp(const char *s1, const char *s2) { + while (true) { + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + } + return 0; +} + +int internal_strncmp(const char *s1, const char *s2, uptr n) { + for (uptr i = 0; i < n; i++) { + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + } + return 0; +} + +char* internal_strchr(const char *s, int c) { + while (true) { + if (*s == (char)c) + return const_cast(s); + if (*s == 0) + return nullptr; + s++; + } +} + +char *internal_strchrnul(const char *s, int c) { + char *res = internal_strchr(s, c); + if (!res) { + res = const_cast(s) + internal_strlen(s); + } + return res; +} + +char *internal_strrchr(const char *s, int c) { + const char *res = nullptr; + for (uptr i = 0; s[i]; i++) { + if (s[i] == c) { + res = s + i; + } + } + return const_cast(res); +} + +uptr internal_strlen(const char *s) { + uptr i = 0; + while (s[i] != '\0') i++; + return i; +} + +uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + const uptr dstlen = internal_strnlen(dst, maxlen); + if (dstlen == maxlen) return maxlen + srclen; + if (srclen < maxlen - dstlen) { + internal_memmove(dst + dstlen, src, srclen + 1); + } else { + internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); + dst[maxlen - 1] = '\0'; + } + return dstlen + srclen; +} + +char *internal_strncat(char *dst, const char *src, uptr n) { + uptr len = internal_strlen(dst); + uptr i; + for (i = 0; i < n && src[i]; i++) { + dst[len + i] = src[i]; + } + dst[len + i] = 0; + return dst; +} + +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + if (srclen < maxlen) { + internal_memmove(dst, src, srclen + 1); + } else if (maxlen != 0) { + internal_memmove(dst, src, maxlen - 1); + dst[maxlen - 1] = '\0'; + } + return srclen; +} + +char *internal_strncpy(char *dst, const char *src, uptr n) { + uptr i; + for (i = 0; i < n && src[i]; i++) + dst[i] = src[i]; + internal_memset(dst + i, '\0', n - i); + return dst; +} + +uptr internal_strnlen(const char *s, uptr maxlen) { + uptr i = 0; + while (i < maxlen && s[i] != '\0') i++; + return i; +} + +char *internal_strstr(const char *haystack, const char *needle) { + // This is O(N^2), NEVER use it in hot place!!!!! + uptr len1 = internal_strlen(haystack); + uptr len2 = internal_strlen(needle); + if (len1 < len2) return nullptr; + for (uptr pos = 0; pos <= len1 - len2; pos++) { + if (internal_memcmp(haystack + pos, needle, len2) == 0) + return const_cast(haystack) + pos; + } + return nullptr; +} + +s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { + CHECK_EQ(base, 10); + while (IsSpace(*nptr)) nptr++; + int sgn = 1; + u64 res = 0; + bool have_digits = false; + char *old_nptr = const_cast(nptr); + if (*nptr == '+') { + sgn = 1; + nptr++; + } else if (*nptr == '-') { + sgn = -1; + nptr++; + } + while (IsDigit(*nptr)) { + res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; + int digit = ((*nptr) - '0'); + res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; + have_digits = true; + nptr++; + } + if (endptr) { + *endptr = (have_digits) ? const_cast(nptr) : old_nptr; + } + if (sgn > 0) { + return (s64)(Min((u64)INT64_MAX, res)); + } else { + return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); + } +} + +uptr internal_wcslen(const wchar_t *s) { + uptr i = 0; + while (s[i]) i++; + return i; +} + +uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) { + uptr i = 0; + while (i < maxlen && s[i]) i++; + return i; +} + +bool mem_is_zero(const char *beg, uptr size) { + CHECK_LE(size, 1ULL << 40); // Sanity check. + const char *end = beg + size; + uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); + uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); + uptr all = 0; + // Prologue. + for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) + all |= *mem; + // Aligned loop. + for (; aligned_beg < aligned_end; aligned_beg++) + all |= *aligned_beg; + // Epilogue. + if ((char *)aligned_end >= beg) { + for (const char *mem = (char *)aligned_end; mem < end; mem++) { + all |= *mem; + } + } + return all == 0; +} + +} \ No newline at end of file diff --git a/src/mrt/libsan/asan/sanitizer_libc.h b/src/mrt/libsan/asan/sanitizer_libc.h new file mode 100644 index 0000000000..ffdffb520a --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_libc.h @@ -0,0 +1,46 @@ +#ifndef SANITIZER_LIBC_H +#define SANITIZER_LIBC_H + +#include "asan_internal_defs.h" +#include "wchar.h" + +namespace __sanitizer { + +extern "C" { + +INTERFACE_ATTRIBUTE void* internal_malloc(uptr size); +INTERFACE_ATTRIBUTE void* internal_calloc(uptr num, uptr size); +INTERFACE_ATTRIBUTE void* internal_realloc(void* addr, uptr size); +INTERFACE_ATTRIBUTE s64 internal_atoll(const char *nptr); +INTERFACE_ATTRIBUTE char* internal_itoa(int value, char* str, int base); +INTERFACE_ATTRIBUTE char* internal_lltoa(long long value, char* str, int base); +INTERFACE_ATTRIBUTE void *internal_memchr(const void *s, int c, uptr n); +INTERFACE_ATTRIBUTE void *internal_memrchr(const void *s, int c, uptr n); +INTERFACE_ATTRIBUTE int internal_memcmp(const void* s1, const void* s2, uptr n); +INTERFACE_ATTRIBUTE void *internal_memcpy(void *dest, const void *src, uptr n); +INTERFACE_ATTRIBUTE void *internal_memmove(void *dest, const void *src, uptr n); +INTERFACE_ATTRIBUTE void *internal_memset(void* s, int c, uptr n); +INTERFACE_ATTRIBUTE uptr internal_strcspn(const char *s, const char *reject); +INTERFACE_ATTRIBUTE char* internal_strdup(const char *s); +INTERFACE_ATTRIBUTE int internal_strcmp(const char *s1, const char *s2); +INTERFACE_ATTRIBUTE int internal_strncmp(const char *s1, const char *s2, uptr n); +INTERFACE_ATTRIBUTE char* internal_strchr(const char *s, int c); +INTERFACE_ATTRIBUTE char *internal_strchrnul(const char *s, int c); +INTERFACE_ATTRIBUTE char *internal_strrchr(const char *s, int c); +INTERFACE_ATTRIBUTE uptr internal_strlen(const char *s); +INTERFACE_ATTRIBUTE uptr internal_strlcat(char *dst, const char *src, uptr maxlen); +INTERFACE_ATTRIBUTE char *internal_strncat(char *dst, const char *src, uptr n); +INTERFACE_ATTRIBUTE uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); +INTERFACE_ATTRIBUTE char *internal_strncpy(char *dst, const char *src, uptr n); +INTERFACE_ATTRIBUTE uptr internal_strnlen(const char *s, uptr maxlen); +INTERFACE_ATTRIBUTE char *internal_strstr(const char *haystack, const char *needle); +INTERFACE_ATTRIBUTE s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base); +INTERFACE_ATTRIBUTE uptr internal_wcslen(const wchar_t *s); +INTERFACE_ATTRIBUTE uptr internal_wcsnlen(const wchar_t *s, uptr maxlen); +INTERFACE_ATTRIBUTE bool mem_is_zero(const char *beg, uptr size); + +} + +} // namespace __sanitizer + +#endif // SANITIZER_LIBC_H diff --git a/src/mrt/libsan/asan/sanitizer_linux_syscall.cpp b/src/mrt/libsan/asan/sanitizer_linux_syscall.cpp new file mode 100644 index 0000000000..b93468105a --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_linux_syscall.cpp @@ -0,0 +1,29 @@ +/* +This is a copy of LLVM-ASAN's internal syscall's implementation for aarch64 +I am not sure if I need to use it. +*/ +#include "asan_internal_defs.h" + +#include "sanitizer_linux_syscall.h" +// platform relative +#include "sanitizer_linux_syscall_NR_aarch64.h" + +namespace __sanitizer { + +uptr internal_openat(int dirfd, const char *pathname, int flags, int mode) { + return syscall(SYSCALL(openat), dirfd, pathname, flags, mode); +} + +uptr internal_ftruncate(int fd, OFF_T length) { + return syscall(SYSCALL(ftruncate), fd, length); +} + +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { + return syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, offset); +} + +uptr internal_unlink(const char* path) { + return syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); +} + +} // namespace __sanitizer \ No newline at end of file diff --git a/src/mrt/libsan/asan/sanitizer_linux_syscall.h b/src/mrt/libsan/asan/sanitizer_linux_syscall.h new file mode 100644 index 0000000000..50ac58a4a5 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_linux_syscall.h @@ -0,0 +1,21 @@ +#ifndef SANITIZER_LINUX_SYSCALL_H +#define SANITIZER_LINUX_SYSCALL_H +#include "fcntl.h" +#include "unistd.h" +#include "sys/syscall.h" +#include "sys/types.h" +#include "sys/signal.h" +#include "sys/mman.h" + +namespace __sanitizer +{ + +INTERFACE_ATTRIBUTE uptr internal_openat(int dirfd, const char *pathname, int flags, int mode); +INTERFACE_ATTRIBUTE uptr internal_ftruncate(int fd, OFF_T length); +INTERFACE_ATTRIBUTE uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset); +INTERFACE_ATTRIBUTE uptr internal_unlink(const char* path); + +} // namespace __sanitizer + + +#endif // SANITIZER_LINUX_SYSCALL_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/sanitizer_linux_syscall_NR_aarch64.h b/src/mrt/libsan/asan/sanitizer_linux_syscall_NR_aarch64.h new file mode 100644 index 0000000000..fb8fc52bd4 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_linux_syscall_NR_aarch64.h @@ -0,0 +1,5 @@ +#define SYSCALL(name) __NR_ ## name + +#define __NR_ftruncate 46 +#define __NR_openat 56 +#define __NR_mmap 222 diff --git a/src/mrt/libsan/asan/sanitizer_printf.cpp b/src/mrt/libsan/asan/sanitizer_printf.cpp new file mode 100644 index 0000000000..4c02a8d103 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_printf.cpp @@ -0,0 +1,211 @@ +#include "sanitizer_printf.h" +#include +#include "asan_interceptors.h" +#include +#include "common_flags.h" +#include "sanitizer_libc.h" +#include "asan_report.h" + +namespace __sanitizer +{ + +const int SAFE_PRINTF_BUFF_SIZE = 4096 * 4; + +bool ColorizeReports() { + const char *flag = common_flags()->color; + return internal_strcmp(flag, "always") == 0 || \ + internal_strcmp(flag, "auto") == 0; +} + +const char* PrintfDecorator::GetShadowByteStr(su_t v) { + #define COLOR_SD_SNPRINTF(color) \ + REAL(snprintf(shadow_byte_buff, 31, "%s%x%s", color(), v & 0x0ff, Default())); + switch (v) { + case kAsanHeapLeftRedzoneMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanHeapFreeMagic: + COLOR_SD_SNPRINTF(Magenta); break; + case kAsanStackLeftRedzoneMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanStackMidRedzoneMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanStackRightRedzoneMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanStackAfterReturnMagic: + COLOR_SD_SNPRINTF(Magenta); break; + case kAsanInitializationOrderMagic: + COLOR_SD_SNPRINTF(Cyan); break; + case kAsanUserPoisonedMemoryMagic: + COLOR_SD_SNPRINTF(Blue); break; + case kAsanContiguousContainerOOBMagic: + COLOR_SD_SNPRINTF(Blue); break; + case kAsanStackUseAfterScopeMagic: + COLOR_SD_SNPRINTF(Magenta); break; + case kAsanInternalHeapMagic: + COLOR_SD_SNPRINTF(Yellow); break; + case kAsanGlobalRedzoneMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanArrayCookieMagic: + COLOR_SD_SNPRINTF(Red); break; + case kAsanIntraObjectRedzone: + COLOR_SD_SNPRINTF(Yellow); break; + case kAsanAllocaLeftMagic: + COLOR_SD_SNPRINTF(Blue); break; + case kAsanAllocaRightMagic: + COLOR_SD_SNPRINTF(Blue); break; + default: + if (0 <= v && v <= 0x0f) { + REAL(snprintf(shadow_byte_buff, 31, "0%x", v & 0x0ff)); + } + else { + REAL(snprintf(shadow_byte_buff, 31, "%x", v & 0x0ff)); + } + break; + } + #undef COLOR_SD_SNPRINTF + return shadow_byte_buff; +} + +int safe_printf(const char* format, ...) { + va_list args; + va_start(args, format); + char * buff = (char*)REAL(malloc(SAFE_PRINTF_BUFF_SIZE + 1)); + int char_count_or_error = vsnprintf(buff, SAFE_PRINTF_BUFF_SIZE, format, args); + va_end(args); + + if (char_count_or_error < 0 || char_count_or_error > SAFE_PRINTF_BUFF_SIZE) { + REAL(free(buff)); + return char_count_or_error; + } + buff[SAFE_PRINTF_BUFF_SIZE] = '\0'; + write(2, buff, char_count_or_error); + REAL(free(buff)); + return char_count_or_error; +} + +void Printf(const char *format, ...) { + va_list args; + va_start(args, format); + // The following is the code of safe_printf + // Call safe_printf here result in errornous output + char * buff = (char*)REAL(malloc(SAFE_PRINTF_BUFF_SIZE + 1)); + int char_count_or_error = vsnprintf(buff, SAFE_PRINTF_BUFF_SIZE, format, args); + + if (char_count_or_error < 0 || char_count_or_error > SAFE_PRINTF_BUFF_SIZE) { + REAL(free(buff)); + va_end(args); + return; + } + buff[SAFE_PRINTF_BUFF_SIZE] = '\0'; + write(2, buff, char_count_or_error); + REAL(free(buff)); + va_end(args); +} + +void RawWrite(const char* msg) { + uptr read_len = internal_strnlen(msg, 4096); + write(2, msg, read_len); +} + +void CheckPrintfVars(const char* format, va_list args) { + // Go through char* pointers of the format string + static const char *kPrintfFormatsHelp = + "Supported Printf formats: \%([0-9]*)?(z|l|ll|L)?{d,u,x,X,e,E,g,G,a,A,f,F}; \%p; " + "\%[-]([0-9]*)?(\\.\\*)?s; \%c\nProvided format: "; + const char* cur = format; + char pre = 0; + + int result = 0; + for (; *cur; cur++) { + if (*cur != '%') { + continue; + } + cur++; + bool left_justified = *cur == '-'; + if (left_justified) + cur++; + bool have_width = (*cur >= '0' && *cur <= '9'); + bool pad_with_zero = (*cur == '0'); + int width = 0; + if (have_width) { + while (*cur >= '0' && *cur <= '9') { + width = width * 10 + *cur++ - '0'; + } + } + bool have_precision = (cur[0] == '.' && cur[1] == '*'); + int precision = -1; + if (have_precision) { + cur += 2; + precision = va_arg(args, int); + } + bool have_z = (*cur == 'z'); + cur += have_z; + bool have_l = (cur[0] == 'l' && cur[1] != 'l'); + cur += have_l; + bool have_L = (cur[0] == 'L'); + cur += have_L; + bool have_ll = (cur[0] == 'l' && cur[1] == 'l'); + cur += have_ll * 2; + // %Lf is %llf + if (have_L) have_ll = true; + const bool have_length = have_z || have_l || have_ll; + const bool have_flags = have_width || have_length; + // At the moment only %s supports precision and left-justification. + CHECK(!((precision >= 0 || left_justified) && *cur != 's')); + switch (*cur) { + case 'd': { + s64 dval = have_ll ? va_arg(args, s64) + : have_z ? va_arg(args, sptr) + : have_l ? va_arg(args, long) + : va_arg(args, int); + break; + } + case 'u': + case 'x': + case 'X': { + u64 uval = have_ll ? va_arg(args, u64) + : have_z ? va_arg(args, uptr) + : have_l ? va_arg(args, unsigned long) + : va_arg(args, unsigned); + bool uppercase = (*cur == 'X'); + break; + } + case 'e' || 'E' || 'g' || 'G' || 'a' || 'A' || 'f' || 'F': { + // It is said that C99 will auto upscale float to double + long double uval = have_ll ? va_arg(args, long double) + : have_l ? va_arg(args, double) + : va_arg(args, double); + break; + } + case 'p': { + // RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); + va_arg(args, uptr); + break; + } + case 's': { + // RAW_CHECK_VA(!have_length, kPrintfFormatsHelp, format); + // Only left-justified width is supported. + CHECK(!have_width || left_justified); + char* str = va_arg(args, char*); + CheckAndReport((void*)str, 1, false); + uptr tmp_read_len = REAL(strlen(str)); + CheckAndReport((void*)str, (tmp_read_len + 1), false); + break; + } + case 'c': { + va_arg(args, int); + break; + } + case '%' : { + // RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); + break; + } + default: { + // RAW_CHECK_VA(false, kPrintfFormatsHelp, format); + } + } + } +} + +} // namespace __sanitizer + diff --git a/src/mrt/libsan/asan/sanitizer_printf.h b/src/mrt/libsan/asan/sanitizer_printf.h new file mode 100644 index 0000000000..4fed50e643 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_printf.h @@ -0,0 +1,41 @@ +#ifndef SANITIZER_PRINTF_H +#define SANITIZER_PRINTF_H +#include "stdio.h" +#include "asan_internal_defs.h" +#include "common_flags.h" +#include "asan_internal.h" +#include + +#define Report Printf + +namespace __sanitizer { + +bool ColorizeReports(); + +class PrintfDecorator { + public: + PrintfDecorator() : ansi_(ColorizeReports()) {} + inline const char *Bold() const { return ansi_ ? "\033[1m" : ""; } + inline const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } + inline const char *Warning() const { return Red(); } + inline const char *Error() const { return Red(); } + inline const char *MemoryByte() const { return Magenta(); } + inline const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } + inline const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; } + inline const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; } + inline const char *Yellow() const { return ansi_ ? "\033[1m\033[33m" : ""; } + inline const char *Blue() const { return ansi_ ? "\033[1m\033[34m" : ""; } + inline const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; } + inline const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; } + inline const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; } + const char* GetShadowByteStr(su_t v); + private: + bool ansi_; + char shadow_byte_buff[32]; +}; + +void CheckPrintfVars(const char* format, va_list copy_args); + +} // namespace __sanitizer + +#endif // SANITIZER_PRINTF_H \ No newline at end of file diff --git a/src/mrt/libsan/asan/sanitizer_termination.cpp b/src/mrt/libsan/asan/sanitizer_termination.cpp new file mode 100644 index 0000000000..b482455f14 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_termination.cpp @@ -0,0 +1,68 @@ +#include "sanitizer_termination.h" +#include "stdlib.h" +#include "common_flags.h" +#include "string.h" +#include "asan_thread.h" +#include "asan_interceptors.h" +#include "asan_alloctor.h" + + +namespace __sanitizer{ + +static const int kMaxNumOfInternalDieCallbacks = 5; +static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; + +void Abort() { abort(); } + +bool AddDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == nullptr) { + InternalDieCallbacks[i] = callback; + return true; + } + } + return false; +} + +bool RemoveDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == callback) { + memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], + sizeof(InternalDieCallbacks[0]) * + (kMaxNumOfInternalDieCallbacks - i - 1)); + InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; + return true; + } + } + return false; +} + +void NORETURN Die() { + VReport(ASAN_LOG_DEBUG, "Dieing\n"); + // clear shadow and allocator + if (allocatorPtr != nullptr) { + allocatorPtr->OnDelete(); + REAL(free(allocatorPtr)); + } + // TODO: support user callback + for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { + if (InternalDieCallbacks[i]) + InternalDieCallbacks[i](); + } + if (common_flags()->abort_on_error) + Abort(); + exit(common_flags()->exitcode); +} + +void NORETURN CheckFailed(const char *file, int line, const char *cond, + u64 v1, u64 v2) { + u32 tid = GetCurrentTid(); + Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n", + SanitizerToolName, file, line, cond, (uptr)v1, + (uptr)v2, tid); + // TODO: wait other threads to exit with printed error + Die(); +} + +} // namespace __sanitizer + diff --git a/src/mrt/libsan/asan/sanitizer_termination.h b/src/mrt/libsan/asan/sanitizer_termination.h new file mode 100644 index 0000000000..bd05566148 --- /dev/null +++ b/src/mrt/libsan/asan/sanitizer_termination.h @@ -0,0 +1,18 @@ +#ifndef SANITIZER_TERMINATION_H +#define SANITIZER_TERMINATION_H + +#include "asan_internal_defs.h" + + +namespace __sanitizer{ + +typedef void (*DieCallbackType)(void); + +bool AddDieCallback(DieCallbackType callback); +bool RemoveDieCallback(DieCallbackType callback); +void NORETURN Die(); + +} // namespace __sanitizer + + +#endif // SANITIZER_TERMINATION_H \ No newline at end of file diff --git a/src/mrt/libsan/interception/interception.h b/src/mrt/libsan/interception/interception.h new file mode 100644 index 0000000000..d3546451da --- /dev/null +++ b/src/mrt/libsan/interception/interception.h @@ -0,0 +1,90 @@ +#ifndef INTERCEPTION_H +#define INTERCEPTION_H + +#include "asan_internal_defs.h" + +/** + * Note: the following macros are borrowed from LLVM + * In this way, we could improve the portability via changing the macro for + * different platforms. We currently merely support linux for aarch64 + * Also, the following macros contain declarition for interceptors, we + * reuse those macros as the interception mechanism is the same as that + * of LLVM ASAN (using dlsym) + * **/ + +#define SANITIZER_LINUX 1 + +// These typedefs should be used only in the interceptor definitions to replace +// the standard system types (e.g. SSIZE_T instead of ssize_t) +typedef __sanitizer::uptr SIZE_T; +typedef __sanitizer::sptr SSIZE_T; +typedef __sanitizer::sptr PTRDIFF_T; +typedef __sanitizer::s64 INTMAX_T; +typedef __sanitizer::u64 UINTMAX_T; +typedef __sanitizer::OFF_T OFF_T; +typedef __sanitizer::OFF64_T OFF64_T; + +# define WRAP(x) __interceptor_ ## x +# define WRAPPER_NAME(x) "__interceptor_" #x +# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) +# define DECLARE_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__) \ + __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); + + +# define PTR_TO_REAL(x) real_##x +# define REAL(x) __sanitizer::PTR_TO_REAL(x) +# define FUNC_TYPE(x) x##_type + +# define DECLARE_REAL(ret_type, func, ...) \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __sanitizer { \ + extern FUNC_TYPE(func) PTR_TO_REAL(func); \ + } +# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) + +# define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ + DECLARE_REAL(ret_type, func, __VA_ARGS__) \ + extern "C" ret_type WRAP(func)(__VA_ARGS__); +// Declare an interceptor and its wrapper defined in a different translation +// unit (ex. asm). +# define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type WRAP(func)(__VA_ARGS__); \ + extern "C" ret_type func(__VA_ARGS__); + + +// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR +// macros does its job. In exceptional cases you may need to call REAL(foo) +// without defining INTERCEPTOR(..., foo, ...). For example, if you override +// foo with an interceptor for other function. +# define DEFINE_REAL(ret_type, func, ...) \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __sanitizer { \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ + } + +#define INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__) \ + DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ + extern "C" \ + INTERCEPTOR_ATTRIBUTE \ + ret_type WRAP(func)(__VA_ARGS__) + +// We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now. +#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ + INTERCEPTOR(ret_type, func, __VA_ARGS__) + +#define INCLUDED_FROM_INTERCEPTION_LIB + +#if SANITIZER_LINUX +# include "interception_linux.h" +# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) +# define INTERCEPT_FUNCTION_WITH_ADDR(func, addr) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD_WITH_ADDR(func, addr) + +# define INTERCEPT_FUNCTION_VER(func, symver) \ + INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) +#endif + +#undef INCLUDED_FROM_INTERCEPTION_LIB + +#endif // INTERCEPTION_H diff --git a/src/mrt/libsan/interception/interception_linux.cpp b/src/mrt/libsan/interception/interception_linux.cpp new file mode 100644 index 0000000000..d97fd02c65 --- /dev/null +++ b/src/mrt/libsan/interception/interception_linux.cpp @@ -0,0 +1,38 @@ +#include "interception.h" + +#if SANITIZER_LINUX + +// for dlsym() and dlvsym() +#include + +namespace __sanitizer { + +static void *GetFuncAddr(const char *name, uptr wrapper_addr) { + void *addr = dlsym(RTLD_NEXT, name); + if (!addr) { + // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is + // later in the library search order than the DSO that we are trying to + // intercept, which means that we cannot intercept this function. We still + // want the address of the real definition, though, so look it up using + // RTLD_DEFAULT. + addr = dlsym(RTLD_DEFAULT, name); + + // In case `name' is not loaded, dlsym ends up finding the actual wrapper. + // We don't want to intercept the wrapper and have it point to itself. + if ((uptr)addr == wrapper_addr) + addr = nullptr; + } + return addr; +} + +bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, + uptr wrapper) { + void *addr = GetFuncAddr(name, wrapper); + *ptr_to_real = (uptr)addr; + __sync_synchronize(); + return addr && (func == wrapper); +} + +} // namespace __interception + +#endif // SANITIZER_LINUX diff --git a/src/mrt/libsan/interception/interception_linux.h b/src/mrt/libsan/interception/interception_linux.h new file mode 100644 index 0000000000..8546e51849 --- /dev/null +++ b/src/mrt/libsan/interception/interception_linux.h @@ -0,0 +1,35 @@ + +#if SANITIZER_LINUX + +#if !defined(INCLUDED_FROM_INTERCEPTION_LIB) +# error "interception_linux.h should be included from interception library only" +#endif + +#ifndef INTERCEPTION_LINUX_H +#define INTERCEPTION_LINUX_H + +namespace __sanitizer { +bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, + uptr wrapper); +// InterceptFunction for FREEBSD and NETBSD (with GLIBC support), see +// how to write the interfaces for other systems in LLVM +// bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, +// uptr func, uptr wrapper); +} // namespace __sanitizer + +#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ + ::__sanitizer::InterceptFunction( \ + #func, \ + (::__sanitizer::uptr *) & REAL(func), \ + (::__sanitizer::uptr) & (func), \ + (::__sanitizer::uptr) & WRAP(func)) + +#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD_WITH_ADDR(func, func_addr) \ + ::__sanitizer::InterceptFunction( \ + #func, \ + (::__sanitizer::uptr *) & REAL(func), \ + (::__sanitizer::uptr) (func_addr), \ + (::__sanitizer::uptr) & WRAP(func)) + +#endif // INTERCEPTION_LINUX_H +#endif // SANITIZER_LINUX -- Gitee From 55976406751b09122af5cfe64d2752ad00221cf0 Mon Sep 17 00:00:00 2001 From: WANG Date: Sun, 3 Sep 2023 14:35:06 +0000 Subject: [PATCH 2/3] add _asan_init before call main --- src/mapleall/maple_san/include/asan_module.h | 3 +- src/mapleall/maple_san/include/san_common.h | 2 + src/mapleall/maple_san/src/asan_module.cpp | 48 ++++++++++--------- src/mapleall/maple_san/src/asan_stackvar.cpp | 4 ++ src/mapleall/maple_san/src/san_common.cpp | 16 +++++++ .../maple_san/src/san_phase_manager.cpp | 4 +- 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/mapleall/maple_san/include/asan_module.h b/src/mapleall/maple_san/include/asan_module.h index 45bd73626d..c3102885fe 100644 --- a/src/mapleall/maple_san/include/asan_module.h +++ b/src/mapleall/maple_san/include/asan_module.h @@ -35,8 +35,7 @@ class ModuleAddressSanitizer { void InstrumentGlobalsWithMetadataArray(BlockNode *ctorToBeInserted, const std::vector ExtendedGlobals, std::vector MetadataInitializers); - BlockNode *CreateCtorAndInitFunctions(const std::string CtorName, const std::string InitName, - const MapleVector InitArgs); + BlockNode *CreateModuleCtor(); BlockNode *CreateModuleDtor(); diff --git a/src/mapleall/maple_san/include/san_common.h b/src/mapleall/maple_san/include/san_common.h index 425a8a0871..32b0edc3b6 100644 --- a/src/mapleall/maple_san/include/san_common.h +++ b/src/mapleall/maple_san/include/san_common.h @@ -111,8 +111,10 @@ size_t TypeSizeToSizeIndex(uint32_t TypeSize); std::vector GetGlobalVaribles(const MIRModule &mirModule); void appendToGlobalCtors(const MIRModule &mirModule, const MIRFunction *func); +void appendToGlobalCtors(const MIRModule &mirModule, StmtNode *stmt); void appendToGlobalDtors(const MIRModule &mirModule, const MIRFunction *func); +void appendToGlobalDtors(const MIRModule &mirModule, StmtNode *stmt); MIRFunction *getOrInsertFunction(MIRBuilder *mirBuilder, const char *name, MIRType *retType, std::vector argTypes); diff --git a/src/mapleall/maple_san/src/asan_module.cpp b/src/mapleall/maple_san/src/asan_module.cpp index 0e944d9c33..b3dab28f56 100644 --- a/src/mapleall/maple_san/src/asan_module.cpp +++ b/src/mapleall/maple_san/src/asan_module.cpp @@ -36,14 +36,20 @@ namespace maple { bool ModuleAddressSanitizer::instrumentModule() { initializeCallbacks(); MapleVector args(module->GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter()); - BlockNode *ctorToBeInserted = CreateCtorAndInitFunctions(kAsanModuleCtorName, kAsanInitName, args); - InstrumentGlobals(ctorToBeInserted); + MIRBuilder *mirBuilder = module->GetMIRBuilder(); + MIRFunction *initFunction = getOrInsertFunction(mirBuilder, kAsanInitName, + GlobalTables::GetTypeTable().GetVoid(), {}); + appendToGlobalCtors(*module, initFunction); - appendToGlobalCtors(*module, AsanCtorFunction); - if (AsanDtorFunction) { - appendToGlobalDtors(*module, AsanDtorFunction); - } + // BlockNode* ctorToBeInserted = CreateModuleCtor(); + // InstrumentGlobals(ctorToBeInserted); + // InstrumentGlobals(nullptr); + + // if (AsanDtorFunction) { + // appendToGlobalCtors(*module, AsanCtorFunction); + // appendToGlobalDtors(*module, AsanDtorFunction); + // } module->SetSomeSymbolNeedForDecl(false); return true; } @@ -79,7 +85,7 @@ namespace maple { GlobalTables::GetTypeTable().PushIntoFieldVector( fieldVector, "has_dynamic_init", *IntPtrTy); GlobalTables::GetTypeTable().PushIntoFieldVector( - fieldVector, "source_location", *IntPtrTy); + fieldVector, "windows_padding", *IntPtrTy); GlobalTables::GetTypeTable().PushIntoFieldVector( fieldVector, "odr_indicator", *IntPtrTy); // Create new type for global with redzones @@ -273,39 +279,35 @@ namespace maple { registerGlobal.emplace_back(constvalNode); CallNode *registerCallNode = module->GetMIRBuilder()->CreateStmtCall( AsanRegisterGlobals->GetPuidx(), registerGlobal); - ctorToBeInserted->InsertBefore(ctorToBeInserted->GetLast(), registerCallNode); - BlockNode *dtorTobeInserted = CreateModuleDtor(); + // ctorToBeInserted->InsertBefore(ctorToBeInserted->GetLast(), registerCallNode); + appendToGlobalCtors(*module, registerCallNode); + // BlockNode *dtorTobeInserted = CreateModuleDtor(); // We also need to unregister globals at the end, e.g., when a shared library // gets closed. CallNode *unRegisterCallNode = module->GetMIRBuilder()->CreateStmtCall( AsanUnregisterGlobals->GetPuidx(), registerGlobal); - dtorTobeInserted->InsertBefore(dtorTobeInserted->GetLast(), unRegisterCallNode); + // dtorTobeInserted->InsertBefore(dtorTobeInserted->GetLast(), unRegisterCallNode); + appendToGlobalDtors(*module, unRegisterCallNode); } - BlockNode *ModuleAddressSanitizer::CreateCtorAndInitFunctions( - const std::string CtorName, const std::string InitName, const MapleVector InitArgs) { + BlockNode *ModuleAddressSanitizer::CreateModuleCtor() { MIRBuilder *mirBuilder = module->GetMIRBuilder(); - ArgVector args(module->GetMPAllocator().Adapter()); - AsanCtorFunction = mirBuilder->CreateFunction(CtorName, *GlobalTables::GetTypeTable().GetVoid(), args); + // ArgVector args(module->GetMPAllocator().Adapter()); + AsanCtorFunction = mirBuilder->GetOrCreateFunction(kAsanModuleCtorName, + TyIdx(PTY_void)); module->AddFunction(AsanCtorFunction); AsanCtorFunction->SetAttr(FUNCATTR_local); BlockNode *asanCtorBlock = AsanCtorFunction->GetBody(); StmtNode *retNode = mirBuilder->CreateStmtReturn(nullptr); asanCtorBlock->AddStatement(retNode); - - MIRFunction *initFunction = getOrInsertFunction(mirBuilder, InitName.c_str(), - GlobalTables::GetTypeTable().GetVoid(), {}); - CallNode *callInitNode = mirBuilder->CreateStmtCall(initFunction->GetPuidx(), InitArgs); - - asanCtorBlock->InsertBefore(retNode, callInitNode); return asanCtorBlock; } BlockNode *ModuleAddressSanitizer::CreateModuleDtor() { MIRBuilder *mirBuilder = module->GetMIRBuilder(); - ArgVector args(module->GetMPAllocator().Adapter()); - AsanDtorFunction = mirBuilder->CreateFunction(kAsanModuleDtorName, - *GlobalTables::GetTypeTable().GetVoid(), args); + // ArgVector args(module->GetMPAllocator().Adapter()); + AsanDtorFunction = mirBuilder->GetOrCreateFunction(kAsanModuleDtorName, + TyIdx(PTY_void)); module->AddFunction(AsanDtorFunction); AsanDtorFunction->SetAttr(FUNCATTR_local); BlockNode *asanDtorBlock = AsanDtorFunction->GetBody(); diff --git a/src/mapleall/maple_san/src/asan_stackvar.cpp b/src/mapleall/maple_san/src/asan_stackvar.cpp index 87f4d884ec..18dec63ae7 100644 --- a/src/mapleall/maple_san/src/asan_stackvar.cpp +++ b/src/mapleall/maple_san/src/asan_stackvar.cpp @@ -462,6 +462,10 @@ void FunctionStackPoisoner::processStackVariable() { ASanStackVariableDescription desc = stackVariableDesc.at(i); if (desc.Symbol != nullptr) { MIRSymbol *localVar = desc.Symbol; + if (localVar->IsStatic() || localVar->IsPUStatic()) { + // skip them as I do not know how to assign its initial values + continue; + } BinaryNode *addExpr = mirBuilder->CreateExprBinary(OP_add, *IntptrTy, mirBuilder->CreateExprTypeCvt(OP_cvt, IntptrTy->GetPrimType(), PTY_u64, diff --git a/src/mapleall/maple_san/src/san_common.cpp b/src/mapleall/maple_san/src/san_common.cpp index 29e626e3da..c04e0d5d8a 100644 --- a/src/mapleall/maple_san/src/san_common.cpp +++ b/src/mapleall/maple_san/src/san_common.cpp @@ -21,6 +21,14 @@ void appendToGlobalCtors(const MIRModule &mirModule, const MIRFunction *func) { GlobalCtors->GetBody()->AddStatement(callNode); } + +void appendToGlobalCtors(const MIRModule &mirModule, StmtNode *stmt) { + MIRBuilder *mirBuilder = mirModule.GetMIRBuilder(); + MIRFunction *GlobalCtors = mirBuilder->GetOrCreateFunction("__cxx_global_var_init", TyIdx(PTY_void)); + GlobalCtors->GetBody()->AddStatement(stmt); +} + + void appendToGlobalDtors(const MIRModule &mirModule, const MIRFunction *func) { MIRBuilder *mirBuilder = mirModule.GetMIRBuilder(); MIRFunction *GlobalCtors = mirBuilder->GetOrCreateFunction("__cxx_global_var_fini", TyIdx(PTY_void)); @@ -29,6 +37,14 @@ void appendToGlobalDtors(const MIRModule &mirModule, const MIRFunction *func) { GlobalCtors->GetBody()->AddStatement(callNode); } + +void appendToGlobalDtors(const MIRModule &mirModule, StmtNode *stmt) { + MIRBuilder *mirBuilder = mirModule.GetMIRBuilder(); + MIRFunction *GlobalCtors = mirBuilder->GetOrCreateFunction("__cxx_global_var_fini", TyIdx(PTY_void)); + GlobalCtors->GetBody()->AddStatement(stmt); +} + + MIRFunction *getOrInsertFunction(MIRBuilder *mirBuilder, const char *name, MIRType *retType, std::vector argTypes) { GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(name); diff --git a/src/mapleall/maple_san/src/san_phase_manager.cpp b/src/mapleall/maple_san/src/san_phase_manager.cpp index d55f50bc8c..52aabf90be 100644 --- a/src/mapleall/maple_san/src/san_phase_manager.cpp +++ b/src/mapleall/maple_san/src/san_phase_manager.cpp @@ -39,8 +39,8 @@ bool MEModuleDoAsan::FuncLevelRun(MeFunction &meFunc, AnalysisDataManager &seria bool MEModuleDoAsan::PhaseRun(maple::MIRModule &m) { bool changed = false; // TODO: We have not instrumented global values - // TODO: ModuleAddressSanitizer AsanModule(m); - // TODO: AsanModule.instrumentModule(); + ModuleAddressSanitizer AsanModule(m); + AsanModule.instrumentModule(); auto &compFuncList = m.GetFunctionList(); auto admMempool = AllocateMemPoolInPhaseManager("ASAN phase manager's analysis data manager mempool"); auto *serialADM = GetManagerMemPool()->New(*(admMempool.get())); -- Gitee From 387c92233a84859bf62365950eff9d04e852c045 Mon Sep 17 00:00:00 2001 From: WANG Date: Sun, 3 Sep 2023 14:36:34 +0000 Subject: [PATCH 3/3] fix maple compile error --- src/mapleall/maple_be/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapleall/maple_be/CMakeLists.txt b/src/mapleall/maple_be/CMakeLists.txt index b245545381..492778a7ec 100755 --- a/src/mapleall/maple_be/CMakeLists.txt +++ b/src/mapleall/maple_be/CMakeLists.txt @@ -36,7 +36,7 @@ set(deps_maple if(ENABLE_MAPLE_SAN) list(APPEND deps_maple - maple_san) + libmplsan) endif(ENABLE_MAPLE_SAN) -- Gitee