From 135715436aae7a7c688e649ddaa898ecefb08fe5 Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Tue, 14 May 2019 21:17:21 +0000 Subject: [PATCH] [NewPM] Port HWASan and Kernel HWASan Port hardware assisted address sanitizer to new PM following the same guidelines as msan and tsan. Changes: - Separate HWAddressSanitizer into a pass class and a sanitizer class. - Create new PM wrapper pass for the sanitizer class. - Use the getOrINsert pattern for some module level initialization declarations. - Also enable kernel-kwasan in new PM - Update llvm tests and add clang test. Differential Revision: https://reviews.llvm.org/D61709 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360707 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/InitializePasses.h | 2 +- include/llvm/Transforms/Instrumentation.h | 3 - .../Instrumentation/HWAddressSanitizer.h | 41 ++++++ lib/Passes/PassBuilder.cpp | 1 + lib/Passes/PassRegistry.def | 2 + .../Instrumentation/HWAddressSanitizer.cpp | 133 ++++++++++++------ .../Instrumentation/Instrumentation.cpp | 2 +- .../HWAddressSanitizer/basic.ll | 6 + 8 files changed, 139 insertions(+), 51 deletions(-) create mode 100644 include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index e0ea2082de5..f60a99c6205 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -163,7 +163,7 @@ void initializeGlobalSplitPass(PassRegistry&); void initializeGlobalsAAWrapperPassPass(PassRegistry&); void initializeGuardWideningLegacyPassPass(PassRegistry&); void initializeHotColdSplittingLegacyPassPass(PassRegistry&); -void initializeHWAddressSanitizerPass(PassRegistry&); +void initializeHWAddressSanitizerLegacyPassPass(PassRegistry &); void initializeIPCPPass(PassRegistry&); void initializeIPSCCPLegacyPassPass(PassRegistry&); void initializeIRCELegacyPassPass(PassRegistry&); diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index e747a744b74..8b70d2926ae 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -152,9 +152,6 @@ ModulePass *createInstrProfilingLegacyPass( ModulePass *createInstrOrderFilePass(); -FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false, - bool Recover = false); - // Insert DataFlowSanitizer (dynamic data flow analysis) instrumentation ModulePass *createDataFlowSanitizerPass( const std::vector &ABIListFiles = std::vector(), diff --git a/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h b/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h new file mode 100644 index 00000000000..e34cf6c50d1 --- /dev/null +++ b/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h @@ -0,0 +1,41 @@ +//===--------- Definition of the HWAddressSanitizer class -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Hardware AddressSanitizer class which is a port of the +// legacy HWAddressSanitizer pass to use the new PassManager infrastructure. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_HWADDRESSSANITIZERPASS_H +#define LLVM_TRANSFORMS_INSTRUMENTATION_HWADDRESSSANITIZERPASS_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// This is a public interface to the hardware address sanitizer pass for +/// instrumenting code to check for various memory errors at runtime, similar to +/// AddressSanitizer but based on partial hardware assistance. +class HWAddressSanitizerPass : public PassInfoMixin { +public: + explicit HWAddressSanitizerPass(bool CompileKernel = false, + bool Recover = false); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); + +private: + bool CompileKernel; + bool Recover; +}; + +FunctionPass *createHWAddressSanitizerLegacyPassPass(bool CompileKernel = false, + bool Recover = false); + +} // namespace llvm + +#endif diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 89b9c520af8..3fb963fddf3 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -94,6 +94,7 @@ #include "llvm/Transforms/Instrumentation/CGProfile.h" #include "llvm/Transforms/Instrumentation/ControlHeightReduction.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" +#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Instrumentation/InstrOrderFile.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index 68f7d45cc43..0d614d1d69b 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -237,6 +237,8 @@ FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass()) FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass()) FUNCTION_PASS("asan", AddressSanitizerPass(false, false, false)) FUNCTION_PASS("kasan", AddressSanitizerPass(true, false, false)) +FUNCTION_PASS("hwasan", HWAddressSanitizerPass(false, false)) +FUNCTION_PASS("khwasan", HWAddressSanitizerPass(true, true)) FUNCTION_PASS("msan", MemorySanitizerPass({})) FUNCTION_PASS("kmsan", MemorySanitizerPass({0, false, /*Kernel=*/true})) FUNCTION_PASS("tsan", ThreadSanitizerPass()) diff --git a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index 254e9ecd3ea..56db746565b 100644 --- a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -11,6 +11,7 @@ /// based on tagged addressing. //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -164,22 +165,19 @@ namespace { /// An instrumentation pass implementing detection of addressability bugs /// using tagged pointers. -class HWAddressSanitizer : public FunctionPass { +class HWAddressSanitizer { public: - // Pass identification, replacement for typeid. - static char ID; - - explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false) - : FunctionPass(ID) { + explicit HWAddressSanitizer(Module &M, bool CompileKernel = false, + bool Recover = false) { this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ? ClEnableKhwasan : CompileKernel; - } - StringRef getPassName() const override { return "HWAddressSanitizer"; } + initializeModule(M); + } - bool runOnFunction(Function &F) override; - bool doInitialization(Module &M) override; + bool sanitizeFunction(Function &F); + void initializeModule(Module &M); void initializeCallbacks(Module &M); @@ -279,29 +277,61 @@ private: GlobalValue *ThreadPtrGlobal = nullptr; }; +class HWAddressSanitizerLegacyPass : public FunctionPass { +public: + // Pass identification, replacement for typeid. + static char ID; + + explicit HWAddressSanitizerLegacyPass(bool CompileKernel = false, + bool Recover = false) + : FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover) {} + + StringRef getPassName() const override { return "HWAddressSanitizer"; } + + bool runOnFunction(Function &F) override { + HWAddressSanitizer HWASan(*F.getParent(), CompileKernel, Recover); + return HWASan.sanitizeFunction(F); + } + +private: + bool CompileKernel; + bool Recover; +}; + } // end anonymous namespace -char HWAddressSanitizer::ID = 0; +char HWAddressSanitizerLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( - HWAddressSanitizer, "hwasan", + HWAddressSanitizerLegacyPass, "hwasan", "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) INITIALIZE_PASS_END( - HWAddressSanitizer, "hwasan", + HWAddressSanitizerLegacyPass, "hwasan", "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) -FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel, - bool Recover) { +FunctionPass *llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel, + bool Recover) { assert(!CompileKernel || Recover); - return new HWAddressSanitizer(CompileKernel, Recover); + return new HWAddressSanitizerLegacyPass(CompileKernel, Recover); +} + +HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover) + : CompileKernel(CompileKernel), Recover(Recover) {} + +PreservedAnalyses HWAddressSanitizerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + HWAddressSanitizer HWASan(*F.getParent(), CompileKernel, Recover); + if (HWASan.sanitizeFunction(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); } /// Module-level initialization. /// /// inserts a call to __hwasan_init to the module's constructor list. -bool HWAddressSanitizer::doInitialization(Module &M) { +void HWAddressSanitizer::initializeModule(Module &M) { LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n"); auto &DL = M.getDataLayout(); @@ -320,13 +350,24 @@ bool HWAddressSanitizer::doInitialization(Module &M) { HwasanCtorFunction = nullptr; if (!CompileKernel) { std::tie(HwasanCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName, - kHwasanInitName, - /*InitArgTypes=*/{}, - /*InitArgs=*/{}); - Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); - HwasanCtorFunction->setComdat(CtorComdat); - appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction); + getOrCreateSanitizerCtorAndInitFunctions( + M, kHwasanModuleCtorName, kHwasanInitName, + /*InitArgTypes=*/{}, + /*InitArgs=*/{}, + // This callback is invoked when the functions are created the first + // time. Hook them into the global ctors list in that case: + [&](Function *Ctor, FunctionCallee) { + Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + Ctor->setComdat(CtorComdat); + appendToGlobalCtors(M, Ctor, 0, Ctor); + + IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); + IRBCtor.CreateCall( + declareSanitizerInitFunction(M, "__hwasan_init_frames", + {Int8PtrTy, Int8PtrTy}), + {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()), + createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())}); + }); // Create a zero-length global in __hwasan_frame so that the linker will // always create start and stop symbols. @@ -334,29 +375,29 @@ bool HWAddressSanitizer::doInitialization(Module &M) { // N.B. If we ever start creating associated metadata in this pass this // global will need to be associated with the ctor. Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); - auto GV = - new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true, - GlobalVariable::PrivateLinkage, - Constant::getNullValue(Int8Arr0Ty), "__hwasan"); - GV->setSection(getFrameSection()); - GV->setComdat(CtorComdat); - appendToCompilerUsed(M, GV); - - IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator()); - IRBCtor.CreateCall( - declareSanitizerInitFunction(M, "__hwasan_init_frames", - {Int8PtrTy, Int8PtrTy}), - {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()), - createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())}); + M.getOrInsertGlobal("__hwasan", Int8Arr0Ty, [&] { + auto *GV = new GlobalVariable( + M, Int8Arr0Ty, /*isConstantGlobal=*/true, GlobalValue::PrivateLinkage, + Constant::getNullValue(Int8Arr0Ty), "__hwasan"); + GV->setSection(getFrameSection()); + Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + GV->setComdat(CtorComdat); + appendToCompilerUsed(M, GV); + return GV; + }); } - if (!TargetTriple.isAndroid()) - appendToCompilerUsed( - M, ThreadPtrGlobal = new GlobalVariable( - M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr, - "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel)); - - return true; + if (!TargetTriple.isAndroid()) { + Constant *C = M.getOrInsertGlobal("__hwasan_tls", IntptrTy, [&] { + auto *GV = new GlobalVariable(M, IntptrTy, /*isConstantGlobal=*/false, + GlobalValue::ExternalLinkage, nullptr, + "__hwasan_tls", nullptr, + GlobalVariable::InitialExecTLSModel); + appendToCompilerUsed(M, GV); + return GV; + }); + ThreadPtrGlobal = cast(C); + } } void HWAddressSanitizer::initializeCallbacks(Module &M) { @@ -970,7 +1011,7 @@ bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) { !AI.isSwiftError()); } -bool HWAddressSanitizer::runOnFunction(Function &F) { +bool HWAddressSanitizer::sanitizeFunction(Function &F) { if (&F == HwasanCtorFunction) return false; diff --git a/lib/Transforms/Instrumentation/Instrumentation.cpp b/lib/Transforms/Instrumentation/Instrumentation.cpp index 22fa76a6c1f..f56a1bd91b8 100644 --- a/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -114,7 +114,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeInstrOrderFileLegacyPassPass(Registry); initializeInstrProfilingLegacyPassPass(Registry); initializeMemorySanitizerLegacyPassPass(Registry); - initializeHWAddressSanitizerPass(Registry); + initializeHWAddressSanitizerLegacyPassPass(Registry); initializeThreadSanitizerLegacyPassPass(Registry); initializeSanitizerCoverageModulePass(Registry); initializeDataFlowSanitizerPass(Registry); diff --git a/test/Instrumentation/HWAddressSanitizer/basic.ll b/test/Instrumentation/HWAddressSanitizer/basic.ll index ec50ea78839..9e7cd66f7db 100644 --- a/test/Instrumentation/HWAddressSanitizer/basic.ll +++ b/test/Instrumentation/HWAddressSanitizer/basic.ll @@ -5,6 +5,12 @@ ; RUN: opt < %s -hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ABORT-ZERO-BASED-SHADOW ; RUN: opt < %s -hwasan -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-ZERO-BASED-SHADOW +; Ensure than hwasan runs with the new PM pass +; RUN: opt < %s -passes='function(hwasan)' -hwasan-recover=0 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ABORT-DYNAMIC-SHADOW +; RUN: opt < %s -passes='function(hwasan)' -hwasan-recover=1 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-DYNAMIC-SHADOW +; RUN: opt < %s -passes='function(hwasan)' -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ABORT-ZERO-BASED-SHADOW +; RUN: opt < %s -passes='function(hwasan)' -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-ZERO-BASED-SHADOW + ; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @hwasan.module_ctor, i8* bitcast (void ()* @hwasan.module_ctor to i8*) }] ; CHECK: @__hwasan = private constant [0 x i8] zeroinitializer, section "__hwasan_frames", comdat($hwasan.module_ctor) -- 2.50.1