From 63af302b6c56408ff696f7827183be432c7366e8 Mon Sep 17 00:00:00 2001 From: Yuri Iozzelli Date: Fri, 27 Sep 2024 17:29:34 +0200 Subject: [PATCH] fix(asan): Poison memory between stack and globals This fixes compiler-rt/test/asan/TestCases/global-underflow.cpp , which would sometimes fail to detect the underfloa if the tested global was the very first one --- compiler-rt/lib/asan/asan_shadow_setup.cpp | 4 ++++ compiler-rt/lib/sanitizer_common/sanitizer_cheerpwasm.cpp | 1 + llvm/include/llvm/Cheerp/LinearMemoryHelper.h | 2 ++ llvm/lib/CheerpUtils/LinearMemoryHelper.cpp | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp index 8aed734c1692..9d8f4ab8e672 100644 --- a/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -22,6 +22,8 @@ # if SANITIZER_CHEERPWASM # include "asan_poisoning.h" extern char* volatile _stackTop; +extern char* volatile _stackBottom; +extern char* volatile _globalsStart; # endif namespace __asan { @@ -107,6 +109,8 @@ void InitializeShadowMemory() { // CHEERP: Poison everything from 0x0 up to stack top to detect null // derefences FastPoisonShadow(0, reinterpret_cast(_stackTop), 0xfe); + // CHEERP: Poison the space between the stack and the globals + PoisonShadow(reinterpret_cast(_stackBottom), reinterpret_cast(_globalsStart)-reinterpret_cast(_stackBottom), 0xfe); # endif CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); } else if (kMidMemBeg && diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_cheerpwasm.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_cheerpwasm.cpp index c85532c4aed5..18320d222cd5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_cheerpwasm.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_cheerpwasm.cpp @@ -19,6 +19,7 @@ __attribute__((cheerp_asmjs)) char *volatile _stackBottom = (char *)0xdeadbeef; __attribute__((cheerp_asmjs)) char *volatile _stackTop = (char *)0xdeadbeef; +__attribute__((cheerp_asmjs)) char *volatile _globalsStart = (char *)0xdeadbeef; static __asan::atomic_sint32_t _collect_traces; diff --git a/llvm/include/llvm/Cheerp/LinearMemoryHelper.h b/llvm/include/llvm/Cheerp/LinearMemoryHelper.h index 57109801eaad..49b7f2c15fa7 100644 --- a/llvm/include/llvm/Cheerp/LinearMemoryHelper.h +++ b/llvm/include/llvm/Cheerp/LinearMemoryHelper.h @@ -434,6 +434,8 @@ class LinearMemoryHelper uint32_t stackSize; // Stack start (it grows downwards) uint32_t stackStart; + // Globals start + uint32_t globalsStart; // Offset from 0x0 to the stack top. Primarily used with Asan to reserve // the lower addresses for null pointer checks uint32_t stackOffset; diff --git a/llvm/lib/CheerpUtils/LinearMemoryHelper.cpp b/llvm/lib/CheerpUtils/LinearMemoryHelper.cpp index 6a9fecec0b16..4c1080d8c740 100644 --- a/llvm/lib/CheerpUtils/LinearMemoryHelper.cpp +++ b/llvm/lib/CheerpUtils/LinearMemoryHelper.cpp @@ -426,6 +426,7 @@ void LinearMemoryHelper::addGlobals() // Also, for thread locals, calculate offsets to the image start, and the total size of the image. threadLocalImageSize = 0; threadLocalStart = 0; + globalsStart = 0; for (const auto G: asmjsGlobals) { //Globalized globals do not need an address if (globalizedGlobalsUsage.count(G)) @@ -437,6 +438,8 @@ void LinearMemoryHelper::addGlobals() uint32_t alignment = std::max(TypeSupport::getAlignmentAsmJS(targetData, ty), G->getAlignment()); // The following is correct if alignment is a power of 2 (which it should be) heapStart = (heapStart + alignment - 1) & ~(alignment - 1); + if (globalsStart == 0) + globalsStart = heapStart; globalAddresses.emplace(G, heapStart); inverseGlobalAddresses.emplace(heapStart, G); if (G->isThreadLocal()) @@ -688,6 +691,7 @@ void LinearMemoryHelper::addMemoryInfo() { setGlobalPtrIfPresent("_stackBottom", stackStart); setGlobalPtrIfPresent("_stackTop", stackStart + 8 - stackSize); + setGlobalPtrIfPresent("_globalsStart", globalsStart); //Align to 8 bytes heapStart = (heapStart + 7) & ~7;