Index: compiler-rt/lib/hwasan/hwasan.cc =================================================================== --- compiler-rt/lib/hwasan/hwasan.cc +++ compiler-rt/lib/hwasan/hwasan.cc @@ -363,6 +363,14 @@ TagMemoryAligned(p, sz, tag); } +static const u8 kFallbackTag = 0xBB; + +u8 __hwasan_generate_tag() { + HwasanThread *t = GetCurrentThread(); + if (!t) return kFallbackTag; + return t->GenerateRandomTag(); +} + #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE Index: compiler-rt/lib/hwasan/hwasan_interface_internal.h =================================================================== --- compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -86,6 +86,9 @@ SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_tag_memory(uptr p, u8 tag, uptr sz); +SANITIZER_INTERFACE_ATTRIBUTE +u8 __hwasan_generate_tag(); + // Returns the offset of the first tag mismatch or -1 if the whole range is // good. SANITIZER_INTERFACE_ATTRIBUTE Index: compiler-rt/test/hwasan/lit.cfg =================================================================== --- compiler-rt/test/hwasan/lit.cfg +++ compiler-rt/test/hwasan/lit.cfg @@ -9,7 +9,7 @@ config.test_source_root = os.path.dirname(__file__) # Setup default compiler flags used with -fsanitize=memory option. -clang_hwasan_cflags = ["-fsanitize=hwaddress", config.target_cflags] + config.debug_info_flags +clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls", config.target_cflags] + config.debug_info_flags clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags def build_invocation(compile_flags): Index: llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -91,6 +91,11 @@ cl::desc("instrument stack (allocas)"), cl::Hidden, cl::init(true)); +static cl::opt ClGenerateTagsWithCalls( + "hwasan-generate-tags-with-calls", + cl::desc("generate new tags with runtime library calls"), cl::Hidden, + cl::init(false)); + namespace { /// \brief An instrumentation pass implementing detection of addressability bugs @@ -121,6 +126,11 @@ bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag); bool instrumentStack(SmallVectorImpl &Allocas, SmallVectorImpl &RetVec); + Value *getNextTagWithCall(IRBuilder<> &IRB); + Value *getStackBaseTag(IRBuilder<> &IRB); + Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI, + unsigned AllocaNo); + Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); private: LLVMContext *C; @@ -135,6 +145,7 @@ Function *HwasanMemoryAccessCallbackSized[2]; Function *HwasanTagMemoryFunc; + Function *HwasanGenerateTagFunc; }; } // end anonymous namespace @@ -198,6 +209,8 @@ HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction( "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy)); + HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( + M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); } Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, @@ -373,18 +386,20 @@ return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))]; } -bool HWAddressSanitizer::instrumentStack( - SmallVectorImpl &Allocas, - SmallVectorImpl &RetVec) { - Function *F = Allocas[0]->getParent()->getParent(); - Module *M = F->getParent(); - Instruction *InsertPt = &*F->getEntryBlock().begin(); - IRBuilder<> IRB(InsertPt); +Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { + return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy); +} +Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { + if (ClGenerateTagsWithCalls) + return nullptr; // FIXME: use addressofreturnaddress (but implement it in aarch64 backend // first). - auto GetStackPointerFn = Intrinsic::getDeclaration(M, Intrinsic::frameaddress); - Value *StackPointer = IRB.CreateCall(GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())}); + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + auto GetStackPointerFn = + Intrinsic::getDeclaration(M, Intrinsic::frameaddress); + Value *StackPointer = IRB.CreateCall( + GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())}); // Extract some entropy from the stack pointer for the tags. // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ @@ -393,6 +408,31 @@ Value *StackTag = IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20), "hwasan.stack.base.tag"); + return StackTag; +} + +Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag, + AllocaInst *AI, unsigned AllocaNo) { + if (ClGenerateTagsWithCalls) + return getNextTagWithCall(IRB); + return IRB.CreateXor(StackTag, + ConstantInt::get(IntptrTy, RetagMask(AllocaNo))); +} + +Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) { + if (ClGenerateTagsWithCalls) + return getNextTagWithCall(IRB); + return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); +} + +bool HWAddressSanitizer::instrumentStack( + SmallVectorImpl &Allocas, + SmallVectorImpl &RetVec) { + Function *F = Allocas[0]->getParent()->getParent(); + Instruction *InsertPt = &*F->getEntryBlock().begin(); + IRBuilder<> IRB(InsertPt); + + Value *StackTag = getStackBaseTag(IRB); // Ideally, we want to calculate tagged stack base pointer, and rewrite all // alloca addresses using that. Unfortunately, offsets are not known yet @@ -404,17 +444,15 @@ IRB.SetInsertPoint(AI->getNextNode()); // Replace uses of the alloca with tagged address. + Value *Tag = getAllocaTag(IRB, StackTag, AI, N); + Value *AILong = IRB.CreatePointerCast(AI, IntptrTy); std::string Name = AI->hasName() ? AI->getName().str() : "alloca." + itostr(N); - Value *Tag = - IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, RetagMask(N))); - Value *AILong = IRB.CreatePointerCast(AI, IntptrTy); Value *Replacement = IRB.CreateIntToPtr( IRB.CreateOr(AILong, IRB.CreateShl(Tag, kPointerTagShift)), AI->getType(), Name + ".hwasan"); - for (auto UI = AI->use_begin(), UE = AI->use_end(); - UI != UE;) { + for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) { Use &U = *UI++; if (U.getUser() != AILong) U.set(Replacement); @@ -426,7 +464,7 @@ IRB.SetInsertPoint(RI); // Re-tag alloca memory with the special UAR tag. - Value *Tag = IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); + Value *Tag = getUARTag(IRB, StackTag); tagAlloca(IRB, AI, Tag); } } Index: llvm/test/Instrumentation/HWAddressSanitizer/alloca.ll =================================================================== --- llvm/test/Instrumentation/HWAddressSanitizer/alloca.ll +++ llvm/test/Instrumentation/HWAddressSanitizer/alloca.ll @@ -1,6 +1,7 @@ ; Test basic address sanitizer instrumentation. ; ; RUN: opt < %s -hwasan -S | FileCheck %s +; RUN: opt < %s -hwasan -hwasan-generate-tags-with-calls -S | FileCheck %s --check-prefix=WITH-CALLS target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64--linux-android" @@ -43,3 +44,9 @@ ret void } +; WITH-CALLS-LABEL: @test_alloca( +; WITH-CALLS: %[[T1:[^ ]*]] = call i8 @__hwasan_generate_tag() +; WITH-CALLS: %[[A:[^ ]*]] = zext i8 %[[T1]] to i64 +; WITH-CALLS: %[[B:[^ ]*]] = ptrtoint i32* %x to i64 +; WITH-CALLS: %[[C:[^ ]*]] = shl i64 %[[A]], 56 +; WITH-CALLS: or i64 %[[B]], %[[C]]